diff --git a/docs/index.md b/docs/index.md new file mode 100644 index 000000000..11c6e4d30 --- /dev/null +++ b/docs/index.md @@ -0,0 +1,3 @@ +# Koku UI Documentation Index # + +Welcome to the Koku UI documentation! \ No newline at end of file diff --git a/locales/data.json b/locales/data.json index d6f7e0a86..28e272f8d 100644 --- a/locales/data.json +++ b/locales/data.json @@ -503,7 +503,7 @@ "value": [ { "type": 0, - "value": "Cost by accounts" + "value": "Cost breakdown by accounts" } ] }, @@ -511,7 +511,7 @@ "value": [ { "type": 0, - "value": "Cost by category" + "value": "Cost breakdown by category" } ] }, @@ -519,7 +519,7 @@ "value": [ { "type": 0, - "value": "Cost by clusters" + "value": "Cost breakdown by clusters" } ] }, @@ -527,7 +527,7 @@ "value": [ { "type": 0, - "value": "Cost by GCP projects" + "value": "Cost breakdown by GCP projects" } ] }, @@ -535,7 +535,7 @@ "value": [ { "type": 0, - "value": "Cost by Node" + "value": "Cost breakdown by Node" } ] }, @@ -543,7 +543,7 @@ "value": [ { "type": 0, - "value": "Cost by organizational units" + "value": "Cost breakdown by organizational units" } ] }, @@ -554,7 +554,7 @@ "value": [ { "type": 0, - "value": "Cost by accounts" + "value": "Cost breakdown by accounts" } ] }, @@ -562,7 +562,7 @@ "value": [ { "type": 0, - "value": "Cost by default projects" + "value": "Cost breakdown by default projects" } ] }, @@ -570,7 +570,7 @@ "value": [ { "type": 0, - "value": "Cost by services" + "value": "Cost breakdown by services" } ] }, @@ -578,7 +578,7 @@ "value": [ { "type": 0, - "value": "Cost by projects" + "value": "Cost breakdown by projects" } ] }, @@ -586,7 +586,7 @@ "value": [ { "type": 0, - "value": "Cost by regions" + "value": "Cost breakdown by regions" } ] }, @@ -594,7 +594,7 @@ "value": [ { "type": 0, - "value": "Cost by regions" + "value": "Cost breakdown by regions" } ] }, @@ -602,7 +602,7 @@ "value": [ { "type": 0, - "value": "Cost by services" + "value": "Cost breakdown by services" } ] }, @@ -610,7 +610,15 @@ "value": [ { "type": 0, - "value": "Cost by services" + "value": "Cost breakdown by services" + } + ] + }, + "storageclass": { + "value": [ + { + "type": 0, + "value": "Storage cost breakdown by type" } ] }, @@ -618,7 +626,7 @@ "value": [ { "type": 0, - "value": "Cost by accounts" + "value": "Cost breakdown by accounts" } ] }, @@ -626,7 +634,7 @@ "value": [ { "type": 0, - "value": "Cost by tags" + "value": "Cost breakdown by tags" } ] } @@ -671,7 +679,7 @@ "value": "Cancel" } ], - "chartCostForecastConeLegendLabel": [ + "chartCostForecastConeLabel": [ { "type": 0, "value": "Cost confidence (" @@ -685,13 +693,27 @@ "value": ")" } ], - "chartCostForecastConeLegendNoDataLabel": [ + "chartCostForecastConeLabelNoData": [ { "type": 0, "value": "Cost confidence (no data)" } ], - "chartCostForecastConeLegendTooltip": [ + "chartCostForecastConeRangeTooltip": [ + { + "type": 1, + "value": "value0" + }, + { + "type": 0, + "value": " - " + }, + { + "type": 1, + "value": "value1" + } + ], + "chartCostForecastConeTooltip": [ { "type": 0, "value": "Cost confidence (" @@ -705,24 +727,44 @@ "value": ")" } ], - "chartCostForecastConeTooltip": [ + "chartCostForecastLabel": [ + { + "type": 0, + "value": "Cost forecast (" + }, { "type": 1, - "value": "value0" + "value": "dateRange" }, { "type": 0, - "value": " - " + "value": ")" + } + ], + "chartCostForecastLabelNoData": [ + { + "type": 0, + "value": "Cost forecast (no data)" + } + ], + "chartCostForecastTooltip": [ + { + "type": 0, + "value": "Cost forecast (" }, { "type": 1, - "value": "value1" + "value": "month" + }, + { + "type": 0, + "value": ")" } ], - "chartCostForecastLegendLabel": [ + "chartCostLabel": [ { "type": 0, - "value": "Cost forecast (" + "value": "Cost (" }, { "type": 1, @@ -733,16 +775,16 @@ "value": ")" } ], - "chartCostForecastLegendNoDataLabel": [ + "chartCostLabelNoData": [ { "type": 0, - "value": "Cost forecast (no data)" + "value": "Cost (no data)" } ], - "chartCostForecastLegendTooltip": [ + "chartCostTooltip": [ { "type": 0, - "value": "Cost forecast (" + "value": "Cost (" }, { "type": 1, @@ -753,10 +795,10 @@ "value": ")" } ], - "chartCostLegendLabel": [ + "chartDataInLabel": [ { "type": 0, - "value": "Cost (" + "value": "Data in (" }, { "type": 1, @@ -767,16 +809,16 @@ "value": ")" } ], - "chartCostLegendNoDataLabel": [ + "chartDataInLabelNoData": [ { "type": 0, - "value": "Cost (no data)" + "value": "Data in (no data)" } ], - "chartCostLegendTooltip": [ + "chartDataInTooltip": [ { "type": 0, - "value": "Cost (" + "value": "Data in (" }, { "type": 1, @@ -787,10 +829,10 @@ "value": ")" } ], - "chartCostSupplementaryLegendLabel": [ + "chartDataOutLabel": [ { "type": 0, - "value": "Supplementary cost (" + "value": "Data out (" }, { "type": 1, @@ -801,16 +843,16 @@ "value": ")" } ], - "chartCostSupplementaryLegendNoDataLabel": [ + "chartDataOutLabelNoData": [ { "type": 0, - "value": "Supplementary cost (no data)" + "value": "Data out (no data)" } ], - "chartCostSupplementaryLegendTooltip": [ + "chartDataOutTooltip": [ { "type": 0, - "value": "Supplementary cost (" + "value": "Data out (" }, { "type": 1, @@ -831,7 +873,7 @@ "value": "day" } ], - "chartLimitLegendLabel": [ + "chartLimitLabel": [ { "type": 0, "value": "Limit (" @@ -845,13 +887,13 @@ "value": ")" } ], - "chartLimitLegendNoDataLabel": [ + "chartLimitLabelNoData": [ { "type": 0, "value": "Limit (no data)" } ], - "chartLimitLegendTooltip": [ + "chartLimitTooltip": [ { "type": 0, "value": "Limit (" @@ -905,7 +947,7 @@ "value": "count" } ], - "chartRequestsLegendLabel": [ + "chartRequestsLabel": [ { "type": 0, "value": "Requests (" @@ -919,13 +961,13 @@ "value": ")" } ], - "chartRequestsLegendNoDataLabel": [ + "chartRequestsLabelNoData": [ { "type": 0, "value": "Requests (no data)" } ], - "chartRequestsLegendTooltip": [ + "chartRequestsTooltip": [ { "type": 0, "value": "Requests (" @@ -939,7 +981,41 @@ "value": ")" } ], - "chartUsageLegendLabel": [ + "chartSupplementaryCostLabel": [ + { + "type": 0, + "value": "Supplementary cost (" + }, + { + "type": 1, + "value": "dateRange" + }, + { + "type": 0, + "value": ")" + } + ], + "chartSupplementaryCostLabelNoData": [ + { + "type": 0, + "value": "Supplementary cost (no data)" + } + ], + "chartSupplementaryCostTooltip": [ + { + "type": 0, + "value": "Supplementary cost (" + }, + { + "type": 1, + "value": "month" + }, + { + "type": 0, + "value": ")" + } + ], + "chartUsageLabel": [ { "type": 0, "value": "Usage (" @@ -953,13 +1029,13 @@ "value": ")" } ], - "chartUsageLegendNoDataLabel": [ + "chartUsageLabelNoData": [ { "type": 0, "value": "Usage (no data)" } ], - "chartUsageLegendTooltip": [ + "chartUsageTooltip": [ { "type": 0, "value": "Usage (" @@ -2856,6 +2932,30 @@ } ] }, + "instance": { + "value": [ + { + "type": 0, + "value": "Instance names" + } + ] + }, + "instance_type": { + "value": [ + { + "type": 0, + "value": "Instance type" + } + ] + }, + "memory": { + "value": [ + { + "type": 0, + "value": "Memory" + } + ] + }, "name": { "value": [ { @@ -2872,6 +2972,14 @@ } ] }, + "operating_system": { + "value": [ + { + "type": 0, + "value": "Operating system" + } + ] + }, "org_unit_id": { "value": [ { @@ -2880,6 +2988,14 @@ } ] }, + "os": { + "value": [ + { + "type": 0, + "value": "OS" + } + ] + }, "other": { "value": [] }, @@ -2978,6 +3094,22 @@ "value": "Tag keys" } ] + }, + "tags": { + "value": [ + { + "type": 0, + "value": "Tags" + } + ] + }, + "vcpu": { + "value": [ + { + "type": 0, + "value": "vCPU" + } + ] } }, "type": 5, @@ -3184,7 +3316,7 @@ "detailsUnusedRequestsLabel": [ { "type": 0, - "value": "Unrequested capacity" + "value": "Unused requests" } ], "detailsUnusedUnits": [ @@ -3387,6 +3519,14 @@ } ] }, + "storageclass": { + "value": [ + { + "type": 0, + "value": "View all storage types" + } + ] + }, "subscription_guid": { "value": [ { @@ -3439,6 +3579,91 @@ } ], "distributeCosts": [ + { + "options": { + "false": { + "value": [ + { + "type": 0, + "value": "Do not distribute " + }, + { + "options": { + "network": { + "value": [ + { + "type": 0, + "value": "network" + } + ] + }, + "other": { + "value": [] + }, + "storage": { + "value": [ + { + "type": 0, + "value": "storage" + } + ] + } + }, + "type": 5, + "value": "type" + }, + { + "type": 0, + "value": " costs" + } + ] + }, + "other": { + "value": [] + }, + "true": { + "value": [ + { + "type": 0, + "value": "Distribute " + }, + { + "options": { + "network": { + "value": [ + { + "type": 0, + "value": "network" + } + ] + }, + "other": { + "value": [] + }, + "storage": { + "value": [ + { + "type": 0, + "value": "storage" + } + ] + } + }, + "type": 5, + "value": "type" + }, + { + "type": 0, + "value": " costs" + } + ] + } + }, + "type": 5, + "value": "value" + } + ], + "distributeUnallocatedCapacity": [ { "options": { "false": { @@ -3526,7 +3751,7 @@ "distributionModelDesc": [ { "type": 0, - "value": "This choice is for users to direct how their raw costs are distributed either by CPU or Memory on the project level breakdowns." + "value": "Choose how your raw costs are distributed at the project level." } ], "distributionType": [ @@ -4248,6 +4473,67 @@ } ] }, + "instance": { + "value": [ + { + "options": { + "daily": { + "value": [ + { + "type": 1, + "value": "provider" + }, + { + "type": 0, + "value": "_instances_daily_" + }, + { + "type": 1, + "value": "startDate" + }, + { + "type": 0, + "value": "_" + }, + { + "type": 1, + "value": "endDate" + } + ] + }, + "monthly": { + "value": [ + { + "type": 1, + "value": "provider" + }, + { + "type": 0, + "value": "_instances_monthly_" + }, + { + "type": 1, + "value": "startDate" + }, + { + "type": 0, + "value": "_" + }, + { + "type": 1, + "value": "endDate" + } + ] + }, + "other": { + "value": [] + } + }, + "type": 5, + "value": "resolution" + } + ] + }, "node": { "value": [ { @@ -5001,6 +5287,14 @@ } ] }, + "instance": { + "value": [ + { + "type": 0, + "value": "Aggregates of the following instances will be exported to a .csv file." + } + ] + }, "node": { "value": [ { @@ -5504,6 +5798,107 @@ } ] }, + "instance": { + "value": [ + { + "options": { + "aws": { + "value": [ + { + "type": 0, + "value": "Amazon Web Services grouped by instance" + } + ] + }, + "aws_ocp": { + "value": [ + { + "type": 0, + "value": "Amazon Web Services filtered by OpenShift grouped by instance" + } + ] + }, + "azure": { + "value": [ + { + "type": 0, + "value": "Microsoft Azure grouped by instance" + } + ] + }, + "azure_ocp": { + "value": [ + { + "type": 0, + "value": "Microsoft Azure filtered by OpenShift grouped by instance" + } + ] + }, + "gcp": { + "value": [ + { + "type": 0, + "value": "Google Cloud Platform grouped by instance" + } + ] + }, + "gcp_ocp": { + "value": [ + { + "type": 0, + "value": "Google Cloud Platform filtered by OpenShift grouped by instance" + } + ] + }, + "ibm": { + "value": [ + { + "type": 0, + "value": "IBM Cloud grouped by instance" + } + ] + }, + "ibm_ocp": { + "value": [ + { + "type": 0, + "value": "IBM Cloud filtered by OpenShift grouped by instance" + } + ] + }, + "oci": { + "value": [ + { + "type": 0, + "value": "Oracle Cloud Infrastructure grouped by instance" + } + ] + }, + "ocp": { + "value": [ + { + "type": 0, + "value": "OpenShift grouped by instance" + } + ] + }, + "ocp_cloud": { + "value": [ + { + "type": 0, + "value": "All cloud filtered by OpenShift grouped by instance" + } + ] + }, + "other": { + "value": [] + } + }, + "type": 5, + "value": "provider" + } + ] + }, "node": { "value": [ { @@ -6569,6 +6964,22 @@ } ] }, + "instance": { + "value": [ + { + "type": 0, + "value": "Selected instances (" + }, + { + "type": 1, + "value": "count" + }, + { + "type": 0, + "value": ")" + } + ] + }, "node": { "value": [ { @@ -7532,6 +7943,14 @@ } ] }, + "instance": { + "value": [ + { + "type": 0, + "value": "Instance" + } + ] + }, "name": { "value": [ { @@ -7548,6 +7967,14 @@ } ] }, + "operating_system": { + "value": [ + { + "type": 0, + "value": "Operating system" + } + ] + }, "org_unit_id": { "value": [ { @@ -7714,6 +8141,18 @@ "value": "Values" } ], + "filteredBy": [ + { + "type": 0, + "value": "Filtered by" + } + ], + "filteredByWarning": [ + { + "type": 0, + "value": "This page shows filtered results. To undo filters, clear filters on the previous page." + } + ], "forDate": [ { "type": 1, @@ -9714,6 +10153,14 @@ } ] }, + "network": { + "value": [ + { + "type": 0, + "value": "Network usage comparison" + } + ] + }, "other": { "value": [] }, @@ -9851,6 +10298,12 @@ "value": "Infrastructure" } ], + "instances": [ + { + "type": 0, + "value": "Instances" + } + ], "lastProcessed": [ { "type": 0, @@ -10291,6 +10744,12 @@ "value": "Month over month change" } ], + "moreOptions": [ + { + "type": 0, + "value": "More options" + } + ], "names": [ { "offset": 0, @@ -10317,6 +10776,18 @@ "value": "count" } ], + "network": [ + { + "type": 0, + "value": "Network" + } + ], + "networkDesc": [ + { + "type": 0, + "value": "Distribute the cost of network traffic to projects based on distribution type." + } + ], "next": [ { "type": 0, @@ -10363,6 +10834,18 @@ "value": "There are no export files available" } ], + "noInstancesDesc": [ + { + "type": 0, + "value": "Add an Amazon EC2 instance to see a total cost breakdown of your spend by instances." + } + ], + "noInstancesTitle": [ + { + "type": 0, + "value": "No instances available" + } + ], "noMappedTags": [ { "type": 0, @@ -10393,18 +10876,6 @@ "value": "Tags must be enabled to be mapped." } ], - "noOptimizationsDesc": [ - { - "type": 0, - "value": "Resource Optimization is now available in preview for select customers. If your organization wants to participate, tell us through the Feedback button, which is purple and located on the right. Otherwise, there is not enough data available to generate an optimization." - } - ], - "noOptimizationsTitle": [ - { - "type": 0, - "value": "No optimizations available" - } - ], "noProvidersStateAwsDesc": [ { "type": 0, @@ -12102,12 +12573,24 @@ "value": "Status/Actions" } ], + "storage": [ + { + "type": 0, + "value": "Storage" + } + ], "storageClass": [ { "type": 0, "value": "StorageClass" } ], + "storageDesc": [ + { + "type": 0, + "value": "Distribute the cost of storage to projects based on distribution type." + } + ], "suggestions": [ { "type": 0, @@ -12909,6 +13392,12 @@ "value": "Various" } ], + "vcpuTitle": [ + { + "type": 0, + "value": "vCPU" + } + ], "volumeTitle": [ { "type": 0, diff --git a/locales/translations.json b/locales/translations.json index 37747ff4b..707544d7d 100644 --- a/locales/translations.json +++ b/locales/translations.json @@ -26,36 +26,42 @@ "breakdownBackToTitles": "{value, select, aws {Amazon Web Services} azure {Microsoft Azure} oci {Oracle Cloud Infrastructure} gcp {Google Cloud Platform} ibm {IBM Cloud - Top 5 Costliest} ocp {OpenShift} other {}}", "breakdownCostOverviewTitle": "Cost overview", "breakdownHistoricalDataTitle": "Historical data", - "breakdownSummaryTitle": "{value, select, account {Cost by accounts} aws_category {Cost by category} cluster {Cost by clusters} gcp_project {Cost by GCP projects} node {Cost by Node} org_unit_id {Cost by organizational units} payer_tenant_id {Cost by accounts} platform {Cost by default projects} product_service {Cost by services} project {Cost by projects} region {Cost by regions} resource_location {Cost by regions} service {Cost by services} service_name {Cost by services} subscription_guid {Cost by accounts} tag {Cost by tags} other {}}", + "breakdownSummaryTitle": "{value, select, account {Cost breakdown by accounts} aws_category {Cost breakdown by category} cluster {Cost breakdown by clusters} gcp_project {Cost breakdown by GCP projects} node {Cost breakdown by Node} org_unit_id {Cost breakdown by organizational units} payer_tenant_id {Cost breakdown by accounts} platform {Cost breakdown by default projects} product_service {Cost breakdown by services} project {Cost breakdown by projects} region {Cost breakdown by regions} resource_location {Cost breakdown by regions} service {Cost breakdown by services} service_name {Cost breakdown by services} storageclass {Storage cost breakdown by type} subscription_guid {Cost breakdown by accounts} tag {Cost breakdown by tags} other {}}", "breakdownTitle": "{value}", "breakdownTotalCostDate": "{value} total cost ({dateRange})", "calculationType": "Calculation type", "cancel": "Cancel", - "chartCostForecastConeLegendLabel": "Cost confidence ({dateRange})", - "chartCostForecastConeLegendNoDataLabel": "Cost confidence (no data)", - "chartCostForecastConeLegendTooltip": "Cost confidence ({month})", - "chartCostForecastConeTooltip": "{value0} - {value1}", - "chartCostForecastLegendLabel": "Cost forecast ({dateRange})", - "chartCostForecastLegendNoDataLabel": "Cost forecast (no data)", - "chartCostForecastLegendTooltip": "Cost forecast ({month})", - "chartCostLegendLabel": "Cost ({dateRange})", - "chartCostLegendNoDataLabel": "Cost (no data)", - "chartCostLegendTooltip": "Cost ({month})", - "chartCostSupplementaryLegendLabel": "Supplementary cost ({dateRange})", - "chartCostSupplementaryLegendNoDataLabel": "Supplementary cost (no data)", - "chartCostSupplementaryLegendTooltip": "Supplementary cost ({month})", + "chartCostForecastConeLabel": "Cost confidence ({dateRange})", + "chartCostForecastConeLabelNoData": "Cost confidence (no data)", + "chartCostForecastConeRangeTooltip": "{value0} - {value1}", + "chartCostForecastConeTooltip": "Cost confidence ({month})", + "chartCostForecastLabel": "Cost forecast ({dateRange})", + "chartCostForecastLabelNoData": "Cost forecast (no data)", + "chartCostForecastTooltip": "Cost forecast ({month})", + "chartCostLabel": "Cost ({dateRange})", + "chartCostLabelNoData": "Cost (no data)", + "chartCostTooltip": "Cost ({month})", + "chartDataInLabel": "Data in ({dateRange})", + "chartDataInLabelNoData": "Data in (no data)", + "chartDataInTooltip": "Data in ({month})", + "chartDataOutLabel": "Data out ({dateRange})", + "chartDataOutLabelNoData": "Data out (no data)", + "chartDataOutTooltip": "Data out ({month})", "chartDayOfTheMonth": "Day {day}", - "chartLimitLegendLabel": "Limit ({dateRange})", - "chartLimitLegendNoDataLabel": "Limit (no data)", - "chartLimitLegendTooltip": "Limit ({month})", + "chartLimitLabel": "Limit ({dateRange})", + "chartLimitLabelNoData": "Limit (no data)", + "chartLimitTooltip": "Limit ({month})", "chartNoData": "no data", "chartOthers": "{count, plural, one {{count} Other} other {{count} Others}}", - "chartRequestsLegendLabel": "Requests ({dateRange})", - "chartRequestsLegendNoDataLabel": "Requests (no data)", - "chartRequestsLegendTooltip": "Requests ({month})", - "chartUsageLegendLabel": "Usage ({dateRange})", - "chartUsageLegendNoDataLabel": "Usage (no data)", - "chartUsageLegendTooltip": "Usage ({month})", + "chartRequestsLabel": "Requests ({dateRange})", + "chartRequestsLabelNoData": "Requests (no data)", + "chartRequestsTooltip": "Requests ({month})", + "chartSupplementaryCostLabel": "Supplementary cost ({dateRange})", + "chartSupplementaryCostLabelNoData": "Supplementary cost (no data)", + "chartSupplementaryCostTooltip": "Supplementary cost ({month})", + "chartUsageLabel": "Usage ({dateRange})", + "chartUsageLabelNoData": "Usage (no data)", + "chartUsageTooltip": "Usage ({month})", "chooseKeyPlaceholder": "Choose key", "chooseValuePlaceholder": "Choose value", "close": "Close", @@ -225,23 +231,24 @@ "detailsEmptyState": "Processing data to generate a list of all services that sums to a total cost...", "detailsMore": "{value} more...", "detailsMoreClusters": ", {value} more...", - "detailsResourceNames": "{value, select, account {Account names} aws_category {Cost category names} cluster {Cluster names} gcp_project {GCP project names} group {Group} name {Name} node {Node names} org_unit_id {Organizational unit names} payer_tenant_id {Account names} product_service {Service names} project {Project names} region {Region names} resource_location {Region names} service {Service names} service_name {Service names} status {Status} subscription_guid {Account names} source_type {Integration} tag {Tag names} tag_key {Tag keys} other {}}", + "detailsResourceNames": "{value, select, account {Account names} aws_category {Cost category names} cluster {Cluster names} gcp_project {GCP project names} group {Group} instance {Instance names} instance_type {Instance type} memory {Memory} name {Name} node {Node names} org_unit_id {Organizational unit names} os {OS} operating_system {Operating system} payer_tenant_id {Account names} product_service {Service names} project {Project names} region {Region names} resource_location {Region names} service {Service names} service_name {Service names} status {Status} subscription_guid {Account names} source_type {Integration} tag {Tag names} tags {Tags} tag_key {Tag keys} vcpu {vCPU} other {}}", "detailsSummaryModalTitle": "{groupBy, select, account {{name} accounts} aws_category {{name} cost categories} cluster {{name} clusters} gcp_project {{name} GCP projects} node {{name} nodes} org_unit_id {{name} organizational units} payer_tenant_id {{name} accounts} product_service {{name} services} project {{name} projects} region {{name} regions} resource_location {{name} regions} service {{name} services} service_name {{name} services} subscription_guid {{name} accounts} tag {{name} tags} other {}}", "detailsUnusedCapacityLabel": "Unused capacity", - "detailsUnusedRequestsLabel": "Unrequested capacity", + "detailsUnusedRequestsLabel": "Unused requests", "detailsUnusedUnits": "{units} ({percentage}% of capacity)", "detailsUsageCapacity": "Capacity - {value} {units}", "detailsUsageLimit": "Limit - {value} {units}", "detailsUsageRequests": "Requests - {value} {units}", "detailsUsageUsage": "Usage - {value} {units}", - "detailsViewAll": "{value, select, account {View all accounts} aws_category {View all cost categories} cluster {View all clusters} gcp_project {View all GCP projects} node {View all nodes} org_unit_id {View all organizational units} payer_tenant_id {View all accounts} product_service {View all services} project {View all projects} region {View all regions} resource_location {View all regions} service {View all Services} service_name {View all services} subscription_guid {View all accounts} tag {View all tags} other {}}", + "detailsViewAll": "{value, select, account {View all accounts} aws_category {View all cost categories} cluster {View all clusters} gcp_project {View all GCP projects} node {View all nodes} org_unit_id {View all organizational units} payer_tenant_id {View all accounts} product_service {View all services} project {View all projects} region {View all regions} resource_location {View all regions} service {View all Services} service_name {View all services} storageclass {View all storage types} subscription_guid {View all accounts} tag {View all tags} other {}}", "disableCategories": "Disable categories", "disableTags": "Disable tags", "disabled": "Disabled", "discountMinus": "Discount (-)", "distribute": "Distribute", - "distributeCosts": "{value, select, true {Distribute {type, select, platform {platform} worker {worker} other {}} unallocated capacity}false {Do not distribute {type, select, platform {platform} worker {worker} other {}} unallocated capacity}other {}}", - "distributionModelDesc": "This choice is for users to direct how their raw costs are distributed either by CPU or Memory on the project level breakdowns.", + "distributeCosts": "{value, select, true {Distribute {type, select, network {network} storage {storage} other {}} costs}false {Do not distribute {type, select, network {network} storage {storage} other {}} costs}other {}}", + "distributeUnallocatedCapacity": "{value, select, true {Distribute {type, select, platform {platform} worker {worker} other {}} unallocated capacity}false {Do not distribute {type, select, platform {platform} worker {worker} other {}} unallocated capacity}other {}}", + "distributionModelDesc": "Choose how your raw costs are distributed at the project level.", "distributionType": "Distribution type", "distributionTypeDesc": "{type, select, cpu {Distribute costs based on CPU usage}memory {Distribute costs based on memory usage}other {}}", "doNotDistribute": "Do not distribute", @@ -286,16 +293,16 @@ "exportAll": "Export all", "exportDesc": "The active selections from the table plus the values here will be used to generate an export file. When the file is available, download it from the {value} view.", "exportError": "Something went wrong, please try fewer selections", - "exportFileName": "{groupBy, select, account {{resolution, select, daily {{provider}_accounts_daily_{startDate}_{endDate}} monthly {{provider}_accounts_monthly_{startDate}_{endDate}} other {}}} aws_category {{resolution, select, daily {{provider}_cost_category_daily_{startDate}_{endDate}} monthly {{provider}_cost_category_monthly_{startDate}_{endDate}} other {}}} cluster {{resolution, select, daily {{provider}_clusters_daily_{startDate}_{endDate}} monthly {{provider}_clusters_monthly_{startDate}_{endDate}} other {}}} gcp_project {{resolution, select, daily {{provider}_gcp-projects_daily_{startDate}_{endDate}} monthly {{provider}_gcp-projects_monthly_{startDate}_{endDate}} other {}}} node {{resolution, select, daily {{provider}_node_daily_{startDate}_{endDate}} monthly {{provider}_node_monthly_{startDate}_{endDate}} other {}}} org_unit_id {{resolution, select, daily {{provider}_orgs_daily_{startDate}_{endDate}} monthly {{provider}_orgs_monthly_{startDate}_{endDate}} other {}}} payer_tenant_id {{resolution, select, daily {{provider}_accounts_daily_{startDate}_{endDate}} monthly {{provider}_accounts_monthly_{startDate}_{endDate}} other {}}} product_service {{resolution, select, daily {{provider}_services_daily_{startDate}_{endDate}} monthly {{provider}_services_monthly_{startDate}_{endDate}} other {}}} project {{resolution, select, daily {{provider}_projects_daily_{startDate}_{endDate}} monthly {{provider}_projects_monthly_{startDate}_{endDate}} other {}}} region {{resolution, select, daily {{provider}_regions_daily_{startDate}_{endDate}} monthly {{provider}_regions_monthly_{startDate}_{endDate}} other {}}} resource_location {{resolution, select, daily {{provider}_regions_daily_{startDate}_{endDate}} monthly {{provider}_regions_monthly_{startDate}_{endDate}} other {}}} service {{resolution, select, daily {{provider}_services_daily_{startDate}_{endDate}} monthly {{provider}_services_monthly_{startDate}_{endDate}} other {}}} service_name {{resolution, select, daily {{provider}_services_daily_{startDate}_{endDate}} monthly {{provider}_services_monthly_{startDate}_{endDate}} other {}}} subscription_guid {{resolution, select, daily {{provider}_accounts_daily_{startDate}_{endDate}} monthly {{provider}_accounts_monthly_{startDate}_{endDate}} other {}}} tag {{resolution, select, daily {{provider}_tags_daily_{startDate}_{endDate}} monthly {{provider}_tags_monthly_{startDate}_{endDate}} other {}}} other {}}", + "exportFileName": "{groupBy, select, account {{resolution, select, daily {{provider}_accounts_daily_{startDate}_{endDate}} monthly {{provider}_accounts_monthly_{startDate}_{endDate}} other {}}} aws_category {{resolution, select, daily {{provider}_cost_category_daily_{startDate}_{endDate}} monthly {{provider}_cost_category_monthly_{startDate}_{endDate}} other {}}} cluster {{resolution, select, daily {{provider}_clusters_daily_{startDate}_{endDate}} monthly {{provider}_clusters_monthly_{startDate}_{endDate}} other {}}} gcp_project {{resolution, select, daily {{provider}_gcp-projects_daily_{startDate}_{endDate}} monthly {{provider}_gcp-projects_monthly_{startDate}_{endDate}} other {}}} instance {{resolution, select, daily {{provider}_instances_daily_{startDate}_{endDate}} monthly {{provider}_instances_monthly_{startDate}_{endDate}} other {}}} node {{resolution, select, daily {{provider}_node_daily_{startDate}_{endDate}} monthly {{provider}_node_monthly_{startDate}_{endDate}} other {}}} org_unit_id {{resolution, select, daily {{provider}_orgs_daily_{startDate}_{endDate}} monthly {{provider}_orgs_monthly_{startDate}_{endDate}} other {}}} payer_tenant_id {{resolution, select, daily {{provider}_accounts_daily_{startDate}_{endDate}} monthly {{provider}_accounts_monthly_{startDate}_{endDate}} other {}}} product_service {{resolution, select, daily {{provider}_services_daily_{startDate}_{endDate}} monthly {{provider}_services_monthly_{startDate}_{endDate}} other {}}} project {{resolution, select, daily {{provider}_projects_daily_{startDate}_{endDate}} monthly {{provider}_projects_monthly_{startDate}_{endDate}} other {}}} region {{resolution, select, daily {{provider}_regions_daily_{startDate}_{endDate}} monthly {{provider}_regions_monthly_{startDate}_{endDate}} other {}}} resource_location {{resolution, select, daily {{provider}_regions_daily_{startDate}_{endDate}} monthly {{provider}_regions_monthly_{startDate}_{endDate}} other {}}} service {{resolution, select, daily {{provider}_services_daily_{startDate}_{endDate}} monthly {{provider}_services_monthly_{startDate}_{endDate}} other {}}} service_name {{resolution, select, daily {{provider}_services_daily_{startDate}_{endDate}} monthly {{provider}_services_monthly_{startDate}_{endDate}} other {}}} subscription_guid {{resolution, select, daily {{provider}_accounts_daily_{startDate}_{endDate}} monthly {{provider}_accounts_monthly_{startDate}_{endDate}} other {}}} tag {{resolution, select, daily {{provider}_tags_daily_{startDate}_{endDate}} monthly {{provider}_tags_monthly_{startDate}_{endDate}} other {}}} other {}}", "exportFormatType": "{value, select, csv {CSV} json {JSON} other {}}", "exportFormatTypeTitle": "Format type", "exportGenerate": "Generate export", - "exportHeading": "{groupBy, select, account {Aggregates of the following accounts will be exported to a .csv file.} aws_category {Aggregates of the following cost categories will be exported to a .csv file.} cluster {Aggregates of the following clusters will be exported to a .csv file.} gcp_project {Aggregates of the following GCP projects will be exported to a .csv file.} node {Aggregates of the following nodes will be exported to a .csv file.} org_unit_id {Aggregates of the following organizational units will be exported to a .csv file.} payer_tenant_id {Aggregates of the following accounts will be exported to a .csv file.} product_service {Aggregates of the following services will be exported to a .csv file.} project {Aggregates of the following projects will be exported to a .csv file.} region {Aggregates of the following regions will be exported to a .csv file.} resource_location {Aggregates of the regions will be exported to a .csv file.} service {Aggregates of the following services will be exported to a .csv file.} service_name {Aggregates of the following services will be exported to a .csv file.} subscription_guid {Aggregates of the following accounts will be exported to a .csv file.} tag {Aggregates of the following tags will be exported to a .csv file.} other {}}", - "exportName": "{groupBy, select, account {{provider, select, aws {Amazon Web Services grouped by Account} aws_ocp {Amazon Web Services filtered by OpenShift grouped by Account} azure {Microsoft Azure grouped by Account} oci {Oracle Cloud Infrastructure grouped by Account} azure_ocp {Microsoft Azure filtered by OpenShift grouped by Account} gcp {Google Cloud Platform grouped by Account} gcp_ocp {Google Cloud Platform filtered by OpenShift grouped by Account} ibm {IBM Cloud grouped by Account} ibm_ocp {IBM Cloud filtered by OpenShift grouped by Account} ocp {OpenShift grouped by Account} ocp_cloud {All cloud filtered by OpenShift grouped by Account} other {}}} aws_category {{provider, select, aws {Amazon Web Services grouped by Cost category} aws_ocp {Amazon Web Services filtered by OpenShift grouped by Cost category} azure {Microsoft Azure grouped by Cost category} oci {Oracle Cloud Infrastructure grouped by Cost category} azure_ocp {Microsoft Azure filtered by OpenShift grouped by Cost category} gcp {Google Cloud Platform grouped by Cost category} gcp_ocp {Google Cloud Platform filtered by OpenShift grouped by Cost category} ibm {IBM Cloud grouped by Cost category} ibm_ocp {IBM Cloud filtered by OpenShift grouped by Cost category} ocp {OpenShift grouped by Cost category} ocp_cloud {All cloud filtered by OpenShift grouped by Cost category} other {}}} cluster {{provider, select, aws {Amazon Web Services grouped by Cluster} aws_ocp {Amazon Web Services filtered by OpenShift grouped by Cluster} azure {Microsoft Azure grouped by Cluster} oci {Oracle Cloud Infrastructure grouped by Cluster} azure_ocp {Microsoft Azure filtered by OpenShift grouped by Cluster} gcp {Google Cloud Platform grouped by Cluster} gcp_ocp {Google Cloud Platform filtered by OpenShift grouped by Cluster} ibm {IBM Cloud grouped by Cluster} ibm_ocp {IBM Cloud filtered by OpenShift grouped by Cluster} ocp {OpenShift grouped by Cluster} ocp_cloud {All cloud filtered by OpenShift grouped by Cluster} other {}}} gcp_project {{provider, select, aws {Amazon Web Services grouped by GCP Project} aws_ocp {Amazon Web Services filtered by OpenShift grouped by GCP Project} azure {Microsoft Azure grouped by GCP Project} oci {Oracle Cloud Infrastructure grouped by GCP Project} azure_ocp {Microsoft Azure filtered by OpenShift grouped by GCP Project} gcp {Google Cloud Platform grouped by GCP Project} gcp_ocp {Google Cloud Platform filtered by OpenShift grouped by GCP Project} ibm {IBM Cloud grouped by GCP Project} ibm_ocp {IBM Cloud filtered by OpenShift grouped by GCP Project} ocp {OpenShift grouped by GCP Project} ocp_cloud {All cloud filtered by OpenShift grouped by GCP Project} other {}}} node {{provider, select, aws {Amazon Web Services grouped by Node} aws_ocp {Amazon Web Services filtered by OpenShift grouped by Node} azure {Microsoft Azure grouped by Node} oci {Oracle Cloud Infrastructure grouped by Node} azure_ocp {Microsoft Azure filtered by OpenShift grouped by Node} gcp {Google Cloud Platform grouped by Node} gcp_ocp {Google Cloud Platform filtered by OpenShift grouped by Node} ibm {IBM Cloud grouped by Node} ibm_ocp {IBM Cloud filtered by OpenShift grouped by Node} ocp {OpenShift grouped by Node} ocp_cloud {All cloud filtered by OpenShift grouped by Node} other {}}} org_unit_id {{provider, select, aws {Amazon Web Services grouped by Organizational unit} aws_ocp {Amazon Web Services filtered by OpenShift grouped by Organizational unit} azure {Microsoft Azure grouped by Organizational unit} oci {Oracle Cloud Infrastructure grouped by Organizational unit} azure_ocp {Microsoft Azure filtered by OpenShift grouped by Organizational unit} gcp {Google Cloud Platform grouped by Organizational unit} gcp_ocp {Google Cloud Platform filtered by OpenShift grouped by Organizational unit} ibm {IBM Cloud grouped by Organizational unit} ibm_ocp {IBM Cloud filtered by OpenShift grouped by Organizational unit} ocp {OpenShift grouped by Organizational unit} ocp_cloud {All cloud filtered by OpenShift grouped by Organizational unit} other {}}} payer_tenant_id {{provider, select, oci {Oracle Cloud Infrastructure grouped by Account} other {}}}product_service {{provider, select, oci {Oracle Cloud Infrastructure grouped by Service} other {}}}project {{provider, select, aws {Amazon Web Services grouped by Project} aws_ocp {Amazon Web Services filtered by OpenShift grouped by Project} azure {Microsoft Azure grouped by Project} oci {Oracle Cloud Infrastructure grouped by Project} azure_ocp {Microsoft Azure filtered by OpenShift grouped by Project} gcp {Google Cloud Platform grouped by Project} gcp_ocp {Google Cloud Platform filtered by OpenShift grouped by Project} ibm {IBM Cloud grouped by Project} ibm_ocp {IBM Cloud filtered by OpenShift grouped by Project} ocp {OpenShift grouped by Project} ocp_cloud {All cloud filtered by OpenShift grouped by Project} other {}}} region {{provider, select, aws {Amazon Web Services grouped by Region} aws_ocp {Amazon Web Services filtered by OpenShift grouped by Region} azure {Microsoft Azure grouped by Region} oci {Oracle Cloud Infrastructure grouped by Region} azure_ocp {Microsoft Azure filtered by OpenShift grouped by Region} gcp {Google Cloud Platform grouped by Region} gcp_ocp {Google Cloud Platform filtered by OpenShift grouped by Region} ibm {IBM Cloud grouped by Region} ibm_ocp {IBM Cloud filtered by OpenShift grouped by Region} ocp {OpenShift grouped by Region} ocp_cloud {All cloud filtered by OpenShift grouped by Region} other {}}} resource_location {{provider, select, aws {Amazon Web Services grouped by Region} aws_ocp {Amazon Web Services filtered by OpenShift grouped by Region} azure {Microsoft Azure grouped by Region} oci {Oracle Cloud Infrastructure grouped by Region} azure_ocp {Microsoft Azure filtered by OpenShift grouped by Region} gcp {Google Cloud Platform grouped by Region} gcp_ocp {Google Cloud Platform filtered by OpenShift grouped by Region} ibm {IBM Cloud grouped by Region} ibm_ocp {IBM Cloud filtered by OpenShift grouped by Region} ocp {OpenShift grouped by Region} ocp_cloud {All cloud filtered by OpenShift grouped by Region} other {}}} service {{provider, select, aws {Amazon Web Services grouped by Service} aws_ocp {Amazon Web Services filtered by OpenShift grouped by Service} azure {Microsoft Azure grouped by Service} oci {Oracle Cloud Infrastructure grouped by Service} azure_ocp {Microsoft Azure filtered by OpenShift grouped by Service} gcp {Google Cloud Platform grouped by Service} gcp_ocp {Google Cloud Platform filtered by OpenShift grouped by Service} ibm {IBM Cloud grouped by Service} ibm_ocp {IBM Cloud filtered by OpenShift grouped by Service} ocp {OpenShift grouped by Service} ocp_cloud {All cloud filtered by OpenShift grouped by Service} other {}}} service_name {{provider, select, aws {Amazon Web Services grouped by Service} aws_ocp {Amazon Web Services filtered by OpenShift grouped by Service} azure {Microsoft Azure grouped by Service} oci {Oracle Cloud Infrastructure grouped by Service} azure_ocp {Microsoft Azure filtered by OpenShift grouped by Service} gcp {Google Cloud Platform grouped by Service} gcp_ocp {Google Cloud Platform filtered by OpenShift grouped by Service} ibm {IBM Cloud grouped by Service} ibm_ocp {IBM Cloud filtered by OpenShift grouped by Service} ocp {OpenShift grouped by Service} ocp_cloud {All cloud filtered by OpenShift grouped by Service} other {}}} subscription_guid {{provider, select, aws {Amazon Web Services grouped by Account} aws_ocp {Amazon Web Services filtered by OpenShift grouped by Account} azure {Microsoft Azure grouped by Account} oci {Oracle Cloud Infrastructure grouped by Account} azure_ocp {Microsoft Azure filtered by OpenShift grouped by Account} gcp {Google Cloud Platform grouped by Account} gcp_ocp {Google Cloud Platform filtered by OpenShift grouped by Account} ibm {IBM Cloud grouped by Account} ibm_ocp {IBM Cloud filtered by OpenShift grouped by Account} ocp {OpenShift grouped by Account} ocp_cloud {All cloud filtered by OpenShift grouped by Account} other {}}} tag {{provider, select, aws {Amazon Web Services grouped by Tag} aws_ocp {Amazon Web Services filtered by OpenShift grouped by Tag} azure {Microsoft Azure grouped by Tag} oci {Oracle Cloud Infrastructure grouped by Tag} azure_ocp {Microsoft Azure filtered by OpenShift grouped by Tag} gcp {Google Cloud Platform grouped by Tag} gcp_ocp {Google Cloud Platform filtered by OpenShift grouped by Tag} ibm {IBM Cloud grouped by Tag} ibm_ocp {IBM Cloud filtered by OpenShift grouped by Tag} ocp {OpenShift grouped by Tag} ocp_cloud {All cloud filtered by OpenShift grouped by Tag} other {}}} other {}}", + "exportHeading": "{groupBy, select, account {Aggregates of the following accounts will be exported to a .csv file.} aws_category {Aggregates of the following cost categories will be exported to a .csv file.} cluster {Aggregates of the following clusters will be exported to a .csv file.} gcp_project {Aggregates of the following GCP projects will be exported to a .csv file.} instance {Aggregates of the following instances will be exported to a .csv file.} node {Aggregates of the following nodes will be exported to a .csv file.} org_unit_id {Aggregates of the following organizational units will be exported to a .csv file.} payer_tenant_id {Aggregates of the following accounts will be exported to a .csv file.} product_service {Aggregates of the following services will be exported to a .csv file.} project {Aggregates of the following projects will be exported to a .csv file.} region {Aggregates of the following regions will be exported to a .csv file.} resource_location {Aggregates of the regions will be exported to a .csv file.} service {Aggregates of the following services will be exported to a .csv file.} service_name {Aggregates of the following services will be exported to a .csv file.} subscription_guid {Aggregates of the following accounts will be exported to a .csv file.} tag {Aggregates of the following tags will be exported to a .csv file.} other {}}", + "exportName": "{groupBy, select, account {{provider, select, aws {Amazon Web Services grouped by Account} aws_ocp {Amazon Web Services filtered by OpenShift grouped by Account} azure {Microsoft Azure grouped by Account} oci {Oracle Cloud Infrastructure grouped by Account} azure_ocp {Microsoft Azure filtered by OpenShift grouped by Account} gcp {Google Cloud Platform grouped by Account} gcp_ocp {Google Cloud Platform filtered by OpenShift grouped by Account} ibm {IBM Cloud grouped by Account} ibm_ocp {IBM Cloud filtered by OpenShift grouped by Account} ocp {OpenShift grouped by Account} ocp_cloud {All cloud filtered by OpenShift grouped by Account} other {}}} aws_category {{provider, select, aws {Amazon Web Services grouped by Cost category} aws_ocp {Amazon Web Services filtered by OpenShift grouped by Cost category} azure {Microsoft Azure grouped by Cost category} oci {Oracle Cloud Infrastructure grouped by Cost category} azure_ocp {Microsoft Azure filtered by OpenShift grouped by Cost category} gcp {Google Cloud Platform grouped by Cost category} gcp_ocp {Google Cloud Platform filtered by OpenShift grouped by Cost category} ibm {IBM Cloud grouped by Cost category} ibm_ocp {IBM Cloud filtered by OpenShift grouped by Cost category} ocp {OpenShift grouped by Cost category} ocp_cloud {All cloud filtered by OpenShift grouped by Cost category} other {}}} cluster {{provider, select, aws {Amazon Web Services grouped by Cluster} aws_ocp {Amazon Web Services filtered by OpenShift grouped by Cluster} azure {Microsoft Azure grouped by Cluster} oci {Oracle Cloud Infrastructure grouped by Cluster} azure_ocp {Microsoft Azure filtered by OpenShift grouped by Cluster} gcp {Google Cloud Platform grouped by Cluster} gcp_ocp {Google Cloud Platform filtered by OpenShift grouped by Cluster} ibm {IBM Cloud grouped by Cluster} ibm_ocp {IBM Cloud filtered by OpenShift grouped by Cluster} ocp {OpenShift grouped by Cluster} ocp_cloud {All cloud filtered by OpenShift grouped by Cluster} other {}}} gcp_project {{provider, select, aws {Amazon Web Services grouped by GCP Project} aws_ocp {Amazon Web Services filtered by OpenShift grouped by GCP Project} azure {Microsoft Azure grouped by GCP Project} oci {Oracle Cloud Infrastructure grouped by GCP Project} azure_ocp {Microsoft Azure filtered by OpenShift grouped by GCP Project} gcp {Google Cloud Platform grouped by GCP Project} gcp_ocp {Google Cloud Platform filtered by OpenShift grouped by GCP Project} ibm {IBM Cloud grouped by GCP Project} ibm_ocp {IBM Cloud filtered by OpenShift grouped by GCP Project} ocp {OpenShift grouped by GCP Project} ocp_cloud {All cloud filtered by OpenShift grouped by GCP Project} other {}}} instance {{provider, select, aws {Amazon Web Services grouped by instance} aws_ocp {Amazon Web Services filtered by OpenShift grouped by instance} azure {Microsoft Azure grouped by instance} oci {Oracle Cloud Infrastructure grouped by instance} azure_ocp {Microsoft Azure filtered by OpenShift grouped by instance} gcp {Google Cloud Platform grouped by instance} gcp_ocp {Google Cloud Platform filtered by OpenShift grouped by instance} ibm {IBM Cloud grouped by instance} ibm_ocp {IBM Cloud filtered by OpenShift grouped by instance} ocp {OpenShift grouped by instance} ocp_cloud {All cloud filtered by OpenShift grouped by instance} other {}}} node {{provider, select, aws {Amazon Web Services grouped by Node} aws_ocp {Amazon Web Services filtered by OpenShift grouped by Node} azure {Microsoft Azure grouped by Node} oci {Oracle Cloud Infrastructure grouped by Node} azure_ocp {Microsoft Azure filtered by OpenShift grouped by Node} gcp {Google Cloud Platform grouped by Node} gcp_ocp {Google Cloud Platform filtered by OpenShift grouped by Node} ibm {IBM Cloud grouped by Node} ibm_ocp {IBM Cloud filtered by OpenShift grouped by Node} ocp {OpenShift grouped by Node} ocp_cloud {All cloud filtered by OpenShift grouped by Node} other {}}} org_unit_id {{provider, select, aws {Amazon Web Services grouped by Organizational unit} aws_ocp {Amazon Web Services filtered by OpenShift grouped by Organizational unit} azure {Microsoft Azure grouped by Organizational unit} oci {Oracle Cloud Infrastructure grouped by Organizational unit} azure_ocp {Microsoft Azure filtered by OpenShift grouped by Organizational unit} gcp {Google Cloud Platform grouped by Organizational unit} gcp_ocp {Google Cloud Platform filtered by OpenShift grouped by Organizational unit} ibm {IBM Cloud grouped by Organizational unit} ibm_ocp {IBM Cloud filtered by OpenShift grouped by Organizational unit} ocp {OpenShift grouped by Organizational unit} ocp_cloud {All cloud filtered by OpenShift grouped by Organizational unit} other {}}} payer_tenant_id {{provider, select, oci {Oracle Cloud Infrastructure grouped by Account} other {}}}product_service {{provider, select, oci {Oracle Cloud Infrastructure grouped by Service} other {}}}project {{provider, select, aws {Amazon Web Services grouped by Project} aws_ocp {Amazon Web Services filtered by OpenShift grouped by Project} azure {Microsoft Azure grouped by Project} oci {Oracle Cloud Infrastructure grouped by Project} azure_ocp {Microsoft Azure filtered by OpenShift grouped by Project} gcp {Google Cloud Platform grouped by Project} gcp_ocp {Google Cloud Platform filtered by OpenShift grouped by Project} ibm {IBM Cloud grouped by Project} ibm_ocp {IBM Cloud filtered by OpenShift grouped by Project} ocp {OpenShift grouped by Project} ocp_cloud {All cloud filtered by OpenShift grouped by Project} other {}}} region {{provider, select, aws {Amazon Web Services grouped by Region} aws_ocp {Amazon Web Services filtered by OpenShift grouped by Region} azure {Microsoft Azure grouped by Region} oci {Oracle Cloud Infrastructure grouped by Region} azure_ocp {Microsoft Azure filtered by OpenShift grouped by Region} gcp {Google Cloud Platform grouped by Region} gcp_ocp {Google Cloud Platform filtered by OpenShift grouped by Region} ibm {IBM Cloud grouped by Region} ibm_ocp {IBM Cloud filtered by OpenShift grouped by Region} ocp {OpenShift grouped by Region} ocp_cloud {All cloud filtered by OpenShift grouped by Region} other {}}} resource_location {{provider, select, aws {Amazon Web Services grouped by Region} aws_ocp {Amazon Web Services filtered by OpenShift grouped by Region} azure {Microsoft Azure grouped by Region} oci {Oracle Cloud Infrastructure grouped by Region} azure_ocp {Microsoft Azure filtered by OpenShift grouped by Region} gcp {Google Cloud Platform grouped by Region} gcp_ocp {Google Cloud Platform filtered by OpenShift grouped by Region} ibm {IBM Cloud grouped by Region} ibm_ocp {IBM Cloud filtered by OpenShift grouped by Region} ocp {OpenShift grouped by Region} ocp_cloud {All cloud filtered by OpenShift grouped by Region} other {}}} service {{provider, select, aws {Amazon Web Services grouped by Service} aws_ocp {Amazon Web Services filtered by OpenShift grouped by Service} azure {Microsoft Azure grouped by Service} oci {Oracle Cloud Infrastructure grouped by Service} azure_ocp {Microsoft Azure filtered by OpenShift grouped by Service} gcp {Google Cloud Platform grouped by Service} gcp_ocp {Google Cloud Platform filtered by OpenShift grouped by Service} ibm {IBM Cloud grouped by Service} ibm_ocp {IBM Cloud filtered by OpenShift grouped by Service} ocp {OpenShift grouped by Service} ocp_cloud {All cloud filtered by OpenShift grouped by Service} other {}}} service_name {{provider, select, aws {Amazon Web Services grouped by Service} aws_ocp {Amazon Web Services filtered by OpenShift grouped by Service} azure {Microsoft Azure grouped by Service} oci {Oracle Cloud Infrastructure grouped by Service} azure_ocp {Microsoft Azure filtered by OpenShift grouped by Service} gcp {Google Cloud Platform grouped by Service} gcp_ocp {Google Cloud Platform filtered by OpenShift grouped by Service} ibm {IBM Cloud grouped by Service} ibm_ocp {IBM Cloud filtered by OpenShift grouped by Service} ocp {OpenShift grouped by Service} ocp_cloud {All cloud filtered by OpenShift grouped by Service} other {}}} subscription_guid {{provider, select, aws {Amazon Web Services grouped by Account} aws_ocp {Amazon Web Services filtered by OpenShift grouped by Account} azure {Microsoft Azure grouped by Account} oci {Oracle Cloud Infrastructure grouped by Account} azure_ocp {Microsoft Azure filtered by OpenShift grouped by Account} gcp {Google Cloud Platform grouped by Account} gcp_ocp {Google Cloud Platform filtered by OpenShift grouped by Account} ibm {IBM Cloud grouped by Account} ibm_ocp {IBM Cloud filtered by OpenShift grouped by Account} ocp {OpenShift grouped by Account} ocp_cloud {All cloud filtered by OpenShift grouped by Account} other {}}} tag {{provider, select, aws {Amazon Web Services grouped by Tag} aws_ocp {Amazon Web Services filtered by OpenShift grouped by Tag} azure {Microsoft Azure grouped by Tag} oci {Oracle Cloud Infrastructure grouped by Tag} azure_ocp {Microsoft Azure filtered by OpenShift grouped by Tag} gcp {Google Cloud Platform grouped by Tag} gcp_ocp {Google Cloud Platform filtered by OpenShift grouped by Tag} ibm {IBM Cloud grouped by Tag} ibm_ocp {IBM Cloud filtered by OpenShift grouped by Tag} ocp {OpenShift grouped by Tag} ocp_cloud {All cloud filtered by OpenShift grouped by Tag} other {}}} other {}}", "exportNameRequired": "Please enter a name for the export", "exportNameTooLong": "Should not exceed 50 characters", "exportResolution": "{value, select, daily {Daily} monthly {Monthly} other {}}", - "exportSelected": "{groupBy, select, account {Selected accounts ({count})} aws_category {Selected cost categories ({count})} cluster {Selected clusters ({count})} gcp_project {Selected GCP projects ({count})} node {Selected nodes ({count})} org_unit_id {Selected organizational units ({count})} payer_tenant_id {Selected accounts ({count})} product_service {Selected services ({count})} project {Selected projects ({count})} region {Selected regions ({count})} resource_location {Selected regions ({count})} service {Selected services ({count})} service_name {Selected services ({count})} subscription_guid {Selected accounts ({count})} tag {Selected tags ({count})} other {}}", + "exportSelected": "{groupBy, select, account {Selected accounts ({count})} aws_category {Selected cost categories ({count})} cluster {Selected clusters ({count})} gcp_project {Selected GCP projects ({count})} instance {Selected instances ({count})} node {Selected nodes ({count})} org_unit_id {Selected organizational units ({count})} payer_tenant_id {Selected accounts ({count})} product_service {Selected services ({count})} project {Selected projects ({count})} region {Selected regions ({count})} resource_location {Selected regions ({count})} service {Selected services ({count})} service_name {Selected services ({count})} subscription_guid {Selected accounts ({count})} tag {Selected tags ({count})} other {}}", "exportTimeScope": "{value, select, current {Current ({date})} previous {Previous ({date})} other {}}", "exportTimeScopeTitle": "Month", "exportTitle": "Export", @@ -320,8 +327,10 @@ "filterByTagValueAriaLabel": "Tag values", "filterByTagValueButtonAriaLabel": "Filter button for tag value", "filterByValuePlaceholder": "Filter by value", - "filterByValues": "{value, select, account {Account} aws_category {Cost category} cluster {Cluster} container {Container} default {Default} gcp_project {GCP project} group {Group} name {Name} node {Node} org_unit_id {Organizational unit} payer_tenant_id {Account} persistent_volume_claim {Persistent volume claim} product_service {Service} project {Project} region {Region} resource_location {Region} service {Service} service_name {Service} source_type {Integration} status {Status} storage_class {StorageClass} subscription_guid {Account} tag {Tag} tag_key {Tag key} tag_key_child {Child tag Key} tag_key_parent {Parent tag Key} workload {Workload name} workload_type {Workload type} other {}}", + "filterByValues": "{value, select, account {Account} aws_category {Cost category} cluster {Cluster} container {Container} default {Default} gcp_project {GCP project} group {Group} instance {Instance} name {Name} node {Node} org_unit_id {Organizational unit} operating_system {Operating system} payer_tenant_id {Account} persistent_volume_claim {Persistent volume claim} product_service {Service} project {Project} region {Region} resource_location {Region} service {Service} service_name {Service} source_type {Integration} status {Status} storage_class {StorageClass} subscription_guid {Account} tag {Tag} tag_key {Tag key} tag_key_child {Child tag Key} tag_key_parent {Parent tag Key} workload {Workload name} workload_type {Workload type} other {}}", "filterByValuesAriaLabel": "Values", + "filteredBy": "Filtered by", + "filteredByWarning": "This page shows filtered results. To undo filters, clear filters on the previous page.", "forDate": "{value} for {dateRange}", "gcp": "Google Cloud Platform", "gcpComputeTitle": "Compute instances usage", @@ -338,7 +347,7 @@ "groupByValuesTitleCase": "{value, select, account {{count, plural, one {Account} other {Accounts}}} aws_category {{count, plural, one {Cost category} other {Cost categories}}} cluster {{count, plural, one {Cluster} other {Clusters}}} gcp_project {{count, plural, one {GCP project} other {GCP projects}}} node {{count, plural, one {Node} other {Node}}} org_unit_id {{count, plural, one {Organizational unit} other {Organizational units}}} payer_tenant_id {{count, plural, one {Account} other {Accounts}}} product_service {{count, plural, one {Service} other {Services}}} project {{count, plural, one {Project} other {Projects}}} region {{count, plural, one {Region} other {Regions}}} resource_location {{count, plural, one {Region} other {Regions}}} service {{count, plural, one {Service} other {Services}}} service_name {{count, plural, one {Service} other {Services}}} subscription_guid {{count, plural, one {Account} other {Accounts}}} tag {{count, plural, one {Tag} other {Tags}}} other {}}", "historicalChartCostLabel": "Cost ({units})", "historicalChartDayOfMonthLabel": "Day of Month", - "historicalChartTitle": "{value, select, cost {Cost comparison} cpu {CPU usage, request, and limit comparison} instance_type {Compute usage comparison}memory {Memory usage, request, and limit comparison} modal {{name} daily usage comparison} storage {Storage usage comparison} virtual_machine {Virtual machine usage comparison}other {}}", + "historicalChartTitle": "{value, select, cost {Cost comparison} cpu {CPU usage, request, and limit comparison} instance_type {Compute usage comparison}memory {Memory usage, request, and limit comparison} modal {{name} daily usage comparison} network {Network usage comparison} storage {Storage usage comparison} virtual_machine {Virtual machine usage comparison}other {}}", "historicalChartUsageLabel": "{value, select, instance_type {hrs} storage {gb-mo} other {}}", "ibm": "IBM Cloud", "ibmComputeTitle": "Compute instances usage", @@ -351,6 +360,7 @@ "inactiveSourcesTitle": "A problem was detected with {value}", "inactiveSourcesTitleMultiplier": "A problem was detected with the following integrations", "infrastructure": "Infrastructure", + "instances": "Instances", "lastProcessed": "Last processed", "learnMore": "Learn more", "loadingStateDesc": "Searching for your integrations. Do not refresh the browser", @@ -379,7 +389,10 @@ "metricValues": "{value, select, cpu {CPU} cluster {Cluster} memory {Memory} node {Node} persistent_volume_claims {Persistent volume claims} storage {Storage} other {}}", "metricsOperatorVersion": "Cost Management operator version", "monthOverMonthChange": "Month over month change", + "moreOptions": "More options", "names": "{count, plural, one {Name} other {Names}}", + "network": "Network", + "networkDesc": "Distribute the cost of network traffic to projects based on distribution type.", "next": "next", "no": "No", "noDataForDate": "No data available for {dateRange}", @@ -387,11 +400,11 @@ "noDataStateRefresh": "Refresh this page", "noDataStateTitle": "Still processing the data", "noExportsStateTitle": "There are no export files available", + "noInstancesDesc": "Add an Amazon EC2 instance to see a total cost breakdown of your spend by instances.", + "noInstancesTitle": "No instances available", "noMappedTags": "No mapped tags", "noMappedTagsDesc": "Map multiple tags across data sources to be used as a single tag key for report grouping and filtering. {warning} Changes will be reflected within 24 hours. {learnMore}", "noMappedTagsWarning": "Tags must be enabled to be mapped.", - "noOptimizationsDesc": "Resource Optimization is now available in preview for select customers. If your organization wants to participate, tell us through the Feedback button, which is purple and located on the right. Otherwise, there is not enough data available to generate an optimization.", - "noOptimizationsTitle": "No optimizations available", "noProvidersStateAwsDesc": "Add an Amazon Web Services account to see a total cost breakdown of your spend by accounts, organizational units, services, regions, or tags.", "noProvidersStateAwsTitle": "Track your Amazon Web Services spending!", "noProvidersStateAzureDesc": "Add a Microsoft Azure account to see a total cost breakdown of your spend by accounts, services, regions, or tags.", @@ -546,7 +559,9 @@ "start": "Start", "status": "{value, select, pending {Pending} running {Running} failed {Failed} other {}}", "statusActions": "Status/Actions", + "storage": "Storage", "storageClass": "StorageClass", + "storageDesc": "Distribute the cost of storage to projects based on distribution type.", "suggestions": "Suggestions", "sumPlatformCosts": "Sum platform costs", "summary": "Summary", @@ -606,6 +621,7 @@ "usageSubtitle": "{value} {units} maximum", "valueUnits": "{value} {units}", "various": "Various", + "vcpuTitle": "vCPU", "volumeTitle": "Volume", "workerUnallocated": "Worker unallocated", "workerUnallocatedDesc": "Distribute unused and non-reserved resource costs to projects", diff --git a/mkdocs.yml b/mkdocs.yml new file mode 100644 index 000000000..3647e9f81 --- /dev/null +++ b/mkdocs.yml @@ -0,0 +1,4 @@ +docs_dir: docs/ +site_name: Koku UI Documentation +plugins: + - techdocs-core diff --git a/package-lock.json b/package-lock.json index ce55ef877..7af60a2b2 100644 --- a/package-lock.json +++ b/package-lock.json @@ -10,66 +10,65 @@ "hasInstallScript": true, "license": "GNU AGPLv3", "dependencies": { - "@patternfly/patternfly": "5.2.0", - "@patternfly/react-charts": "7.2.2", - "@patternfly/react-component-groups": "5.1.0", - "@patternfly/react-core": "5.2.0", - "@patternfly/react-icons": "5.2.0", - "@patternfly/react-table": "5.2.0", - "@patternfly/react-tokens": "5.2.0", - "@redhat-cloud-services/frontend-components": "^4.2.6", + "@patternfly/patternfly": "5.3.1", + "@patternfly/react-charts": "7.3.0", + "@patternfly/react-component-groups": "^5.1.0", + "@patternfly/react-core": "5.3.3", + "@patternfly/react-icons": "5.3.2", + "@patternfly/react-table": "5.3.3", + "@patternfly/react-tokens": "5.3.1", + "@redhat-cloud-services/frontend-components": "^4.2.10", "@redhat-cloud-services/frontend-components-notifications": "^4.1.0", "@redhat-cloud-services/frontend-components-translations": "^3.2.7", - "@redhat-cloud-services/frontend-components-utilities": "^4.0.10", - "@redhat-cloud-services/rbac-client": "^1.3.3", - "@reduxjs/toolkit": "^2.2.3", - "@unleash/proxy-client-react": "^4.2.2", - "axios": "^1.6.8", + "@redhat-cloud-services/frontend-components-utilities": "^4.0.11", + "@redhat-cloud-services/rbac-client": "^1.4.4", + "@reduxjs/toolkit": "^2.2.5", + "@unleash/proxy-client-react": "^4.2.4", + "axios": "^1.7.2", "date-fns": "^3.6.0", "js-file-download": "^0.4.12", "lodash": "^4.17.21", "qs": "^6.12.1", - "react": "^18.2.0", - "react-dom": "^18.2.0", - "react-intl": "^6.6.5", - "react-redux": "^9.1.1", - "react-router-dom": "^6.22.3", + "react": "^18.3.1", + "react-dom": "^18.3.1", + "react-intl": "^6.6.8", + "react-redux": "^9.1.2", + "react-router-dom": "^6.23.1", "redux": "^5.0.1", "redux-thunk": "^3.1.0", "typesafe-actions": "^5.1.0", - "unleash-proxy-client": "^3.3.2", "victory-core": "^37.0.2" }, "devDependencies": { - "@formatjs/cli": "^6.2.9", - "@formatjs/ecma402-abstract": "^1.18.2", - "@formatjs/icu-messageformat-parser": "^2.7.6", + "@formatjs/cli": "^6.2.12", + "@formatjs/ecma402-abstract": "^2.0.0", + "@formatjs/icu-messageformat-parser": "^2.7.8", "@redhat-cloud-services/eslint-config-redhat-cloud-services": "^2.0.4", - "@redhat-cloud-services/frontend-components-config": "^6.0.12", - "@redhat-cloud-services/tsc-transform-imports": "^1.0.9", - "@swc/core": "^1.4.14", + "@redhat-cloud-services/frontend-components-config": "^6.0.14", + "@redhat-cloud-services/tsc-transform-imports": "^1.0.10", + "@swc/core": "^1.5.7", "@swc/jest": "^0.2.36", - "@testing-library/jest-dom": "^6.4.2", - "@testing-library/react": "^15.0.2", + "@testing-library/jest-dom": "^6.4.5", + "@testing-library/react": "^15.0.7", "@testing-library/user-event": "^14.5.2", "@types/jest": "^29.5.12", "@types/qs": "^6.9.15", - "@types/react": "^18.2.79", - "@types/react-dom": "^18.2.25", + "@types/react": "^18.3.3", + "@types/react-dom": "^18.3.0", "@types/react-redux": "^7.1.33", "@types/react-router-dom": "^5.3.3", - "@typescript-eslint/eslint-plugin": "^7.7.0", - "@typescript-eslint/parser": "^7.7.0", + "@typescript-eslint/eslint-plugin": "^7.11.0", + "@typescript-eslint/parser": "^7.11.0", "aphrodite": "^2.4.0", "copy-webpack-plugin": "^12.0.2", "eslint": "^8.57.0", - "eslint-plugin-formatjs": "^4.13.0", - "eslint-plugin-jest-dom": "^5.2.0", - "eslint-plugin-jsdoc": "^48.2.3", - "eslint-plugin-markdown": "^4.0.1", - "eslint-plugin-patternfly-react": "^5.2.1", + "eslint-plugin-formatjs": "^4.13.3", + "eslint-plugin-jest-dom": "^5.4.0", + "eslint-plugin-jsdoc": "^48.2.7", + "eslint-plugin-markdown": "^5.0.0", + "eslint-plugin-patternfly-react": "^5.3.0", "eslint-plugin-prettier": "^5.1.3", - "eslint-plugin-react": "^7.34.1", + "eslint-plugin-react": "^7.34.2", "eslint-plugin-simple-import-sort": "^12.1.0", "eslint-plugin-sort-keys-fix": "^1.1.2", "eslint-plugin-testing-library": "^6.2.2", @@ -82,9 +81,9 @@ "jws": "^4.0.0", "npm-run-all": "^4.1.5", "prettier": "^3.2.5", - "rimraf": "^5.0.5", + "rimraf": "^5.0.7", "swc_mut_cjs_exports": "^0.90.24", - "ts-jest": "^29.1.2", + "ts-jest": "^29.1.4", "ts-patch": "^3.1.2", "typescript": "^5.4.5", "webpack-bundle-analyzer": "^4.10.2" @@ -746,11 +745,14 @@ "integrity": "sha512-Qv4LTqO11jepd5Qmlp3M1YEjBumoTHcHFdgPTQ+sFlIL5myi/7xu/POwP7IRu6odBdmLXdtIs1D6TuW6kbwbbg==" }, "node_modules/@es-joy/jsdoccomment": { - "version": "0.42.0", - "resolved": "https://registry.npmjs.org/@es-joy/jsdoccomment/-/jsdoccomment-0.42.0.tgz", - "integrity": "sha512-R1w57YlVA6+YE01wch3GPYn6bCsrOV3YW/5oGGE2tmX6JcL9Nr+b5IikrjMPF+v9CV3ay+obImEdsDhovhJrzw==", + "version": "0.43.1", + "resolved": "https://registry.npmjs.org/@es-joy/jsdoccomment/-/jsdoccomment-0.43.1.tgz", + "integrity": "sha512-I238eDtOolvCuvtxrnqtlBaw0BwdQuYqK7eA6XIonicMdOOOb75mqdIzkGDUbS04+1Di007rgm9snFRNeVrOog==", "dev": true, "dependencies": { + "@types/eslint": "^8.56.5", + "@types/estree": "^1.0.5", + "@typescript-eslint/types": "^7.2.0", "comment-parser": "1.4.1", "esquery": "^1.5.0", "jsdoc-type-pratt-parser": "~4.0.0" @@ -877,9 +879,9 @@ } }, "node_modules/@formatjs/cli": { - "version": "6.2.9", - "resolved": "https://registry.npmjs.org/@formatjs/cli/-/cli-6.2.9.tgz", - "integrity": "sha512-YH09kY6oufPdNDIwva/rC7wyg/ptJG6hRZ768eJEafiBR5R1VV1pKFmx106FV5WT7nzBm8Xf4Td+8+Mu+DtQsg==", + "version": "6.2.12", + "resolved": "https://registry.npmjs.org/@formatjs/cli/-/cli-6.2.12.tgz", + "integrity": "sha512-bt1NEgkeYN8N9zWcpsPu3fZ57vv+biA+NtIQBlyOZnCp1bcvh+vNTXvmwF4C5qxqDtCylpOIb3yi3Ktgp4v0JQ==", "dev": true, "bin": { "formatjs": "bin/formatjs" @@ -888,18 +890,46 @@ "node": ">= 16" }, "peerDependencies": { + "@glimmer/env": "^0.1.7", + "@glimmer/reference": "^0.91.1 || ^0.92.0", + "@glimmer/syntax": "^0.92.0", + "@glimmer/validator": "^0.92.0", + "@vue/compiler-core": "^3.4.0", + "content-tag": "^2.0.1", + "ember-template-recast": "^6.1.4", "vue": "^3.4.0" }, "peerDependenciesMeta": { + "@glimmer/env": { + "optional": true + }, + "@glimmer/reference": { + "optional": true + }, + "@glimmer/syntax": { + "optional": true + }, + "@glimmer/validator": { + "optional": true + }, + "@vue/compiler-core": { + "optional": true + }, + "content-tag": { + "optional": true + }, + "ember-template-recast": { + "optional": true + }, "vue": { "optional": true } } }, "node_modules/@formatjs/ecma402-abstract": { - "version": "1.18.2", - "resolved": "https://registry.npmjs.org/@formatjs/ecma402-abstract/-/ecma402-abstract-1.18.2.tgz", - "integrity": "sha512-+QoPW4csYALsQIl8GbN14igZzDbuwzcpWrku9nyMXlaqAlwRBgl5V+p0vWMGFqHOw37czNXaP/lEk4wbLgcmtA==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@formatjs/ecma402-abstract/-/ecma402-abstract-2.0.0.tgz", + "integrity": "sha512-rRqXOqdFmk7RYvj4khklyqzcfQl9vEL/usogncBHRZfZBDOwMGuSRNFl02fu5KGHXdbinju+YXyuR+Nk8xlr/g==", "dependencies": { "@formatjs/intl-localematcher": "0.5.4", "tslib": "^2.4.0" @@ -914,35 +944,35 @@ } }, "node_modules/@formatjs/icu-messageformat-parser": { - "version": "2.7.6", - "resolved": "https://registry.npmjs.org/@formatjs/icu-messageformat-parser/-/icu-messageformat-parser-2.7.6.tgz", - "integrity": "sha512-etVau26po9+eewJKYoiBKP6743I1br0/Ie00Pb/S/PtmYfmjTcOn2YCh2yNkSZI12h6Rg+BOgQYborXk46BvkA==", + "version": "2.7.8", + "resolved": "https://registry.npmjs.org/@formatjs/icu-messageformat-parser/-/icu-messageformat-parser-2.7.8.tgz", + "integrity": "sha512-nBZJYmhpcSX0WeJ5SDYUkZ42AgR3xiyhNCsQweFx3cz/ULJjym8bHAzWKvG5e2+1XO98dBYC0fWeeAECAVSwLA==", "dependencies": { - "@formatjs/ecma402-abstract": "1.18.2", - "@formatjs/icu-skeleton-parser": "1.8.0", + "@formatjs/ecma402-abstract": "2.0.0", + "@formatjs/icu-skeleton-parser": "1.8.2", "tslib": "^2.4.0" } }, "node_modules/@formatjs/icu-skeleton-parser": { - "version": "1.8.0", - "resolved": "https://registry.npmjs.org/@formatjs/icu-skeleton-parser/-/icu-skeleton-parser-1.8.0.tgz", - "integrity": "sha512-QWLAYvM0n8hv7Nq5BEs4LKIjevpVpbGLAJgOaYzg9wABEoX1j0JO1q2/jVkO6CVlq0dbsxZCngS5aXbysYueqA==", + "version": "1.8.2", + "resolved": "https://registry.npmjs.org/@formatjs/icu-skeleton-parser/-/icu-skeleton-parser-1.8.2.tgz", + "integrity": "sha512-k4ERKgw7aKGWJZgTarIcNEmvyTVD9FYh0mTrrBMHZ1b8hUu6iOJ4SzsZlo3UNAvHYa+PnvntIwRPt1/vy4nA9Q==", "dependencies": { - "@formatjs/ecma402-abstract": "1.18.2", + "@formatjs/ecma402-abstract": "2.0.0", "tslib": "^2.4.0" } }, "node_modules/@formatjs/intl": { - "version": "2.10.1", - "resolved": "https://registry.npmjs.org/@formatjs/intl/-/intl-2.10.1.tgz", - "integrity": "sha512-dsLG15U7xDi8yzKf4hcAWSsCaez3XrjTO2oaRHPyHtXLm1aEzYbDw6bClo/HMHu+iwS5GbDqT3DV+hYP2ylScg==", + "version": "2.10.4", + "resolved": "https://registry.npmjs.org/@formatjs/intl/-/intl-2.10.4.tgz", + "integrity": "sha512-56483O+HVcL0c7VucAS2tyH020mt9XTozZO67cwtGg0a7KWDukS/FzW3OnvaHmTHDuYsoPIzO+ZHVfU6fT/bJw==", "dependencies": { - "@formatjs/ecma402-abstract": "1.18.2", + "@formatjs/ecma402-abstract": "2.0.0", "@formatjs/fast-memoize": "2.2.0", - "@formatjs/icu-messageformat-parser": "2.7.6", - "@formatjs/intl-displaynames": "6.6.6", - "@formatjs/intl-listformat": "7.5.5", - "intl-messageformat": "10.5.11", + "@formatjs/icu-messageformat-parser": "2.7.8", + "@formatjs/intl-displaynames": "6.6.8", + "@formatjs/intl-listformat": "7.5.7", + "intl-messageformat": "10.5.14", "tslib": "^2.4.0" }, "peerDependencies": { @@ -955,21 +985,21 @@ } }, "node_modules/@formatjs/intl-displaynames": { - "version": "6.6.6", - "resolved": "https://registry.npmjs.org/@formatjs/intl-displaynames/-/intl-displaynames-6.6.6.tgz", - "integrity": "sha512-Dg5URSjx0uzF8VZXtHb6KYZ6LFEEhCbAbKoYChYHEOnMFTw/ZU3jIo/NrujzQD2EfKPgQzIq73LOUvW6Z/LpFA==", + "version": "6.6.8", + "resolved": "https://registry.npmjs.org/@formatjs/intl-displaynames/-/intl-displaynames-6.6.8.tgz", + "integrity": "sha512-Lgx6n5KxN16B3Pb05z3NLEBQkGoXnGjkTBNCZI+Cn17YjHJ3fhCeEJJUqRlIZmJdmaXQhjcQVDp6WIiNeRYT5g==", "dependencies": { - "@formatjs/ecma402-abstract": "1.18.2", + "@formatjs/ecma402-abstract": "2.0.0", "@formatjs/intl-localematcher": "0.5.4", "tslib": "^2.4.0" } }, "node_modules/@formatjs/intl-listformat": { - "version": "7.5.5", - "resolved": "https://registry.npmjs.org/@formatjs/intl-listformat/-/intl-listformat-7.5.5.tgz", - "integrity": "sha512-XoI52qrU6aBGJC9KJddqnacuBbPlb/bXFN+lIFVFhQ1RnFHpzuFrlFdjD9am2O7ZSYsyqzYRpkVcXeT1GHkwDQ==", + "version": "7.5.7", + "resolved": "https://registry.npmjs.org/@formatjs/intl-listformat/-/intl-listformat-7.5.7.tgz", + "integrity": "sha512-MG2TSChQJQT9f7Rlv+eXwUFiG24mKSzmF144PLb8m8OixyXqn4+YWU+5wZracZGCgVTVmx8viCf7IH3QXoiB2g==", "dependencies": { - "@formatjs/ecma402-abstract": "1.18.2", + "@formatjs/ecma402-abstract": "2.0.0", "@formatjs/intl-localematcher": "0.5.4", "tslib": "^2.4.0" } @@ -983,12 +1013,12 @@ } }, "node_modules/@formatjs/ts-transformer": { - "version": "3.13.12", - "resolved": "https://registry.npmjs.org/@formatjs/ts-transformer/-/ts-transformer-3.13.12.tgz", - "integrity": "sha512-uf1+DgbsCrzHAg7uIf0QlzpIkHYxRSRig5iJa9FaoUNIDZzNEE2oW/uLLLq7I9Z2FLIPhbmgq8hbW40FoQv+Fg==", + "version": "3.13.14", + "resolved": "https://registry.npmjs.org/@formatjs/ts-transformer/-/ts-transformer-3.13.14.tgz", + "integrity": "sha512-TP/R54lxQ9Drzzimxrrt6yBT/xBofTgYl5wSTpyKe3Aq9vIBVcFmS6EOqycj0X34KGu3EpDPGO0ng8ZQZGLIFg==", "dev": true, "dependencies": { - "@formatjs/icu-messageformat-parser": "2.7.6", + "@formatjs/icu-messageformat-parser": "2.7.8", "@types/json-stable-stringify": "^1.0.32", "@types/node": "14 || 16 || 17", "chalk": "^4.0.0", @@ -2215,17 +2245,17 @@ "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" }, "node_modules/@patternfly/patternfly": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/@patternfly/patternfly/-/patternfly-5.2.0.tgz", - "integrity": "sha512-phdsXcCRO+JICFXIKtORxSbOWoBr9zRCgtFTKTJ8hAIzm6wEUCdcHZrvsd+SXNR3q/4b/+KlmHUC4Q4KGUiuYw==" + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/@patternfly/patternfly/-/patternfly-5.3.1.tgz", + "integrity": "sha512-KYIr9pKRTzHZNGuDuaa5j5CaZyLltvotPFGG1BiJalBDBGSOyk0BZCgHLowm4txKZXrLhorEuuv9XLrMQL8eoA==" }, "node_modules/@patternfly/react-charts": { - "version": "7.2.2", - "resolved": "https://registry.npmjs.org/@patternfly/react-charts/-/react-charts-7.2.2.tgz", - "integrity": "sha512-1PFuvXz3mm/o/O+BQ2/2e66ncvtV8XIYxFaimurslCLTygodOvjBDDu/D/5tNa3HLxvA+fm2Q58893POGZi+bw==", + "version": "7.3.0", + "resolved": "https://registry.npmjs.org/@patternfly/react-charts/-/react-charts-7.3.0.tgz", + "integrity": "sha512-J6d/bFolI3zUOvJoK4lEveNeXZeJNfBq+iXgQ/mImESyW0H7MSebMcVB4d+NC6JX0QykuaOEn/7YMJMU9K73tw==", "dependencies": { - "@patternfly/react-styles": "^5.2.1", - "@patternfly/react-tokens": "^5.2.1", + "@patternfly/react-styles": "^5.3.0", + "@patternfly/react-tokens": "^5.3.0", "hoist-non-react-statics": "^3.3.0", "lodash": "^4.17.21", "tslib": "^2.5.0", @@ -2252,11 +2282,6 @@ "react-dom": "^17 || ^18" } }, - "node_modules/@patternfly/react-charts/node_modules/@patternfly/react-tokens": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/@patternfly/react-tokens/-/react-tokens-5.2.1.tgz", - "integrity": "sha512-8GYz/jnJTGAWUJt5eRAW5dtyiHPKETeFJBPGHaUQnvi/t1ZAkoy8i4Kd/RlHsDC7ktiu813SKCmlzwBwldAHKg==" - }, "node_modules/@patternfly/react-charts/node_modules/victory-core": { "version": "36.9.2", "resolved": "https://registry.npmjs.org/victory-core/-/victory-core-36.9.2.tgz", @@ -2287,13 +2312,13 @@ } }, "node_modules/@patternfly/react-core": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/@patternfly/react-core/-/react-core-5.2.0.tgz", - "integrity": "sha512-AUd7jccCgE2ZRwVtpEbJNF2Sq1A//ZhRaEQ/QHZiiq8mQRQM0Bkpnx0HdefToZT+TgUIjmPW4AXO3ooRJmt26w==", + "version": "5.3.3", + "resolved": "https://registry.npmjs.org/@patternfly/react-core/-/react-core-5.3.3.tgz", + "integrity": "sha512-qq3j0M+Vi+Xmd+a/MhRhGgjdRh9Hnm79iA+L935HwMIVDcIWRYp6Isib/Ha4+Jk+f3Qdl0RT3dBDvr/4m6OpVQ==", "dependencies": { - "@patternfly/react-icons": "^5.2.0", - "@patternfly/react-styles": "^5.2.0", - "@patternfly/react-tokens": "^5.2.0", + "@patternfly/react-icons": "^5.3.2", + "@patternfly/react-styles": "^5.3.1", + "@patternfly/react-tokens": "^5.3.1", "focus-trap": "7.5.2", "react-dropzone": "^14.2.3", "tslib": "^2.5.0" @@ -2304,28 +2329,28 @@ } }, "node_modules/@patternfly/react-icons": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/@patternfly/react-icons/-/react-icons-5.2.0.tgz", - "integrity": "sha512-vklAF2unvtK0trwx9Kk8nf4Xa2+nie4zxaIaQdnjIL7kX6a5SdsewDjlavOC3cRxnibZLQ5HQtpDZ4EmuXm8DQ==", + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/@patternfly/react-icons/-/react-icons-5.3.2.tgz", + "integrity": "sha512-GEygYbl0H4zD8nZuTQy2dayKIrV2bMMeWKSOEZ16Y3EYNgYVUOUnN+J0naAEuEGH39Xb1DE9n+XUbE1PC4CxPA==", "peerDependencies": { "react": "^17 || ^18", "react-dom": "^17 || ^18" } }, "node_modules/@patternfly/react-styles": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/@patternfly/react-styles/-/react-styles-5.2.1.tgz", - "integrity": "sha512-GT96hzI1QenBhq6Pfc51kxnj9aVLjL1zSLukKZXcYVe0HPOy0BFm90bT1Fo4e/z7V9cDYw4SqSX1XLc3O4jsTw==" + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/@patternfly/react-styles/-/react-styles-5.3.1.tgz", + "integrity": "sha512-H6uBoFH3bJjD6PP75qZ4k+2TtF59vxf9sIVerPpwrGJcRgBZbvbMZCniSC3+S2LQ8DgXLnDvieq78jJzHz0hiA==" }, "node_modules/@patternfly/react-table": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/@patternfly/react-table/-/react-table-5.2.0.tgz", - "integrity": "sha512-Pd+llSuAU9i1dvteQL1keEXmsQv6d8x4+F2arqGQS1umeOR3lvvycyFac1OboJ4oV2rAX97GVmtZdoJjaqxdhg==", + "version": "5.3.3", + "resolved": "https://registry.npmjs.org/@patternfly/react-table/-/react-table-5.3.3.tgz", + "integrity": "sha512-uaRmsJABvVPH8gYTh+EUcDz61knIxe9qor/VGUYDLONYBL5G3IaltwG42IsJ9jShxiwFmIPy+QARPpaadTpv5w==", "dependencies": { - "@patternfly/react-core": "^5.2.0", - "@patternfly/react-icons": "^5.2.0", - "@patternfly/react-styles": "^5.2.0", - "@patternfly/react-tokens": "^5.2.0", + "@patternfly/react-core": "^5.3.3", + "@patternfly/react-icons": "^5.3.2", + "@patternfly/react-styles": "^5.3.1", + "@patternfly/react-tokens": "^5.3.1", "lodash": "^4.17.19", "tslib": "^2.5.0" }, @@ -2335,9 +2360,9 @@ } }, "node_modules/@patternfly/react-tokens": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/@patternfly/react-tokens/-/react-tokens-5.2.0.tgz", - "integrity": "sha512-ZsrLpStHJQfvUJLIXT+cObJbA3jM4r9iWwULLva0s7DzznXJ6iIACQQfgwDtcSVyM95z5S1a/LHPj/wYgaqUIg==" + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/@patternfly/react-tokens/-/react-tokens-5.3.1.tgz", + "integrity": "sha512-VYK0uVP2/2RJ7ZshJCCLeq0Boih5I1bv+9Z/Bg6h12dCkLs85XsxAX9Ve+BGIo5DF54/mzcRHE1RKYap4ISXuw==" }, "node_modules/@pkgjs/parseargs": { "version": "0.11.0", @@ -2472,13 +2497,13 @@ } }, "node_modules/@redhat-cloud-services/frontend-components": { - "version": "4.2.6", - "resolved": "https://registry.npmjs.org/@redhat-cloud-services/frontend-components/-/frontend-components-4.2.6.tgz", - "integrity": "sha512-ErM9sWQUQpKwdKBOQlDBFI6IHyi3mRzTZ3wYJ57pouTzQzOhPozsIpPsPgB2gN/88khenjFEy+7SYuIZDaH5TA==", + "version": "4.2.10", + "resolved": "https://registry.npmjs.org/@redhat-cloud-services/frontend-components/-/frontend-components-4.2.10.tgz", + "integrity": "sha512-4pAmnoVRkFS4h21KNnGmOZn1co4m4y8/GcCFxbnEp8nh8OWSyD2r16DPS95wG9mjcSYmPn9OQ+Ooh+PE6+/wWQ==", "dependencies": { "@patternfly/react-component-groups": "^5.0.0", "@redhat-cloud-services/frontend-components-utilities": "^4.0.0", - "@redhat-cloud-services/types": "^0.0.24", + "@redhat-cloud-services/types": "^1.0.9", "@scalprum/core": "^0.7.0", "@scalprum/react-core": "^0.7.0", "classnames": "^2.2.5", @@ -2498,9 +2523,9 @@ } }, "node_modules/@redhat-cloud-services/frontend-components-config": { - "version": "6.0.12", - "resolved": "https://registry.npmjs.org/@redhat-cloud-services/frontend-components-config/-/frontend-components-config-6.0.12.tgz", - "integrity": "sha512-KVFHCMwnzqv23KA27sLRsEexL0rxmiY3BRH5zPli2WpywYbE6iNLTjJrHnE+xogaHIRtW2wx3CgOLd+JMvnlFQ==", + "version": "6.0.14", + "resolved": "https://registry.npmjs.org/@redhat-cloud-services/frontend-components-config/-/frontend-components-config-6.0.14.tgz", + "integrity": "sha512-VBa2lFClKgrUdJVY/SsqYPIHzao0tf/j4hln6K1wxl9DmYH1D7mXSJaypnytuBjvQBYC5pRiScuLrmYBwUDRcA==", "dev": true, "dependencies": { "@pmmmwh/react-refresh-webpack-plugin": "^0.5.8", @@ -2917,12 +2942,12 @@ "peer": true }, "node_modules/@redhat-cloud-services/frontend-components-utilities": { - "version": "4.0.10", - "resolved": "https://registry.npmjs.org/@redhat-cloud-services/frontend-components-utilities/-/frontend-components-utilities-4.0.10.tgz", - "integrity": "sha512-SAMXD9ciFk8aDXjt+9FnaY6VP+6RTuNswFn7a+TNROBIa0CNqb7O0x5y0gZs/Pc67xrbuxF9K5RG98qwLGdNOQ==", + "version": "4.0.11", + "resolved": "https://registry.npmjs.org/@redhat-cloud-services/frontend-components-utilities/-/frontend-components-utilities-4.0.11.tgz", + "integrity": "sha512-O4Az1B/27Cet/kHtwKtd1Pw9+zYp9XdnmYOUCypACTv9i4HJ+f6Ku7QT4VKO/9wWSGKmTu+Vq6+4ix3d5jdxrg==", "dependencies": { "@redhat-cloud-services/rbac-client": "^1.0.100", - "@redhat-cloud-services/types": "^0.0.24", + "@redhat-cloud-services/types": "^1.0.9", "@sentry/browser": "^5.30.0", "awesome-debounce-promise": "^2.1.0", "axios": "^0.28.1", @@ -2940,6 +2965,11 @@ "react-router-dom": "^5.0.0 || ^6.0.0" } }, + "node_modules/@redhat-cloud-services/frontend-components-utilities/node_modules/@redhat-cloud-services/types": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/@redhat-cloud-services/types/-/types-1.0.9.tgz", + "integrity": "sha512-dKYYSLU0cwNkOSq5kSvdKWzgwFGBk45uwAwoHGi44PMQdWkuz+tXhYLrKKAXoSXVahR6VFjBDONlaxok8Lzkcw==" + }, "node_modules/@redhat-cloud-services/frontend-components-utilities/node_modules/axios": { "version": "0.28.1", "resolved": "https://registry.npmjs.org/axios/-/axios-0.28.1.tgz", @@ -2950,10 +2980,15 @@ "proxy-from-env": "^1.1.0" } }, + "node_modules/@redhat-cloud-services/frontend-components/node_modules/@redhat-cloud-services/types": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/@redhat-cloud-services/types/-/types-1.0.9.tgz", + "integrity": "sha512-dKYYSLU0cwNkOSq5kSvdKWzgwFGBk45uwAwoHGi44PMQdWkuz+tXhYLrKKAXoSXVahR6VFjBDONlaxok8Lzkcw==" + }, "node_modules/@redhat-cloud-services/rbac-client": { - "version": "1.3.3", - "resolved": "https://registry.npmjs.org/@redhat-cloud-services/rbac-client/-/rbac-client-1.3.3.tgz", - "integrity": "sha512-tGKI10dEKbYBkZws9iPAzh5c0LpzNumqRVAQvE3tX+xqWgpwUs27r66QUst87Hv9/83O4ECQwy3hq2zopauyxA==", + "version": "1.4.4", + "resolved": "https://registry.npmjs.org/@redhat-cloud-services/rbac-client/-/rbac-client-1.4.4.tgz", + "integrity": "sha512-I5NE+Xllg8x1qxAorHK4s1CBairnLi4wq3kSIhMinlYrKWZRu/0j2JlDBTTWGmZfsVXAi1Tca0Z0N6u553iRTw==", "dependencies": { "axios": "^0.27.2", "tslib": "^2.6.2" @@ -2969,9 +3004,9 @@ } }, "node_modules/@redhat-cloud-services/tsc-transform-imports": { - "version": "1.0.9", - "resolved": "https://registry.npmjs.org/@redhat-cloud-services/tsc-transform-imports/-/tsc-transform-imports-1.0.9.tgz", - "integrity": "sha512-dodQMeAzeybaam5BlijrXuUA1Ycfy76MUGM+oVn5UUsO1Y2fkMfbuYMkYuOQznQ0N/NHJqCs9Q3nc77bo8KSlQ==", + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/@redhat-cloud-services/tsc-transform-imports/-/tsc-transform-imports-1.0.10.tgz", + "integrity": "sha512-IzZsgGrpE3XaGk7UBVryjUftL/Pd2FKsjf92MhzD6z7FnvtKiQsx7CnLBi6wcaAAT1VWi5HuWIIziS6wVmLGbQ==", "dev": true, "dependencies": { "glob": "10.3.3" @@ -3005,17 +3040,18 @@ "node_modules/@redhat-cloud-services/types": { "version": "0.0.24", "resolved": "https://registry.npmjs.org/@redhat-cloud-services/types/-/types-0.0.24.tgz", - "integrity": "sha512-P50stc+mnWLycID46/AKmD/760r5N1eoam//O6MUVriqVorUdht7xkUL78aJZU1vw8WW6xlrDHwz3F6BM148qg==" + "integrity": "sha512-P50stc+mnWLycID46/AKmD/760r5N1eoam//O6MUVriqVorUdht7xkUL78aJZU1vw8WW6xlrDHwz3F6BM148qg==", + "optional": true }, "node_modules/@reduxjs/toolkit": { - "version": "2.2.3", - "resolved": "https://registry.npmjs.org/@reduxjs/toolkit/-/toolkit-2.2.3.tgz", - "integrity": "sha512-76dll9EnJXg4EVcI5YNxZA/9hSAmZsFqzMmNRHvIlzw2WS/twfcVX3ysYrWGJMClwEmChQFC4yRq74tn6fdzRA==", + "version": "2.2.5", + "resolved": "https://registry.npmjs.org/@reduxjs/toolkit/-/toolkit-2.2.5.tgz", + "integrity": "sha512-aeFA/s5NCG7NoJe/MhmwREJxRkDs0ZaSqt0MxhWUrwCf1UQXpwR87RROJEql0uAkLI6U7snBOYOcKw83ew3FPg==", "dependencies": { "immer": "^10.0.3", "redux": "^5.0.1", "redux-thunk": "^3.1.0", - "reselect": "^5.0.1" + "reselect": "^5.1.0" }, "peerDependencies": { "react": "^16.9.0 || ^17.0.0 || ^18", @@ -3031,9 +3067,9 @@ } }, "node_modules/@remix-run/router": { - "version": "1.15.3", - "resolved": "https://registry.npmjs.org/@remix-run/router/-/router-1.15.3.tgz", - "integrity": "sha512-Oy8rmScVrVxWZVOpEF57ovlnhpZ8CCPlnIIumVcV9nFdiSIrus99+Lw78ekXyGvVDlIsFJbSfmSovJUhCWYV3w==", + "version": "1.16.1", + "resolved": "https://registry.npmjs.org/@remix-run/router/-/router-1.16.1.tgz", + "integrity": "sha512-es2g3dq6Nb07iFxGk5GuHN20RwBZOsuDQN7izWIisUcv9r+d2C5jQxqmgkdebXgReWfiyUabcki6Fg77mSNrig==", "engines": { "node": ">=14.0.0" } @@ -3198,14 +3234,14 @@ } }, "node_modules/@swc/core": { - "version": "1.4.14", - "resolved": "https://registry.npmjs.org/@swc/core/-/core-1.4.14.tgz", - "integrity": "sha512-tHXg6OxboUsqa/L7DpsCcFnxhLkqN/ht5pCwav1HnvfthbiNIJypr86rNx4cUnQDJepETviSqBTIjxa7pSpGDQ==", + "version": "1.5.7", + "resolved": "https://registry.npmjs.org/@swc/core/-/core-1.5.7.tgz", + "integrity": "sha512-U4qJRBefIJNJDRCCiVtkfa/hpiZ7w0R6kASea+/KLp+vkus3zcLSB8Ub8SvKgTIxjWpwsKcZlPf5nrv4ls46SQ==", "dev": true, "hasInstallScript": true, "dependencies": { "@swc/counter": "^0.1.2", - "@swc/types": "^0.1.5" + "@swc/types": "0.1.7" }, "engines": { "node": ">=10" @@ -3215,16 +3251,16 @@ "url": "https://opencollective.com/swc" }, "optionalDependencies": { - "@swc/core-darwin-arm64": "1.4.14", - "@swc/core-darwin-x64": "1.4.14", - "@swc/core-linux-arm-gnueabihf": "1.4.14", - "@swc/core-linux-arm64-gnu": "1.4.14", - "@swc/core-linux-arm64-musl": "1.4.14", - "@swc/core-linux-x64-gnu": "1.4.14", - "@swc/core-linux-x64-musl": "1.4.14", - "@swc/core-win32-arm64-msvc": "1.4.14", - "@swc/core-win32-ia32-msvc": "1.4.14", - "@swc/core-win32-x64-msvc": "1.4.14" + "@swc/core-darwin-arm64": "1.5.7", + "@swc/core-darwin-x64": "1.5.7", + "@swc/core-linux-arm-gnueabihf": "1.5.7", + "@swc/core-linux-arm64-gnu": "1.5.7", + "@swc/core-linux-arm64-musl": "1.5.7", + "@swc/core-linux-x64-gnu": "1.5.7", + "@swc/core-linux-x64-musl": "1.5.7", + "@swc/core-win32-arm64-msvc": "1.5.7", + "@swc/core-win32-ia32-msvc": "1.5.7", + "@swc/core-win32-x64-msvc": "1.5.7" }, "peerDependencies": { "@swc/helpers": "^0.5.0" @@ -3236,9 +3272,9 @@ } }, "node_modules/@swc/core-darwin-arm64": { - "version": "1.4.14", - "resolved": "https://registry.npmjs.org/@swc/core-darwin-arm64/-/core-darwin-arm64-1.4.14.tgz", - "integrity": "sha512-8iPfLhYNspBl836YYsfv6ErXwDUqJ7IMieddV3Ey/t/97JAEAdNDUdtTKDtbyP0j/Ebyqyn+fKcqwSq7rAof0g==", + "version": "1.5.7", + "resolved": "https://registry.npmjs.org/@swc/core-darwin-arm64/-/core-darwin-arm64-1.5.7.tgz", + "integrity": "sha512-bZLVHPTpH3h6yhwVl395k0Mtx8v6CGhq5r4KQdAoPbADU974Mauz1b6ViHAJ74O0IVE5vyy7tD3OpkQxL/vMDQ==", "cpu": [ "arm64" ], @@ -3252,9 +3288,9 @@ } }, "node_modules/@swc/core-darwin-x64": { - "version": "1.4.14", - "resolved": "https://registry.npmjs.org/@swc/core-darwin-x64/-/core-darwin-x64-1.4.14.tgz", - "integrity": "sha512-9CqSj8uRZ92cnlgAlVaWMaJJBdxtNvCzJxaGj5KuIseeG6Q0l1g+qk8JcU7h9dAsH9saHTNwNFBVGKQo0W0ujg==", + "version": "1.5.7", + "resolved": "https://registry.npmjs.org/@swc/core-darwin-x64/-/core-darwin-x64-1.5.7.tgz", + "integrity": "sha512-RpUyu2GsviwTc2qVajPL0l8nf2vKj5wzO3WkLSHAHEJbiUZk83NJrZd1RVbEknIMO7+Uyjh54hEh8R26jSByaw==", "cpu": [ "x64" ], @@ -3268,9 +3304,9 @@ } }, "node_modules/@swc/core-linux-arm-gnueabihf": { - "version": "1.4.14", - "resolved": "https://registry.npmjs.org/@swc/core-linux-arm-gnueabihf/-/core-linux-arm-gnueabihf-1.4.14.tgz", - "integrity": "sha512-mfd5JArPITTzMjcezH4DwMw+BdjBV1y25Khp8itEIpdih9ei+fvxOOrDYTN08b466NuE2dF2XuhKtRLA7fXArQ==", + "version": "1.5.7", + "resolved": "https://registry.npmjs.org/@swc/core-linux-arm-gnueabihf/-/core-linux-arm-gnueabihf-1.5.7.tgz", + "integrity": "sha512-cTZWTnCXLABOuvWiv6nQQM0hP6ZWEkzdgDvztgHI/+u/MvtzJBN5lBQ2lue/9sSFYLMqzqff5EHKlFtrJCA9dQ==", "cpu": [ "arm" ], @@ -3284,9 +3320,9 @@ } }, "node_modules/@swc/core-linux-arm64-gnu": { - "version": "1.4.14", - "resolved": "https://registry.npmjs.org/@swc/core-linux-arm64-gnu/-/core-linux-arm64-gnu-1.4.14.tgz", - "integrity": "sha512-3Lqlhlmy8MVRS9xTShMaPAp0oyUt0KFhDs4ixJsjdxKecE0NJSV/MInuDmrkij1C8/RQ2wySRlV9np5jK86oWw==", + "version": "1.5.7", + "resolved": "https://registry.npmjs.org/@swc/core-linux-arm64-gnu/-/core-linux-arm64-gnu-1.5.7.tgz", + "integrity": "sha512-hoeTJFBiE/IJP30Be7djWF8Q5KVgkbDtjySmvYLg9P94bHg9TJPSQoC72tXx/oXOgXvElDe/GMybru0UxhKx4g==", "cpu": [ "arm64" ], @@ -3300,9 +3336,9 @@ } }, "node_modules/@swc/core-linux-arm64-musl": { - "version": "1.4.14", - "resolved": "https://registry.npmjs.org/@swc/core-linux-arm64-musl/-/core-linux-arm64-musl-1.4.14.tgz", - "integrity": "sha512-n0YoCa64TUcJrbcXIHIHDWQjdUPdaXeMHNEu7yyBtOpm01oMGTKP3frsUXIABLBmAVWtKvqit4/W1KVKn5gJzg==", + "version": "1.5.7", + "resolved": "https://registry.npmjs.org/@swc/core-linux-arm64-musl/-/core-linux-arm64-musl-1.5.7.tgz", + "integrity": "sha512-+NDhK+IFTiVK1/o7EXdCeF2hEzCiaRSrb9zD7X2Z7inwWlxAntcSuzZW7Y6BRqGQH89KA91qYgwbnjgTQ22PiQ==", "cpu": [ "arm64" ], @@ -3316,9 +3352,9 @@ } }, "node_modules/@swc/core-linux-x64-gnu": { - "version": "1.4.14", - "resolved": "https://registry.npmjs.org/@swc/core-linux-x64-gnu/-/core-linux-x64-gnu-1.4.14.tgz", - "integrity": "sha512-CGmlwLWbfG1dB4jZBJnp2IWlK5xBMNLjN7AR5kKA3sEpionoccEnChOEvfux1UdVJQjLRKuHNV9yGyqGBTpxfQ==", + "version": "1.5.7", + "resolved": "https://registry.npmjs.org/@swc/core-linux-x64-gnu/-/core-linux-x64-gnu-1.5.7.tgz", + "integrity": "sha512-25GXpJmeFxKB+7pbY7YQLhWWjkYlR+kHz5I3j9WRl3Lp4v4UD67OGXwPe+DIcHqcouA1fhLhsgHJWtsaNOMBNg==", "cpu": [ "x64" ], @@ -3332,9 +3368,9 @@ } }, "node_modules/@swc/core-linux-x64-musl": { - "version": "1.4.14", - "resolved": "https://registry.npmjs.org/@swc/core-linux-x64-musl/-/core-linux-x64-musl-1.4.14.tgz", - "integrity": "sha512-xq4npk8YKYmNwmr8fbvF2KP3kUVdZYfXZMQnW425gP3/sn+yFQO8Nd0bGH40vOVQn41kEesSe0Z5O/JDor2TgQ==", + "version": "1.5.7", + "resolved": "https://registry.npmjs.org/@swc/core-linux-x64-musl/-/core-linux-x64-musl-1.5.7.tgz", + "integrity": "sha512-0VN9Y5EAPBESmSPPsCJzplZHV26akC0sIgd3Hc/7S/1GkSMoeuVL+V9vt+F/cCuzr4VidzSkqftdP3qEIsXSpg==", "cpu": [ "x64" ], @@ -3348,9 +3384,9 @@ } }, "node_modules/@swc/core-win32-arm64-msvc": { - "version": "1.4.14", - "resolved": "https://registry.npmjs.org/@swc/core-win32-arm64-msvc/-/core-win32-arm64-msvc-1.4.14.tgz", - "integrity": "sha512-imq0X+gU9uUe6FqzOQot5gpKoaC00aCUiN58NOzwp0QXEupn8CDuZpdBN93HiZswfLruu5jA1tsc15x6v9p0Yg==", + "version": "1.5.7", + "resolved": "https://registry.npmjs.org/@swc/core-win32-arm64-msvc/-/core-win32-arm64-msvc-1.5.7.tgz", + "integrity": "sha512-RtoNnstBwy5VloNCvmvYNApkTmuCe4sNcoYWpmY7C1+bPR+6SOo8im1G6/FpNem8AR5fcZCmXHWQ+EUmRWJyuA==", "cpu": [ "arm64" ], @@ -3364,9 +3400,9 @@ } }, "node_modules/@swc/core-win32-ia32-msvc": { - "version": "1.4.14", - "resolved": "https://registry.npmjs.org/@swc/core-win32-ia32-msvc/-/core-win32-ia32-msvc-1.4.14.tgz", - "integrity": "sha512-cH6QpXMw5D3t+lpx6SkErHrxN0yFzmQ0lgNAJxoDRiaAdDbqA6Col8UqUJwUS++Ul6aCWgNhCdiEYehPaoyDPA==", + "version": "1.5.7", + "resolved": "https://registry.npmjs.org/@swc/core-win32-ia32-msvc/-/core-win32-ia32-msvc-1.5.7.tgz", + "integrity": "sha512-Xm0TfvcmmspvQg1s4+USL3x8D+YPAfX2JHygvxAnCJ0EHun8cm2zvfNBcsTlnwYb0ybFWXXY129aq1wgFC9TpQ==", "cpu": [ "ia32" ], @@ -3380,9 +3416,9 @@ } }, "node_modules/@swc/core-win32-x64-msvc": { - "version": "1.4.14", - "resolved": "https://registry.npmjs.org/@swc/core-win32-x64-msvc/-/core-win32-x64-msvc-1.4.14.tgz", - "integrity": "sha512-FmZ4Tby4wW65K/36BKzmuu7mlq7cW5XOxzvufaSNVvQ5PN4OodAlqPjToe029oma4Av+ykJiif64scMttyNAzg==", + "version": "1.5.7", + "resolved": "https://registry.npmjs.org/@swc/core-win32-x64-msvc/-/core-win32-x64-msvc-1.5.7.tgz", + "integrity": "sha512-tp43WfJLCsKLQKBmjmY/0vv1slVywR5Q4qKjF5OIY8QijaEW7/8VwPyUyVoJZEnDgv9jKtUTG5PzqtIYPZGnyg==", "cpu": [ "x64" ], @@ -3419,9 +3455,9 @@ } }, "node_modules/@swc/types": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/@swc/types/-/types-0.1.6.tgz", - "integrity": "sha512-/JLo/l2JsT/LRd80C3HfbmVpxOAJ11FO2RCEslFrgzLltoP9j8XIbsyDcfCt2WWyX+CM96rBoNM+IToAkFOugg==", + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/@swc/types/-/types-0.1.7.tgz", + "integrity": "sha512-scHWahbHF0eyj3JsxG9CFJgFdFNaVQCNAimBlT6PzS3n/HptxqREjsm4OH6AN3lYcffZYSPxXW8ua2BEHp0lJQ==", "dev": true, "dependencies": { "@swc/counter": "^0.1.3" @@ -3524,9 +3560,9 @@ } }, "node_modules/@testing-library/jest-dom": { - "version": "6.4.2", - "resolved": "https://registry.npmjs.org/@testing-library/jest-dom/-/jest-dom-6.4.2.tgz", - "integrity": "sha512-CzqH0AFymEMG48CpzXFriYYkOjk6ZGPCLMhW9e9jg3KMCn5OfJecF8GtGW7yGfR/IgCe3SX8BSwjdzI6BBbZLw==", + "version": "6.4.5", + "resolved": "https://registry.npmjs.org/@testing-library/jest-dom/-/jest-dom-6.4.5.tgz", + "integrity": "sha512-AguB9yvTXmCnySBP1lWjfNNUwpbElsaQ567lt2VdGqAdHtpieLgjmcVyv1q7PMIvLbgpDdkWV5Ydv3FEejyp2A==", "dev": true, "dependencies": { "@adobe/css-tools": "^4.3.2", @@ -3535,7 +3571,7 @@ "chalk": "^3.0.0", "css.escape": "^1.5.1", "dom-accessibility-api": "^0.6.3", - "lodash": "^4.17.15", + "lodash": "^4.17.21", "redent": "^3.0.0" }, "engines": { @@ -3642,9 +3678,9 @@ } }, "node_modules/@testing-library/react": { - "version": "15.0.2", - "resolved": "https://registry.npmjs.org/@testing-library/react/-/react-15.0.2.tgz", - "integrity": "sha512-5mzIpuytB1ctpyywvyaY2TAAUQVCZIGqwiqFQf6u9lvj/SJQepGUzNV18Xpk+NLCaCE2j7CWrZE0tEf9xLZYiQ==", + "version": "15.0.7", + "resolved": "https://registry.npmjs.org/@testing-library/react/-/react-15.0.7.tgz", + "integrity": "sha512-cg0RvEdD1TIhhkm1IeYMQxrzy0MtUNfa3minv4MjbgcYzJAZ7yD0i0lwoPOTPr+INtiXFezt2o8xMSnyHhEn2Q==", "dev": true, "dependencies": { "@babel/runtime": "^7.12.5", @@ -3655,8 +3691,14 @@ "node": ">=18" }, "peerDependencies": { + "@types/react": "^18.0.0", "react": "^18.0.0", "react-dom": "^18.0.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } } }, "node_modules/@testing-library/react/node_modules/@testing-library/dom": { @@ -4197,18 +4239,18 @@ "dev": true }, "node_modules/@types/react": { - "version": "18.2.79", - "resolved": "https://registry.npmjs.org/@types/react/-/react-18.2.79.tgz", - "integrity": "sha512-RwGAGXPl9kSXwdNTafkOEuFrTBD5SA2B3iEB96xi8+xu5ddUa/cpvyVCSNn+asgLCTHkb5ZxN8gbuibYJi4s1w==", + "version": "18.3.3", + "resolved": "https://registry.npmjs.org/@types/react/-/react-18.3.3.tgz", + "integrity": "sha512-hti/R0pS0q1/xx+TsI73XIqk26eBsISZ2R0wUijXIngRK9R/e7Xw/cXVxQK7R5JjW+SV4zGcn5hXjudkN/pLIw==", "dependencies": { "@types/prop-types": "*", "csstype": "^3.0.2" } }, "node_modules/@types/react-dom": { - "version": "18.2.25", - "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-18.2.25.tgz", - "integrity": "sha512-o/V48vf4MQh7juIKZU2QGDfli6p1+OOi5oXx36Hffpc9adsHeXjVp8rHuPkjd8VT8sOJ2Zp05HR7CdpGTIUFUA==", + "version": "18.3.0", + "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-18.3.0.tgz", + "integrity": "sha512-EhwApuTmMBmXuFOikhQLIBUn6uFg81SwLMOAUgodJF14SOBOCMdU04gDoYi0WOJJHD144TL32z4yDqCW3dnkQg==", "dev": true, "dependencies": { "@types/react": "*" @@ -4434,21 +4476,19 @@ } }, "node_modules/@typescript-eslint/eslint-plugin": { - "version": "7.7.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-7.7.0.tgz", - "integrity": "sha512-GJWR0YnfrKnsRoluVO3PRb9r5aMZriiMMM/RHj5nnTrBy1/wIgk76XCtCKcnXGjpZQJQRFtGV9/0JJ6n30uwpQ==", + "version": "7.11.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-7.11.0.tgz", + "integrity": "sha512-P+qEahbgeHW4JQ/87FuItjBj8O3MYv5gELDzr8QaQ7fsll1gSMTYb6j87MYyxwf3DtD7uGFB9ShwgmCJB5KmaQ==", "dev": true, "dependencies": { "@eslint-community/regexpp": "^4.10.0", - "@typescript-eslint/scope-manager": "7.7.0", - "@typescript-eslint/type-utils": "7.7.0", - "@typescript-eslint/utils": "7.7.0", - "@typescript-eslint/visitor-keys": "7.7.0", - "debug": "^4.3.4", + "@typescript-eslint/scope-manager": "7.11.0", + "@typescript-eslint/type-utils": "7.11.0", + "@typescript-eslint/utils": "7.11.0", + "@typescript-eslint/visitor-keys": "7.11.0", "graphemer": "^1.4.0", "ignore": "^5.3.1", "natural-compare": "^1.4.0", - "semver": "^7.6.0", "ts-api-utils": "^1.3.0" }, "engines": { @@ -4468,49 +4508,16 @@ } } }, - "node_modules/@typescript-eslint/eslint-plugin/node_modules/lru-cache": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", - "dev": true, - "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/@typescript-eslint/eslint-plugin/node_modules/semver": { - "version": "7.6.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.0.tgz", - "integrity": "sha512-EnwXhrlwXMk9gKu5/flx5sv/an57AkRplG3hTK68W7FRDN+k+OWBj65M7719OkA82XLBxrcX0KSHj+X5COhOVg==", - "dev": true, - "dependencies": { - "lru-cache": "^6.0.0" - }, - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/@typescript-eslint/eslint-plugin/node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true - }, "node_modules/@typescript-eslint/parser": { - "version": "7.7.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-7.7.0.tgz", - "integrity": "sha512-fNcDm3wSwVM8QYL4HKVBggdIPAy9Q41vcvC/GtDobw3c4ndVT3K6cqudUmjHPw8EAp4ufax0o58/xvWaP2FmTg==", + "version": "7.11.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-7.11.0.tgz", + "integrity": "sha512-yimw99teuaXVWsBcPO1Ais02kwJ1jmNA1KxE7ng0aT7ndr1pT1wqj0OJnsYVGKKlc4QJai86l/025L6z8CljOg==", "dev": true, "dependencies": { - "@typescript-eslint/scope-manager": "7.7.0", - "@typescript-eslint/types": "7.7.0", - "@typescript-eslint/typescript-estree": "7.7.0", - "@typescript-eslint/visitor-keys": "7.7.0", + "@typescript-eslint/scope-manager": "7.11.0", + "@typescript-eslint/types": "7.11.0", + "@typescript-eslint/typescript-estree": "7.11.0", + "@typescript-eslint/visitor-keys": "7.11.0", "debug": "^4.3.4" }, "engines": { @@ -4530,13 +4537,13 @@ } }, "node_modules/@typescript-eslint/scope-manager": { - "version": "7.7.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-7.7.0.tgz", - "integrity": "sha512-/8INDn0YLInbe9Wt7dK4cXLDYp0fNHP5xKLHvZl3mOT5X17rK/YShXaiNmorl+/U4VKCVIjJnx4Ri5b0y+HClw==", + "version": "7.11.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-7.11.0.tgz", + "integrity": "sha512-27tGdVEiutD4POirLZX4YzT180vevUURJl4wJGmm6TrQoiYwuxTIY98PBp6L2oN+JQxzE0URvYlzJaBHIekXAw==", "dev": true, "dependencies": { - "@typescript-eslint/types": "7.7.0", - "@typescript-eslint/visitor-keys": "7.7.0" + "@typescript-eslint/types": "7.11.0", + "@typescript-eslint/visitor-keys": "7.11.0" }, "engines": { "node": "^18.18.0 || >=20.0.0" @@ -4547,13 +4554,13 @@ } }, "node_modules/@typescript-eslint/type-utils": { - "version": "7.7.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-7.7.0.tgz", - "integrity": "sha512-bOp3ejoRYrhAlnT/bozNQi3nio9tIgv3U5C0mVDdZC7cpcQEDZXvq8inrHYghLVwuNABRqrMW5tzAv88Vy77Sg==", + "version": "7.11.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-7.11.0.tgz", + "integrity": "sha512-WmppUEgYy+y1NTseNMJ6mCFxt03/7jTOy08bcg7bxJJdsM4nuhnchyBbE8vryveaJUf62noH7LodPSo5Z0WUCg==", "dev": true, "dependencies": { - "@typescript-eslint/typescript-estree": "7.7.0", - "@typescript-eslint/utils": "7.7.0", + "@typescript-eslint/typescript-estree": "7.11.0", + "@typescript-eslint/utils": "7.11.0", "debug": "^4.3.4", "ts-api-utils": "^1.3.0" }, @@ -4574,9 +4581,9 @@ } }, "node_modules/@typescript-eslint/types": { - "version": "7.7.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-7.7.0.tgz", - "integrity": "sha512-G01YPZ1Bd2hn+KPpIbrAhEWOn5lQBrjxkzHkWvP6NucMXFtfXoevK82hzQdpfuQYuhkvFDeQYbzXCjR1z9Z03w==", + "version": "7.11.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-7.11.0.tgz", + "integrity": "sha512-MPEsDRZTyCiXkD4vd3zywDCifi7tatc4K37KqTprCvaXptP7Xlpdw0NR2hRJTetG5TxbWDB79Ys4kLmHliEo/w==", "dev": true, "engines": { "node": "^18.18.0 || >=20.0.0" @@ -4587,13 +4594,13 @@ } }, "node_modules/@typescript-eslint/typescript-estree": { - "version": "7.7.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-7.7.0.tgz", - "integrity": "sha512-8p71HQPE6CbxIBy2kWHqM1KGrC07pk6RJn40n0DSc6bMOBBREZxSDJ+BmRzc8B5OdaMh1ty3mkuWRg4sCFiDQQ==", + "version": "7.11.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-7.11.0.tgz", + "integrity": "sha512-cxkhZ2C/iyi3/6U9EPc5y+a6csqHItndvN/CzbNXTNrsC3/ASoYQZEt9uMaEp+xFNjasqQyszp5TumAVKKvJeQ==", "dev": true, "dependencies": { - "@typescript-eslint/types": "7.7.0", - "@typescript-eslint/visitor-keys": "7.7.0", + "@typescript-eslint/types": "7.11.0", + "@typescript-eslint/visitor-keys": "7.11.0", "debug": "^4.3.4", "globby": "^11.1.0", "is-glob": "^4.0.3", @@ -4614,18 +4621,6 @@ } } }, - "node_modules/@typescript-eslint/typescript-estree/node_modules/lru-cache": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", - "dev": true, - "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=10" - } - }, "node_modules/@typescript-eslint/typescript-estree/node_modules/minimatch": { "version": "9.0.4", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.4.tgz", @@ -4642,13 +4637,10 @@ } }, "node_modules/@typescript-eslint/typescript-estree/node_modules/semver": { - "version": "7.6.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.0.tgz", - "integrity": "sha512-EnwXhrlwXMk9gKu5/flx5sv/an57AkRplG3hTK68W7FRDN+k+OWBj65M7719OkA82XLBxrcX0KSHj+X5COhOVg==", + "version": "7.6.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.2.tgz", + "integrity": "sha512-FNAIBWCx9qcRhoHcgcJ0gvU7SN1lYU2ZXuSfl04bSC5OpvDHFyJCjdNHomPXxjQlCBU67YW64PzY7/VIEH7F2w==", "dev": true, - "dependencies": { - "lru-cache": "^6.0.0" - }, "bin": { "semver": "bin/semver.js" }, @@ -4656,25 +4648,16 @@ "node": ">=10" } }, - "node_modules/@typescript-eslint/typescript-estree/node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true - }, "node_modules/@typescript-eslint/utils": { - "version": "7.7.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-7.7.0.tgz", - "integrity": "sha512-LKGAXMPQs8U/zMRFXDZOzmMKgFv3COlxUQ+2NMPhbqgVm6R1w+nU1i4836Pmxu9jZAuIeyySNrN/6Rc657ggig==", + "version": "7.11.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-7.11.0.tgz", + "integrity": "sha512-xlAWwPleNRHwF37AhrZurOxA1wyXowW4PqVXZVUNCLjB48CqdPJoJWkrpH2nij9Q3Lb7rtWindtoXwxjxlKKCA==", "dev": true, "dependencies": { "@eslint-community/eslint-utils": "^4.4.0", - "@types/json-schema": "^7.0.15", - "@types/semver": "^7.5.8", - "@typescript-eslint/scope-manager": "7.7.0", - "@typescript-eslint/types": "7.7.0", - "@typescript-eslint/typescript-estree": "7.7.0", - "semver": "^7.6.0" + "@typescript-eslint/scope-manager": "7.11.0", + "@typescript-eslint/types": "7.11.0", + "@typescript-eslint/typescript-estree": "7.11.0" }, "engines": { "node": "^18.18.0 || >=20.0.0" @@ -4687,46 +4670,13 @@ "eslint": "^8.56.0" } }, - "node_modules/@typescript-eslint/utils/node_modules/lru-cache": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", - "dev": true, - "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/@typescript-eslint/utils/node_modules/semver": { - "version": "7.6.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.0.tgz", - "integrity": "sha512-EnwXhrlwXMk9gKu5/flx5sv/an57AkRplG3hTK68W7FRDN+k+OWBj65M7719OkA82XLBxrcX0KSHj+X5COhOVg==", - "dev": true, - "dependencies": { - "lru-cache": "^6.0.0" - }, - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/@typescript-eslint/utils/node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true - }, "node_modules/@typescript-eslint/visitor-keys": { - "version": "7.7.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-7.7.0.tgz", - "integrity": "sha512-h0WHOj8MhdhY8YWkzIF30R379y0NqyOHExI9N9KCzvmu05EgG4FumeYa3ccfKUSphyWkWQE1ybVrgz/Pbam6YA==", + "version": "7.11.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-7.11.0.tgz", + "integrity": "sha512-7syYk4MzjxTEk0g/w3iqtgxnFQspDJfn6QKD36xMuuhTzjcxY7F8EmBLnALjVyaOF1/bVocu3bS/2/F7rXrveQ==", "dev": true, "dependencies": { - "@typescript-eslint/types": "7.7.0", + "@typescript-eslint/types": "7.11.0", "eslint-visitor-keys": "^3.4.3" }, "engines": { @@ -4756,14 +4706,14 @@ "dev": true }, "node_modules/@unleash/proxy-client-react": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/@unleash/proxy-client-react/-/proxy-client-react-4.2.2.tgz", - "integrity": "sha512-KRg1dAQfxLSBe8O2i6GIGDM+7HUdUu/ntREy+JeYbmJ2b6ApFtLX/wt+3T/CjrTYjwRlZKZYJDx5E4fRDOQqpQ==", + "version": "4.2.4", + "resolved": "https://registry.npmjs.org/@unleash/proxy-client-react/-/proxy-client-react-4.2.4.tgz", + "integrity": "sha512-FWzKDqE28ZmogdXgL9caqMJTWnrVEMJWly8Ofbo1xNZHsk7R9jcWgozIXCWEPto/qijfyCBoat5xjsduT09l1g==", "engines": { "node": ">=16.0.0" }, "peerDependencies": { - "unleash-proxy-client": "^3.2.0" + "unleash-proxy-client": "^3.4.0" } }, "node_modules/@webassemblyjs/ast": { @@ -5277,15 +5227,16 @@ "dev": true }, "node_modules/array-includes": { - "version": "3.1.7", - "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.7.tgz", - "integrity": "sha512-dlcsNBIiWhPkHdOEEKnehA+RNUWDc4UqFtnIXU4uuYDPtA4LDkr7qip2p0VvFAEXNDr0yWZ9PJyIRiGjRLQzwQ==", + "version": "3.1.8", + "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.8.tgz", + "integrity": "sha512-itaWrbYbqpGXkGhZPGUulwnhVf5Hpy1xiCFsGqyIGglbBxmG5vSjxQen3/WGOjPpNEv1RtBLKxbmVXm8HpJStQ==", "dev": true, "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "es-abstract": "^1.22.1", - "get-intrinsic": "^1.2.1", + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.2", + "es-object-atoms": "^1.0.0", + "get-intrinsic": "^1.2.4", "is-string": "^1.0.7" }, "engines": { @@ -5333,15 +5284,16 @@ } }, "node_modules/array.prototype.findlast": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/array.prototype.findlast/-/array.prototype.findlast-1.2.4.tgz", - "integrity": "sha512-BMtLxpV+8BD+6ZPFIWmnUBpQoy+A+ujcg4rhp2iwCRJYA7PEh2MS4NL3lz8EiDlLrJPp2hg9qWihr5pd//jcGw==", + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/array.prototype.findlast/-/array.prototype.findlast-1.2.5.tgz", + "integrity": "sha512-CVvd6FHg1Z3POpBLxO6E6zr+rSKEQ9L6rZHAaY7lLfhKsWYUBBOuMs0e9o24oopj6H+geRCX0YJ+TJLBK2eHyQ==", "dev": true, "dependencies": { - "call-bind": "^1.0.5", + "call-bind": "^1.0.7", "define-properties": "^1.2.1", - "es-abstract": "^1.22.3", + "es-abstract": "^1.23.2", "es-errors": "^1.3.0", + "es-object-atoms": "^1.0.0", "es-shim-unscopables": "^1.0.2" }, "engines": { @@ -5616,9 +5568,9 @@ } }, "node_modules/axios": { - "version": "1.6.8", - "resolved": "https://registry.npmjs.org/axios/-/axios-1.6.8.tgz", - "integrity": "sha512-v/ZHtJDU39mDpyBoFVkETcd/uNdxrWRrg3bKpOKzXFA6Bvqopts6ALSMU3y6ijYxbw2B+wPrIv46egTzJXCLGQ==", + "version": "1.7.2", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.7.2.tgz", + "integrity": "sha512-2A8QhOMrbomlDuiLeK9XibIBzuHeRcqqNOHp0Cyp5EoJ1IFDh+XZH3A6BkXtv0K4gFGCI0Y4BM7B1wOEi0Rmgw==", "dependencies": { "follow-redirects": "^1.15.6", "form-data": "^4.0.0", @@ -6136,6 +6088,7 @@ "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-3.3.0.tgz", "integrity": "sha512-zhaCDicdLuWN5UbN5IMnFqNMhNfo919sH85y2/ea+5Yg9TsTkeZxpL+JLbp6cgYFS4sRLp3YV4S6yDuqVWHYOw==", "dev": true, + "peer": true, "engines": { "node": ">=6" }, @@ -8498,9 +8451,9 @@ } }, "node_modules/es-abstract": { - "version": "1.23.2", - "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.23.2.tgz", - "integrity": "sha512-60s3Xv2T2p1ICykc7c+DNDPLDMm9t4QxCOUU0K9JxiLjM3C1zB9YVdN7tjxrFd4+AkZ8CdX1ovUga4P2+1e+/w==", + "version": "1.23.3", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.23.3.tgz", + "integrity": "sha512-e+HfNH61Bj1X9/jLc5v1owaLYuHdeHHSQlkhCBiTK8rBvKaULl/beGMxwrMXjpYrv4pz22BlY570vVePA2ho4A==", "dev": true, "dependencies": { "array-buffer-byte-length": "^1.0.1", @@ -8542,11 +8495,11 @@ "safe-regex-test": "^1.0.3", "string.prototype.trim": "^1.2.9", "string.prototype.trimend": "^1.0.8", - "string.prototype.trimstart": "^1.0.7", + "string.prototype.trimstart": "^1.0.8", "typed-array-buffer": "^1.0.2", "typed-array-byte-length": "^1.0.1", "typed-array-byte-offset": "^1.0.2", - "typed-array-length": "^1.0.5", + "typed-array-length": "^1.0.6", "unbox-primitive": "^1.0.2", "which-typed-array": "^1.1.15" }, @@ -8603,14 +8556,14 @@ } }, "node_modules/es-iterator-helpers": { - "version": "1.0.18", - "resolved": "https://registry.npmjs.org/es-iterator-helpers/-/es-iterator-helpers-1.0.18.tgz", - "integrity": "sha512-scxAJaewsahbqTYrGKJihhViaM6DDZDDoucfvzNbK0pOren1g/daDQ3IAhzn+1G14rBG7w+i5N+qul60++zlKA==", + "version": "1.0.19", + "resolved": "https://registry.npmjs.org/es-iterator-helpers/-/es-iterator-helpers-1.0.19.tgz", + "integrity": "sha512-zoMwbCcH5hwUkKJkT8kDIBZSz9I6mVG//+lDCinLCGov4+r7NIy0ld8o03M0cJxl2spVf6ESYVS6/gpIfq1FFw==", "dev": true, "dependencies": { "call-bind": "^1.0.7", "define-properties": "^1.2.1", - "es-abstract": "^1.23.0", + "es-abstract": "^1.23.3", "es-errors": "^1.3.0", "es-set-tostringtag": "^2.0.3", "function-bind": "^1.1.2", @@ -9025,13 +8978,13 @@ } }, "node_modules/eslint-plugin-formatjs": { - "version": "4.13.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-formatjs/-/eslint-plugin-formatjs-4.13.0.tgz", - "integrity": "sha512-sxgHQNyVclNRO7aydGwxohwxYR03/oRDW0uUXFWayNMPTlnb9sET3LCovBjvQF7qAHDGFDcLwg4ECSyui4nG8A==", + "version": "4.13.3", + "resolved": "https://registry.npmjs.org/eslint-plugin-formatjs/-/eslint-plugin-formatjs-4.13.3.tgz", + "integrity": "sha512-4j3IVwaLEXblnvH2/ZIOZwc9zaaZf2+zyn/b8oLJRt6kMCTu2rIs4UsIxy5nBRYZzsBSh7k34JJ5/ngGtJ3kYw==", "dev": true, "dependencies": { - "@formatjs/icu-messageformat-parser": "2.7.6", - "@formatjs/ts-transformer": "3.13.12", + "@formatjs/icu-messageformat-parser": "2.7.8", + "@formatjs/ts-transformer": "3.13.14", "@types/eslint": "7 || 8", "@types/picomatch": "^2.3.0", "@typescript-eslint/utils": "^6.18.1", @@ -9291,9 +9244,9 @@ } }, "node_modules/eslint-plugin-jest-dom": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-jest-dom/-/eslint-plugin-jest-dom-5.2.0.tgz", - "integrity": "sha512-ctnCP0MsLmUvbCyhnOQ+/1OmsZj+e7V6kFunazIx5728Yq7TQnuKI8HOsgPTStB+9iYEpiEa+VfKB09Lq7/3fA==", + "version": "5.4.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-jest-dom/-/eslint-plugin-jest-dom-5.4.0.tgz", + "integrity": "sha512-yBqvFsnpS5Sybjoq61cJiUsenRkC9K32hYQBFS9doBR7nbQZZ5FyO+X7MlmfM1C48Ejx/qTuOCgukDUNyzKZ7A==", "dev": true, "dependencies": { "@babel/runtime": "^7.16.3", @@ -9305,8 +9258,8 @@ "yarn": ">=1" }, "peerDependencies": { - "@testing-library/dom": "^8.0.0 || ^9.0.0", - "eslint": "^6.8.0 || ^7.0.0 || ^8.0.0" + "@testing-library/dom": "^8.0.0 || ^9.0.0 || ^10.0.0", + "eslint": "^6.8.0 || ^7.0.0 || ^8.0.0 || ^9.0.0" }, "peerDependenciesMeta": { "@testing-library/dom": { @@ -9460,19 +9413,18 @@ "dev": true }, "node_modules/eslint-plugin-jsdoc": { - "version": "48.2.3", - "resolved": "https://registry.npmjs.org/eslint-plugin-jsdoc/-/eslint-plugin-jsdoc-48.2.3.tgz", - "integrity": "sha512-r9DMAmFs66VNvNqRLLjHejdnJtILrt3xGi+Qx0op0oRfFGVpOR1Hb3BC++MacseHx93d8SKYPhyrC9BS7Os2QA==", + "version": "48.2.7", + "resolved": "https://registry.npmjs.org/eslint-plugin-jsdoc/-/eslint-plugin-jsdoc-48.2.7.tgz", + "integrity": "sha512-fYj3roTnkFL9OFFTB129rico8lerC5G8Vp2ZW9SjO9RNWG0exVvI+i/Y8Bpm1ufjR0uvT38xtoab/U0Hp8Ybog==", "dev": true, "dependencies": { - "@es-joy/jsdoccomment": "~0.42.0", + "@es-joy/jsdoccomment": "~0.43.1", "are-docs-informative": "^0.0.2", "comment-parser": "1.4.1", "debug": "^4.3.4", "escape-string-regexp": "^4.0.0", "esquery": "^1.5.0", - "is-builtin-module": "^3.2.1", - "semver": "^7.6.0", + "semver": "^7.6.2", "spdx-expression-parse": "^4.0.0" }, "engines": { @@ -9494,26 +9446,11 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/eslint-plugin-jsdoc/node_modules/lru-cache": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", - "dev": true, - "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=10" - } - }, "node_modules/eslint-plugin-jsdoc/node_modules/semver": { - "version": "7.6.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.0.tgz", - "integrity": "sha512-EnwXhrlwXMk9gKu5/flx5sv/an57AkRplG3hTK68W7FRDN+k+OWBj65M7719OkA82XLBxrcX0KSHj+X5COhOVg==", + "version": "7.6.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.2.tgz", + "integrity": "sha512-FNAIBWCx9qcRhoHcgcJ0gvU7SN1lYU2ZXuSfl04bSC5OpvDHFyJCjdNHomPXxjQlCBU67YW64PzY7/VIEH7F2w==", "dev": true, - "dependencies": { - "lru-cache": "^6.0.0" - }, "bin": { "semver": "bin/semver.js" }, @@ -9521,12 +9458,6 @@ "node": ">=10" } }, - "node_modules/eslint-plugin-jsdoc/node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true - }, "node_modules/eslint-plugin-jsx-a11y": { "version": "6.8.0", "resolved": "https://registry.npmjs.org/eslint-plugin-jsx-a11y/-/eslint-plugin-jsx-a11y-6.8.0.tgz", @@ -9595,9 +9526,9 @@ } }, "node_modules/eslint-plugin-markdown": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/eslint-plugin-markdown/-/eslint-plugin-markdown-4.0.1.tgz", - "integrity": "sha512-5/MnGvYU0i8MbHH5cg8S+Vl3DL+bqRNYshk1xUO86DilNBaxtTkhH+5FD0/yO03AmlI6+lfNFdk2yOw72EPzpA==", + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-markdown/-/eslint-plugin-markdown-5.0.0.tgz", + "integrity": "sha512-kY2u9yDhzvfZ0kmRTsvgm3mTnvZgTSGIIPeHg3yesSx4R5CTCnITUjCPhzCD1MUhNcqHU5Tr6lzx+02EclVPbw==", "dev": true, "dependencies": { "mdast-util-from-markdown": "^0.8.5" @@ -9770,9 +9701,9 @@ } }, "node_modules/eslint-plugin-patternfly-react": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/eslint-plugin-patternfly-react/-/eslint-plugin-patternfly-react-5.2.1.tgz", - "integrity": "sha512-eddeSWQcW9BKALW8Ft+7QA8xs3Hbf5YbW09CeOaD5Zdoc3K0PGwfinQkLAeShYQ4Q00266ZUV6jMGhG0pjzmvA==", + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-patternfly-react/-/eslint-plugin-patternfly-react-5.3.0.tgz", + "integrity": "sha512-6i/13l7NLUcjTvtgvZ5GUF6b/jwcjKK97MkvsLU5sw66Vh2Bk/R+eC5AjMF9fz9g2saRB/wBt1PiZMlYo+QX6Q==", "dev": true, "dependencies": { "@babel/eslint-parser": "^7.19.1", @@ -9851,29 +9782,29 @@ } }, "node_modules/eslint-plugin-react": { - "version": "7.34.1", - "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.34.1.tgz", - "integrity": "sha512-N97CxlouPT1AHt8Jn0mhhN2RrADlUAsk1/atcT2KyA/l9Q/E6ll7OIGwNumFmWfZ9skV3XXccYS19h80rHtgkw==", + "version": "7.34.2", + "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.34.2.tgz", + "integrity": "sha512-2HCmrU+/JNigDN6tg55cRDKCQWicYAPB38JGSFDQt95jDm8rrvSUo7YPkOIm5l6ts1j1zCvysNcasvfTMQzUOw==", "dev": true, "dependencies": { - "array-includes": "^3.1.7", - "array.prototype.findlast": "^1.2.4", + "array-includes": "^3.1.8", + "array.prototype.findlast": "^1.2.5", "array.prototype.flatmap": "^1.3.2", "array.prototype.toreversed": "^1.1.2", "array.prototype.tosorted": "^1.1.3", "doctrine": "^2.1.0", - "es-iterator-helpers": "^1.0.17", + "es-iterator-helpers": "^1.0.19", "estraverse": "^5.3.0", "jsx-ast-utils": "^2.4.1 || ^3.0.0", "minimatch": "^3.1.2", - "object.entries": "^1.1.7", - "object.fromentries": "^2.0.7", - "object.hasown": "^1.1.3", - "object.values": "^1.1.7", + "object.entries": "^1.1.8", + "object.fromentries": "^2.0.8", + "object.hasown": "^1.1.4", + "object.values": "^1.2.0", "prop-types": "^15.8.1", "resolve": "^2.0.0-next.5", "semver": "^6.3.1", - "string.prototype.matchall": "^4.0.10" + "string.prototype.matchall": "^4.0.11" }, "engines": { "node": ">=4" @@ -12451,13 +12382,13 @@ } }, "node_modules/intl-messageformat": { - "version": "10.5.11", - "resolved": "https://registry.npmjs.org/intl-messageformat/-/intl-messageformat-10.5.11.tgz", - "integrity": "sha512-eYq5fkFBVxc7GIFDzpFQkDOZgNayNTQn4Oufe8jw6YY6OHVw70/4pA3FyCsQ0Gb2DnvEJEMmN2tOaXUGByM+kg==", + "version": "10.5.14", + "resolved": "https://registry.npmjs.org/intl-messageformat/-/intl-messageformat-10.5.14.tgz", + "integrity": "sha512-IjC6sI0X7YRjjyVH9aUgdftcmZK7WXdHeil4KwbjDnRWjnVitKpAx3rr6t6di1joFp5188VqKcobOPA6mCLG/w==", "dependencies": { - "@formatjs/ecma402-abstract": "1.18.2", + "@formatjs/ecma402-abstract": "2.0.0", "@formatjs/fast-memoize": "2.2.0", - "@formatjs/icu-messageformat-parser": "2.7.6", + "@formatjs/icu-messageformat-parser": "2.7.8", "tslib": "^2.4.0" } }, @@ -12592,6 +12523,7 @@ "resolved": "https://registry.npmjs.org/is-builtin-module/-/is-builtin-module-3.2.1.tgz", "integrity": "sha512-BSLE3HnV2syZ0FK0iMA/yUGplUeMmNz4AW5fnTunbCIqZi4vG3WjJT9FHMy5D69xmAYBHXQhJdALdpwVxV501A==", "dev": true, + "peer": true, "dependencies": { "builtin-modules": "^3.3.0" }, @@ -16916,28 +16848,29 @@ } }, "node_modules/object.entries": { - "version": "1.1.7", - "resolved": "https://registry.npmjs.org/object.entries/-/object.entries-1.1.7.tgz", - "integrity": "sha512-jCBs/0plmPsOnrKAfFQXRG2NFjlhZgjjcBLSmTnEhU8U6vVTsVe8ANeQJCHTl3gSsI4J+0emOoCgoKlmQPMgmA==", + "version": "1.1.8", + "resolved": "https://registry.npmjs.org/object.entries/-/object.entries-1.1.8.tgz", + "integrity": "sha512-cmopxi8VwRIAw/fkijJohSfpef5PdN0pMQJN6VC/ZKvn0LIknWD8KtgY6KlQdEc4tIjcQ3HxSMmnvtzIscdaYQ==", "dev": true, "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "es-abstract": "^1.22.1" + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-object-atoms": "^1.0.0" }, "engines": { "node": ">= 0.4" } }, "node_modules/object.fromentries": { - "version": "2.0.7", - "resolved": "https://registry.npmjs.org/object.fromentries/-/object.fromentries-2.0.7.tgz", - "integrity": "sha512-UPbPHML6sL8PI/mOqPwsH4G6iyXcCGzLin8KvEPenOZN5lpCNBZZQ+V62vdjB1mQHrmqGQt5/OJzemUA+KJmEA==", + "version": "2.0.8", + "resolved": "https://registry.npmjs.org/object.fromentries/-/object.fromentries-2.0.8.tgz", + "integrity": "sha512-k6E21FzySsSK5a21KRADBd/NGneRegFO5pLHfdQLpRDETUNJueLXs3WCzyQ3tFRDYgbq3KHGXfTbi2bs8WQ6rQ==", "dev": true, "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "es-abstract": "^1.22.1" + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.2", + "es-object-atoms": "^1.0.0" }, "engines": { "node": ">= 0.4" @@ -16960,27 +16893,31 @@ } }, "node_modules/object.hasown": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/object.hasown/-/object.hasown-1.1.3.tgz", - "integrity": "sha512-fFI4VcYpRHvSLXxP7yiZOMAd331cPfd2p7PFDVbgUsYOfCT3tICVqXWngbjr4m49OvsBwUBQ6O2uQoJvy3RexA==", + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/object.hasown/-/object.hasown-1.1.4.tgz", + "integrity": "sha512-FZ9LZt9/RHzGySlBARE3VF+gE26TxR38SdmqOqliuTnl9wrKulaQs+4dee1V+Io8VfxqzAfHu6YuRgUy8OHoTg==", "dev": true, "dependencies": { - "define-properties": "^1.2.0", - "es-abstract": "^1.22.1" + "define-properties": "^1.2.1", + "es-abstract": "^1.23.2", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" }, "funding": { "url": "https://github.com/sponsors/ljharb" } }, "node_modules/object.values": { - "version": "1.1.7", - "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.1.7.tgz", - "integrity": "sha512-aU6xnDFYT3x17e/f0IiiwlGPTy2jzMySGfUB4fq6z7CV8l85CWHDk5ErhyhpfDHhrOMwGFhSQkhMGHaIotA6Ng==", + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.2.0.tgz", + "integrity": "sha512-yBYjY9QX2hnRmZHAjG/f13MzmBzxzYgQhFrke06TTyKY5zSTEqkOeukBzIdVA3j3ulu8Qa3MbVFShV7T2RmGtQ==", "dev": true, "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "es-abstract": "^1.22.1" + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-object-atoms": "^1.0.0" }, "engines": { "node": ">= 0.4" @@ -18061,9 +17998,9 @@ } }, "node_modules/react": { - "version": "18.2.0", - "resolved": "https://registry.npmjs.org/react/-/react-18.2.0.tgz", - "integrity": "sha512-/3IjMdb2L9QbBdWiW5e3P2/npwMBaU9mHCSCUzNln0ZCYbcfTsGbTJrU/kGemdH2IWmB2ioZ+zkxtmq6g09fGQ==", + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/react/-/react-18.3.1.tgz", + "integrity": "sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==", "dependencies": { "loose-envify": "^1.1.0" }, @@ -18088,15 +18025,15 @@ "integrity": "sha512-I+vcaK9t4+kypiSgaiVWAipqHRXYmZIuAiS8vzFvXHHXVigg/sMKwlRgLy6LH2i3rmP+0Vzfl5lFsFRwF1r3pg==" }, "node_modules/react-dom": { - "version": "18.2.0", - "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.2.0.tgz", - "integrity": "sha512-6IMTriUmvsjHUjNtEDudZfuDQUoWXVxKHhlEGSk81n4YFS+r/Kl99wXiwlVXtPBtJenozv2P+hxDsw9eA7Xo6g==", + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.3.1.tgz", + "integrity": "sha512-5m4nQKp+rZRb09LNH59GM4BxTh9251/ylbKIbpe7TpGxfJ+9kv6BLkLBXIjjspbgbnIBNqlI23tRnTWT0snUIw==", "dependencies": { "loose-envify": "^1.1.0", - "scheduler": "^0.23.0" + "scheduler": "^0.23.2" }, "peerDependencies": { - "react": "^18.2.0" + "react": "^18.3.1" } }, "node_modules/react-dropzone": { @@ -18121,19 +18058,19 @@ "integrity": "sha512-nsO+KSNgo1SbJqJEYRE9ERzo7YtYbou/OqjSQKxV7jcKox7+usiUVZOAC+XnDOABXggQTno0Y1CpVnuWEc1boQ==" }, "node_modules/react-intl": { - "version": "6.6.5", - "resolved": "https://registry.npmjs.org/react-intl/-/react-intl-6.6.5.tgz", - "integrity": "sha512-OErDPbGqus0QKVj77MGCC9Plbnys3CDQrq6Lw41c60pmeTdn41AhoS1SIzXG6SUlyF7qNN2AVqfrrIvHUgSyLQ==", - "dependencies": { - "@formatjs/ecma402-abstract": "1.18.2", - "@formatjs/icu-messageformat-parser": "2.7.6", - "@formatjs/intl": "2.10.1", - "@formatjs/intl-displaynames": "6.6.6", - "@formatjs/intl-listformat": "7.5.5", + "version": "6.6.8", + "resolved": "https://registry.npmjs.org/react-intl/-/react-intl-6.6.8.tgz", + "integrity": "sha512-M0pkhzcgV31h++2901BiRXWl69hp2zPyLxRrSwRjd1ErXbNoubz/f4M6DrRTd4OiSUrT4ajRQzrmtS5plG4FtA==", + "dependencies": { + "@formatjs/ecma402-abstract": "2.0.0", + "@formatjs/icu-messageformat-parser": "2.7.8", + "@formatjs/intl": "2.10.4", + "@formatjs/intl-displaynames": "6.6.8", + "@formatjs/intl-listformat": "7.5.7", "@types/hoist-non-react-statics": "^3.3.1", "@types/react": "16 || 17 || 18", "hoist-non-react-statics": "^3.3.2", - "intl-messageformat": "10.5.11", + "intl-messageformat": "10.5.14", "tslib": "^2.4.0" }, "peerDependencies": { @@ -18173,9 +18110,9 @@ } }, "node_modules/react-redux": { - "version": "9.1.1", - "resolved": "https://registry.npmjs.org/react-redux/-/react-redux-9.1.1.tgz", - "integrity": "sha512-5ynfGDzxxsoV73+4czQM56qF43vsmgJsO22rmAvU5tZT2z5Xow/A2uhhxwXuGTxgdReF3zcp7A80gma2onRs1A==", + "version": "9.1.2", + "resolved": "https://registry.npmjs.org/react-redux/-/react-redux-9.1.2.tgz", + "integrity": "sha512-0OA4dhM1W48l3uzmv6B7TXPCGmokUU4p1M44DGN2/D9a1FjVPukVjER1PcPX97jIg6aUeLq1XJo1IpfbgULn0w==", "dependencies": { "@types/use-sync-external-store": "^0.0.3", "use-sync-external-store": "^1.0.0" @@ -18183,16 +18120,12 @@ "peerDependencies": { "@types/react": "^18.2.25", "react": "^18.0", - "react-native": ">=0.69", "redux": "^5.0.0" }, "peerDependenciesMeta": { "@types/react": { "optional": true }, - "react-native": { - "optional": true - }, "redux": { "optional": true } @@ -18208,11 +18141,11 @@ } }, "node_modules/react-router": { - "version": "6.22.3", - "resolved": "https://registry.npmjs.org/react-router/-/react-router-6.22.3.tgz", - "integrity": "sha512-dr2eb3Mj5zK2YISHK++foM9w4eBnO23eKnZEDs7c880P6oKbrjz/Svg9+nxqtHQK+oMW4OtjZca0RqPglXxguQ==", + "version": "6.23.1", + "resolved": "https://registry.npmjs.org/react-router/-/react-router-6.23.1.tgz", + "integrity": "sha512-fzcOaRF69uvqbbM7OhvQyBTFDVrrGlsFdS3AL+1KfIBtGETibHzi3FkoTRyiDJnWNc2VxrfvR+657ROHjaNjqQ==", "dependencies": { - "@remix-run/router": "1.15.3" + "@remix-run/router": "1.16.1" }, "engines": { "node": ">=14.0.0" @@ -18222,12 +18155,12 @@ } }, "node_modules/react-router-dom": { - "version": "6.22.3", - "resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-6.22.3.tgz", - "integrity": "sha512-7ZILI7HjcE+p31oQvwbokjk6OA/bnFxrhJ19n82Ex9Ph8fNAq+Hm/7KchpMGlTgWhUxRHMMCut+vEtNpWpowKw==", + "version": "6.23.1", + "resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-6.23.1.tgz", + "integrity": "sha512-utP+K+aSTtEdbWpC+4gxhdlPFwuEfDKq8ZrPFU65bbRJY+l706qjR7yaidBpo3MSeA/fzwbXWbKBI6ftOnP3OQ==", "dependencies": { - "@remix-run/router": "1.15.3", - "react-router": "6.22.3" + "@remix-run/router": "1.16.1", + "react-router": "6.23.1" }, "engines": { "node": ">=14.0.0" @@ -18576,9 +18509,9 @@ "peer": true }, "node_modules/rimraf": { - "version": "5.0.5", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-5.0.5.tgz", - "integrity": "sha512-CqDakW+hMe/Bz202FPEymy68P+G50RfMQK+Qo5YUqc9SPipvbGjCGKd0RSKEelbsfQuw3g5NZDSrlZZAJurH1A==", + "version": "5.0.7", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-5.0.7.tgz", + "integrity": "sha512-nV6YcJo5wbLW77m+8KjH8aB/7/rxQy9SZ0HY5shnwULfS+9nmTtVXAJET5NdZmCzA4fPI/Hm1wo/Po/4mopOdg==", "dev": true, "dependencies": { "glob": "^10.3.7" @@ -18587,7 +18520,7 @@ "rimraf": "dist/esm/bin.mjs" }, "engines": { - "node": ">=14" + "node": ">=14.18" }, "funding": { "url": "https://github.com/sponsors/isaacs" @@ -18863,9 +18796,9 @@ } }, "node_modules/scheduler": { - "version": "0.23.0", - "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.0.tgz", - "integrity": "sha512-CtuThmgHNg7zIZWAXi3AsyIzA3n4xx7aNyjwC2VJldO2LMVDhFK+63xGqq6CsJH4rTAt6/M+N4GhZiDYPx9eUw==", + "version": "0.23.2", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.2.tgz", + "integrity": "sha512-UOShsPwz7NrMUqhR6t0hWjFduvOzbtv7toDH1/hIrfRNIDBnnBWd0CwJTGvTpngVlmwGCdP9/Zl/tVrDqcuYzQ==", "dependencies": { "loose-envify": "^1.1.0" } @@ -19574,20 +19507,26 @@ "devOptional": true }, "node_modules/string.prototype.matchall": { - "version": "4.0.10", - "resolved": "https://registry.npmjs.org/string.prototype.matchall/-/string.prototype.matchall-4.0.10.tgz", - "integrity": "sha512-rGXbGmOEosIQi6Qva94HUjgPs9vKW+dkG7Y8Q5O2OYkWL6wFaTRZO8zM4mhP94uX55wgyrXzfS2aGtGzUL7EJQ==", + "version": "4.0.11", + "resolved": "https://registry.npmjs.org/string.prototype.matchall/-/string.prototype.matchall-4.0.11.tgz", + "integrity": "sha512-NUdh0aDavY2og7IbBPenWqR9exH+E26Sv8e0/eTe1tltDGZL+GtBkDAnnyBtmekfK6/Dq3MkcGtzXFEd1LQrtg==", "dev": true, "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "es-abstract": "^1.22.1", - "get-intrinsic": "^1.2.1", + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.2", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.0.0", + "get-intrinsic": "^1.2.4", + "gopd": "^1.0.1", "has-symbols": "^1.0.3", - "internal-slot": "^1.0.5", - "regexp.prototype.flags": "^1.5.0", - "set-function-name": "^2.0.0", - "side-channel": "^1.0.4" + "internal-slot": "^1.0.7", + "regexp.prototype.flags": "^1.5.2", + "set-function-name": "^2.0.2", + "side-channel": "^1.0.6" + }, + "engines": { + "node": ">= 0.4" }, "funding": { "url": "https://github.com/sponsors/ljharb" @@ -19643,14 +19582,17 @@ } }, "node_modules/string.prototype.trimstart": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.7.tgz", - "integrity": "sha512-NGhtDFu3jCEm7B4Fy0DpLewdJQOZcQ0rGbwQ/+stjnrp2i+rlKeCvos9hOIeCmqwratM47OBxY7uFZzjxHXmrg==", + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.8.tgz", + "integrity": "sha512-UXSH262CSZY1tfu3G3Secr6uGLCFVPMhIqHjlgCUtCCcgihYc/xKs9djMTMUOb2j1mVSeU8EU6NWc/iQKU6Gfg==", "dev": true, "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "es-abstract": "^1.22.1" + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" }, "funding": { "url": "https://github.com/sponsors/ljharb" @@ -20013,7 +19955,8 @@ "node_modules/tiny-emitter": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/tiny-emitter/-/tiny-emitter-2.1.0.tgz", - "integrity": "sha512-NB6Dk1A9xgQPMoGqC5CVXn123gWyte215ONT5Pp5a0yt4nlEoO1ZWeCwpncaekPHXO60i47ihFnZPiRPjRMq4Q==" + "integrity": "sha512-NB6Dk1A9xgQPMoGqC5CVXn123gWyte215ONT5Pp5a0yt4nlEoO1ZWeCwpncaekPHXO60i47ihFnZPiRPjRMq4Q==", + "peer": true }, "node_modules/tiny-warning": { "version": "1.0.3", @@ -20148,9 +20091,9 @@ } }, "node_modules/ts-jest": { - "version": "29.1.2", - "resolved": "https://registry.npmjs.org/ts-jest/-/ts-jest-29.1.2.tgz", - "integrity": "sha512-br6GJoH/WUX4pu7FbZXuWGKGNDuU7b8Uj77g/Sp7puZV6EXzuByl6JrECvm0MzVzSTkSHWTihsXt+5XYER5b+g==", + "version": "29.1.4", + "resolved": "https://registry.npmjs.org/ts-jest/-/ts-jest-29.1.4.tgz", + "integrity": "sha512-YiHwDhSvCiItoAgsKtoLFCuakDzDsJ1DLDnSouTaTmdOcOwIkSzbLXduaQ6M5DRVhuZC/NYaaZ/mtHbWMv/S6Q==", "dev": true, "dependencies": { "bs-logger": "0.x", @@ -20166,10 +20109,11 @@ "ts-jest": "cli.js" }, "engines": { - "node": "^16.10.0 || ^18.0.0 || >=20.0.0" + "node": "^14.15.0 || ^16.10.0 || ^18.0.0 || >=20.0.0" }, "peerDependencies": { "@babel/core": ">=7.0.0-beta.0 <8", + "@jest/transform": "^29.0.0", "@jest/types": "^29.0.0", "babel-jest": "^29.0.0", "jest": "^29.0.0", @@ -20179,6 +20123,9 @@ "@babel/core": { "optional": true }, + "@jest/transform": { + "optional": true + }, "@jest/types": { "optional": true }, @@ -20646,9 +20593,9 @@ } }, "node_modules/typed-array-length": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/typed-array-length/-/typed-array-length-1.0.5.tgz", - "integrity": "sha512-yMi0PlwuznKHxKmcpoOdeLwxBoVPkqZxd7q2FgMkmD3bNwvF5VW0+UlUQ1k1vmktTu4Yu13Q0RIxEP8+B+wloA==", + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/typed-array-length/-/typed-array-length-1.0.6.tgz", + "integrity": "sha512-/OxDN6OtAk5KBpGb28T+HZc2M+ADtvRxXrKKbUwtsLgdoxgX13hyy7ek6bFRl5+aBs2yZzB0c4CnQfAtVypW/g==", "dev": true, "dependencies": { "call-bind": "^1.0.7", @@ -20763,9 +20710,10 @@ } }, "node_modules/unleash-proxy-client": { - "version": "3.3.2", - "resolved": "https://registry.npmjs.org/unleash-proxy-client/-/unleash-proxy-client-3.3.2.tgz", - "integrity": "sha512-ccv+85nMJAhaaE3q4BJd4Sl894kCEbYr7CwMglvuFrBhdoOGAM5s61NXksk/aA7AGXLeAzNGH5zwY5dn0H9i9A==", + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/unleash-proxy-client/-/unleash-proxy-client-3.4.0.tgz", + "integrity": "sha512-ivCzm//z+S2T3gSBSZY7HN+5GfoLXZIovMyH6lIZRe2/vCicEdXtXD6cnLTQ2LAiXGV7DpoSM1m8WZGoiLRzkw==", + "peer": true, "dependencies": { "tiny-emitter": "^2.1.0", "uuid": "^9.0.1" @@ -20779,6 +20727,7 @@ "https://github.com/sponsors/broofa", "https://github.com/sponsors/ctavan" ], + "peer": true, "bin": { "uuid": "dist/bin/uuid" } diff --git a/package.json b/package.json index 0c0bc932e..f76f4345d 100644 --- a/package.json +++ b/package.json @@ -50,66 +50,65 @@ "verify": "npm-run-all build lint test" }, "dependencies": { - "@patternfly/patternfly": "5.2.0", - "@patternfly/react-charts": "7.2.2", - "@patternfly/react-component-groups": "5.1.0", - "@patternfly/react-core": "5.2.0", - "@patternfly/react-icons": "5.2.0", - "@patternfly/react-table": "5.2.0", - "@patternfly/react-tokens": "5.2.0", - "@redhat-cloud-services/frontend-components": "^4.2.6", + "@patternfly/patternfly": "5.3.1", + "@patternfly/react-charts": "7.3.0", + "@patternfly/react-component-groups": "^5.1.0", + "@patternfly/react-core": "5.3.3", + "@patternfly/react-icons": "5.3.2", + "@patternfly/react-table": "5.3.3", + "@patternfly/react-tokens": "5.3.1", + "@redhat-cloud-services/frontend-components": "^4.2.10", "@redhat-cloud-services/frontend-components-notifications": "^4.1.0", "@redhat-cloud-services/frontend-components-translations": "^3.2.7", - "@redhat-cloud-services/frontend-components-utilities": "^4.0.10", - "@redhat-cloud-services/rbac-client": "^1.3.3", - "@reduxjs/toolkit": "^2.2.3", - "@unleash/proxy-client-react": "^4.2.2", - "axios": "^1.6.8", + "@redhat-cloud-services/frontend-components-utilities": "^4.0.11", + "@redhat-cloud-services/rbac-client": "^1.4.4", + "@reduxjs/toolkit": "^2.2.5", + "@unleash/proxy-client-react": "^4.2.4", + "axios": "^1.7.2", "date-fns": "^3.6.0", "js-file-download": "^0.4.12", "lodash": "^4.17.21", "qs": "^6.12.1", - "react": "^18.2.0", - "react-dom": "^18.2.0", - "react-intl": "^6.6.5", - "react-redux": "^9.1.1", - "react-router-dom": "^6.22.3", + "react": "^18.3.1", + "react-dom": "^18.3.1", + "react-intl": "^6.6.8", + "react-redux": "^9.1.2", + "react-router-dom": "^6.23.1", "redux": "^5.0.1", "redux-thunk": "^3.1.0", "typesafe-actions": "^5.1.0", - "unleash-proxy-client": "^3.3.2", "victory-core": "^37.0.2" }, "devDependencies": { - "@formatjs/cli": "^6.2.9", - "@formatjs/ecma402-abstract": "^1.18.2", - "@formatjs/icu-messageformat-parser": "^2.7.6", + "@formatjs/cli": "^6.2.12", + "@formatjs/ecma402-abstract": "^2.0.0", + "@formatjs/icu-messageformat-parser": "^2.7.8", "@redhat-cloud-services/eslint-config-redhat-cloud-services": "^2.0.4", - "@redhat-cloud-services/frontend-components-config": "^6.0.12", - "@redhat-cloud-services/tsc-transform-imports": "^1.0.9", - "@swc/core": "^1.4.14", + "@redhat-cloud-services/frontend-components-config": "^6.0.14", + "@redhat-cloud-services/tsc-transform-imports": "^1.0.10", + "@swc/core": "^1.5.7", "@swc/jest": "^0.2.36", - "@testing-library/jest-dom": "^6.4.2", - "@testing-library/react": "^15.0.2", + "@testing-library/jest-dom": "^6.4.5", + "@testing-library/react": "^15.0.7", "@testing-library/user-event": "^14.5.2", "@types/jest": "^29.5.12", "@types/qs": "^6.9.15", - "@types/react": "^18.2.79", - "@types/react-dom": "^18.2.25", + "@types/react": "^18.3.3", + "@types/react-dom": "^18.3.0", "@types/react-redux": "^7.1.33", "@types/react-router-dom": "^5.3.3", - "@typescript-eslint/eslint-plugin": "^7.7.0", - "@typescript-eslint/parser": "^7.7.0", + "@typescript-eslint/eslint-plugin": "^7.11.0", + "@typescript-eslint/parser": "^7.11.0", "aphrodite": "^2.4.0", "copy-webpack-plugin": "^12.0.2", "eslint": "^8.57.0", - "eslint-plugin-formatjs": "^4.13.0", - "eslint-plugin-jest-dom": "^5.2.0", - "eslint-plugin-jsdoc": "^48.2.3", - "eslint-plugin-markdown": "^4.0.1", - "eslint-plugin-patternfly-react": "^5.2.1", + "eslint-plugin-formatjs": "^4.13.3", + "eslint-plugin-jest-dom": "^5.4.0", + "eslint-plugin-jsdoc": "^48.2.7", + "eslint-plugin-markdown": "^5.0.0", + "eslint-plugin-patternfly-react": "^5.3.0", "eslint-plugin-prettier": "^5.1.3", - "eslint-plugin-react": "^7.34.1", + "eslint-plugin-react": "^7.34.2", "eslint-plugin-simple-import-sort": "^12.1.0", "eslint-plugin-sort-keys-fix": "^1.1.2", "eslint-plugin-testing-library": "^6.2.2", @@ -122,9 +121,9 @@ "jws": "^4.0.0", "npm-run-all": "^4.1.5", "prettier": "^3.2.5", - "rimraf": "^5.0.5", + "rimraf": "^5.0.7", "swc_mut_cjs_exports": "^0.90.24", - "ts-jest": "^29.1.2", + "ts-jest": "^29.1.4", "ts-patch": "^3.1.2", "typescript": "^5.4.5", "webpack-bundle-analyzer": "^4.10.2" diff --git a/src/api/api.ts b/src/api/api.ts index 003275c2e..703217d77 100644 --- a/src/api/api.ts +++ b/src/api/api.ts @@ -23,11 +23,11 @@ export interface PagedResponse { // axios.interceptors.request.use(authInterceptor); // } -export function authInterceptor(reqConfig: AxiosRequestConfig) { +function authInterceptor(reqConfig: AxiosRequestConfig) { return { ...reqConfig, headers: { - ...reqConfig.headers, + ...(reqConfig?.headers && reqConfig.headers), } as any, }; } diff --git a/src/api/apiDev.ts b/src/api/apiDev.ts new file mode 100644 index 000000000..92e11fe06 --- /dev/null +++ b/src/api/apiDev.ts @@ -0,0 +1,37 @@ +import type { AxiosInstance, AxiosRequestConfig } from 'axios'; +import axios from 'axios'; + +// For use with API development +// +// See https://www.postman.com/devteamkappa/workspace/rh-hccm/example/9135942-f404beb0-47df-4fe1-8ee5-2265ddcabed7 + +function devAuthInterceptor(reqConfig: AxiosRequestConfig) { + const insights = (window as any).insights; + const userToken = insights?.chrome?.auth?.getToken(); + + // For axios mock + if (!userToken?.then) { + return undefined; + } + return userToken.then(token => { + if (!token) { + return reqConfig; + } + return { + ...reqConfig, + headers: { + Accept: 'application/json', // Allow to be overridden + Authorization: `Bearer ${token}`, + ...(reqConfig?.headers && reqConfig.headers), + } as any, + }; + }); +} + +const axiosInstance: AxiosInstance = axios.create({ + baseURL: 'https://de907f1b-995c-4a3b-9c28-6bba63e190b7.mock.pstmn.io/api/cost-management/v1/', +}); + +axiosInstance.interceptors.request.use(devAuthInterceptor); + +export default axiosInstance; diff --git a/src/api/costModels.ts b/src/api/costModels.ts index 3687b4951..bfe3d15cf 100644 --- a/src/api/costModels.ts +++ b/src/api/costModels.ts @@ -15,7 +15,9 @@ export interface CostModel { description: string; distribution_info?: { distribution_type?: string; + network_cost?: boolean; platform_cost?: boolean; + storage_cost?: boolean; worker_cost?: boolean; }; markup: { value: string; unit: string }; @@ -32,7 +34,9 @@ export interface CostModelRequest { description: string; distribution_info?: { distribution_type?: string; + network_cost?: boolean; platform_cost?: boolean; + storage_cost?: boolean; worker_cost?: boolean; }; markup: { value: string; unit: string }; diff --git a/src/api/reports/awsReports.ts b/src/api/reports/awsReports.ts index 989f4391e..1fea4d336 100644 --- a/src/api/reports/awsReports.ts +++ b/src/api/reports/awsReports.ts @@ -1,4 +1,5 @@ import { axiosInstance } from 'api'; +import { default as devAxiosInstance } from 'api/apiDev'; import type { Report, ReportData, ReportItem, ReportItemValue, ReportMeta, ReportValue } from './report'; import { ReportType } from './report'; @@ -48,11 +49,17 @@ export const ReportTypePaths: Partial> = { [ReportType.cost]: 'reports/aws/costs/', [ReportType.database]: 'reports/aws/costs/', [ReportType.network]: 'reports/aws/costs/', + [ReportType.ec2Compute]: 'reports/aws/resources/ec2-compute/', [ReportType.storage]: 'reports/aws/storage/', [ReportType.instanceType]: 'reports/aws/instance-types/', }; export function runReport(reportType: ReportType, query: string) { const path = ReportTypePaths[reportType]; + + // For use with API development + if (reportType === ReportType.ec2Compute) { + return devAxiosInstance.get(`${path}?${query}`); + } return axiosInstance.get(`${path}?${query}`); } diff --git a/src/api/reports/ocpReports.ts b/src/api/reports/ocpReports.ts index c7eafab80..56ec64c07 100644 --- a/src/api/reports/ocpReports.ts +++ b/src/api/reports/ocpReports.ts @@ -61,6 +61,7 @@ export const ReportTypePaths: Partial> = { [ReportType.cost]: 'reports/openshift/costs/', [ReportType.cpu]: 'reports/openshift/compute/', [ReportType.memory]: 'reports/openshift/memory/', + [ReportType.network]: 'reports/openshift/network/', [ReportType.volume]: 'reports/openshift/volumes/', }; diff --git a/src/api/reports/report.ts b/src/api/reports/report.ts index e72a76eaa..9506fa601 100644 --- a/src/api/reports/report.ts +++ b/src/api/reports/report.ts @@ -38,6 +38,27 @@ export interface ReportAwsItem extends ReportItem { service?: string; } +export interface ReportAwsInstancesItem { + account?: string; + account_alias?: string; + cost?: ReportValue; + instance_name?: string; + instance_type?: string; + memory?: ReportValue; + operating_system?: string; + region?: string; + resource_id?: string; + tags: [ + { + key?: string; + values?: string[]; + enabled?: boolean; + }, + ]; + usage?: ReportValue; + vcpu?: ReportValue; +} + export interface ReportGcpItem extends ReportItem { account?: string; project?: string; @@ -74,10 +95,33 @@ export interface ReportOrgData { type?: string; // 'account' or 'organizational_unit' } +export interface ReportNetworkData { + date?: string; + data_transfer_in?: { + value?: number; + units?: string; + }; + data_transfer_out?: { + value?: number; + units?: string; + }; + resource_id?: string; + clusters?: string[]; + source_uuid?: string; + region?: string; +} + // Additional props for group_by[org_unit_id] export interface ReportData extends ReportOrgData { date?: string; - values?: ReportAwsItem[] | ReportAzureItem[] | ReportGcpItem[] | ReportOcpItem[] | ReportOrgItem[]; + values?: + | ReportAwsItem[] + | ReportAwsInstancesItem[] + | ReportAzureItem[] + | ReportGcpItem[] + | ReportOcpItem[] + | ReportOrgItem[] + | ReportNetworkData[]; } export interface ReportMeta extends PagedMetaData { @@ -119,6 +163,7 @@ export const enum ReportType { cost = 'cost', cpu = 'cpu', database = 'database', + ec2Compute = 'ec2Compute', instanceType = 'instance_type', memory = 'memory', network = 'network', diff --git a/src/components/featureToggle/featureToggle.tsx b/src/components/featureToggle/featureToggle.tsx index 5cb1c139a..b0bc08853 100644 --- a/src/components/featureToggle/featureToggle.tsx +++ b/src/components/featureToggle/featureToggle.tsx @@ -6,15 +6,15 @@ import { FeatureToggleActions } from 'store/featureToggle'; // eslint-disable-next-line no-shadow export const enum FeatureToggle { - clusterInfo = 'cost-management.ui.cluster.info', // https://issues.redhat.com/browse/COST-4559 + awsEc2Instances = 'cost-management.ui.aws-ec2-instances', // https://issues.redhat.com/browse/COST-4855 debug = 'cost-management.ui.debug', exports = 'cost-management.ui.exports', // Async exports https://issues.redhat.com/browse/COST-2223 finsights = 'cost-management.ui.finsights', // RHEL support for FINsights https://issues.redhat.com/browse/COST-3306 ibm = 'cost-management.ui.ibm', // IBM https://issues.redhat.com/browse/COST-935 + ocpCloudNetworking = 'cost-management.ui.ocp-cloud-networking', // https://issues.redhat.com/browse/COST-4781 + ocpProjectStorage = 'cost-management.ui.ocp-project-storage', // https://issues.redhat.com/browse/COST-4856 ros = 'cost-management.ui.ros', // ROS support https://issues.redhat.com/browse/COST-3477 - rosBeta = 'cost-management.ui.ros-beta', // ROS support https://issues.redhat.com/browse/COST-3477 - settingsPlatform = 'cost-management.ui.settings.platform', // Platform projects https://issues.redhat.com/browse/COST-3818 - tagMapping = 'cost-management.ui.tag.mapping', // https://issues.redhat.com/browse/COST-3824 + rosPreview = 'cost-management.ui.ros-preview', // ROS support https://issues.redhat.com/browse/COST-3477 } const useIsToggleEnabled = (toggle: FeatureToggle) => { @@ -22,12 +22,12 @@ const useIsToggleEnabled = (toggle: FeatureToggle) => { return client.isEnabled(toggle); }; -export const useIsDebugToggleEnabled = () => { - return useIsToggleEnabled(FeatureToggle.debug); +export const useIsAwsEc2InstancesToggleEnabled = () => { + return useIsToggleEnabled(FeatureToggle.awsEc2Instances); }; -export const useIsClusterInfoToggleEnabled = () => { - return useIsToggleEnabled(FeatureToggle.clusterInfo); +export const useIsDebugToggleEnabled = () => { + return useIsToggleEnabled(FeatureToggle.debug); }; export const useIsExportsToggleEnabled = () => { @@ -42,19 +42,19 @@ export const useIsIbmToggleEnabled = () => { return useIsToggleEnabled(FeatureToggle.ibm); }; -export const useIsRosToggleEnabled = () => { - const { isBeta } = useChrome(); - const isRosToggleEnabled = useIsToggleEnabled(FeatureToggle.ros); - const isRosFeatureBetaEnabled = useIsToggleEnabled(FeatureToggle.rosBeta) && isBeta(); // Enabled for prod-beta - return isRosToggleEnabled || isRosFeatureBetaEnabled; +export const useIsOcpCloudNetworkingToggleEnabled = () => { + return useIsToggleEnabled(FeatureToggle.ocpCloudNetworking); }; -export const useIsSettingsPlatformToggleEnabled = () => { - return useIsToggleEnabled(FeatureToggle.settingsPlatform); +export const useIsOcpProjectStorageToggleEnabled = () => { + return useIsToggleEnabled(FeatureToggle.ocpProjectStorage); }; -export const useIsTagMappingToggleEnabled = () => { - return useIsToggleEnabled(FeatureToggle.tagMapping); +export const useIsRosToggleEnabled = () => { + const { isBeta } = useChrome(); + const isRosToggleEnabled = useIsToggleEnabled(FeatureToggle.ros); + const isRosFeaturePreviewEnabled = useIsToggleEnabled(FeatureToggle.rosPreview) && isBeta(); // Enabled for prod-beta + return isRosToggleEnabled || isRosFeaturePreviewEnabled; }; // The FeatureToggle component saves feature toggles in store for places where Unleash hooks not available @@ -62,14 +62,14 @@ export const useFeatureToggle = () => { const dispatch = useDispatch(); const { auth } = useChrome(); - const isClusterInfoToggleEnabled = useIsClusterInfoToggleEnabled(); + const isAwsEc2InstancesToggleEnabled = useIsAwsEc2InstancesToggleEnabled(); const isDebugToggleEnabled = useIsDebugToggleEnabled(); const isExportsToggleEnabled = useIsExportsToggleEnabled(); const isFinsightsToggleEnabled = useIsFinsightsToggleEnabled(); const isIbmToggleEnabled = useIsIbmToggleEnabled(); + const isOcpCloudNetworkingToggleEnabled = useIsOcpCloudNetworkingToggleEnabled(); + const isOcpProjectStorageToggleEnabled = useIsOcpProjectStorageToggleEnabled(); const isRosToggleEnabled = useIsRosToggleEnabled(); - const isSettingsPlatformToggleEnabled = useIsSettingsPlatformToggleEnabled(); - const isTagMappingToggleEnabled = useIsTagMappingToggleEnabled(); const fetchUser = callback => { auth.getUser().then(user => { @@ -81,14 +81,14 @@ export const useFeatureToggle = () => { // Workaround for code that doesn't use hooks dispatch( FeatureToggleActions.setFeatureToggle({ - isClusterInfoToggleEnabled, + isAwsEc2InstancesToggleEnabled, isDebugToggleEnabled, isExportsToggleEnabled, isFinsightsToggleEnabled, isIbmToggleEnabled, + isOcpCloudNetworkingToggleEnabled, + isOcpProjectStorageToggleEnabled, isRosToggleEnabled, - isSettingsPlatformToggleEnabled, - isTagMappingToggleEnabled, }) ); if (isDebugToggleEnabled) { @@ -96,14 +96,14 @@ export const useFeatureToggle = () => { fetchUser(identity => console.log('User identity:', identity)); } }, [ - isClusterInfoToggleEnabled, + isAwsEc2InstancesToggleEnabled, isDebugToggleEnabled, isExportsToggleEnabled, isFinsightsToggleEnabled, isIbmToggleEnabled, + isOcpCloudNetworkingToggleEnabled, + isOcpProjectStorageToggleEnabled, isRosToggleEnabled, - isSettingsPlatformToggleEnabled, - isTagMappingToggleEnabled, ]); }; diff --git a/src/locales/messages.ts b/src/locales/messages.ts index 3d67d9700..fcd0578c9 100644 --- a/src/locales/messages.ts +++ b/src/locales/messages.ts @@ -165,22 +165,23 @@ export default defineMessages({ breakdownSummaryTitle: { defaultMessage: '{value, select, ' + - 'account {Cost by accounts} ' + - 'aws_category {Cost by category} ' + - 'cluster {Cost by clusters} ' + - 'gcp_project {Cost by GCP projects} ' + - 'node {Cost by Node} ' + - 'org_unit_id {Cost by organizational units} ' + - 'payer_tenant_id {Cost by accounts} ' + - 'platform {Cost by default projects} ' + - 'product_service {Cost by services} ' + - 'project {Cost by projects} ' + - 'region {Cost by regions} ' + - 'resource_location {Cost by regions} ' + - 'service {Cost by services} ' + - 'service_name {Cost by services} ' + - 'subscription_guid {Cost by accounts} ' + - 'tag {Cost by tags} ' + + 'account {Cost breakdown by accounts} ' + + 'aws_category {Cost breakdown by category} ' + + 'cluster {Cost breakdown by clusters} ' + + 'gcp_project {Cost breakdown by GCP projects} ' + + 'node {Cost breakdown by Node} ' + + 'org_unit_id {Cost breakdown by organizational units} ' + + 'payer_tenant_id {Cost breakdown by accounts} ' + + 'platform {Cost breakdown by default projects} ' + + 'product_service {Cost breakdown by services} ' + + 'project {Cost breakdown by projects} ' + + 'region {Cost breakdown by regions} ' + + 'resource_location {Cost breakdown by regions} ' + + 'service {Cost breakdown by services} ' + + 'service_name {Cost breakdown by services} ' + + 'storageclass {Storage cost breakdown by type} ' + + 'subscription_guid {Cost breakdown by accounts} ' + + 'tag {Cost breakdown by tags} ' + 'other {}}', description: 'Cost by {value}', id: 'breakdownSummaryTitle', @@ -205,90 +206,105 @@ export default defineMessages({ description: 'Cancel', id: 'cancel', }, - chartCostForecastConeLegendLabel: { + chartCostForecastConeLabel: { defaultMessage: 'Cost confidence ({dateRange})', description: 'Cost confidence (Jan 1-31)', - id: 'chartCostForecastConeLegendLabel', + id: 'chartCostForecastConeLabel', }, - chartCostForecastConeLegendNoDataLabel: { + chartCostForecastConeLabelNoData: { defaultMessage: 'Cost confidence (no data)', description: 'Cost confidence (no data)', - id: 'chartCostForecastConeLegendNoDataLabel', + id: 'chartCostForecastConeLabelNoData', }, - chartCostForecastConeLegendTooltip: { - defaultMessage: 'Cost confidence ({month})', - description: 'Cost confidence (Jan)', - id: 'chartCostForecastConeLegendTooltip', - }, - chartCostForecastConeTooltip: { + chartCostForecastConeRangeTooltip: { defaultMessage: '{value0} - {value1}', description: 'Cost forecast confidence min/max tooltip', + id: 'chartCostForecastConeRangeTooltip', + }, + chartCostForecastConeTooltip: { + defaultMessage: 'Cost confidence ({month})', + description: 'Cost confidence (Jan)', id: 'chartCostForecastConeTooltip', }, - chartCostForecastLegendLabel: { + chartCostForecastLabel: { defaultMessage: 'Cost forecast ({dateRange})', description: 'Cost forecast (Jan 1-31)', - id: 'chartCostForecastLegendLabel', + id: 'chartCostForecastLabel', }, - chartCostForecastLegendNoDataLabel: { + chartCostForecastLabelNoData: { defaultMessage: 'Cost forecast (no data)', description: 'Cost forecast (no data)', - id: 'chartCostForecastLegendNoDataLabel', + id: 'chartCostForecastLabelNoData', }, - chartCostForecastLegendTooltip: { + chartCostForecastTooltip: { defaultMessage: 'Cost forecast ({month})', description: 'Cost forecast (Jan 1-31)', - id: 'chartCostForecastLegendTooltip', + id: 'chartCostForecastTooltip', }, - chartCostLegendLabel: { + chartCostLabel: { defaultMessage: 'Cost ({dateRange})', description: 'Cost (Jan 1-31)', - id: 'chartCostLegendLabel', + id: 'chartCostLabel', }, - chartCostLegendNoDataLabel: { + chartCostLabelNoData: { defaultMessage: 'Cost (no data)', description: 'Cost (no data)', - id: 'chartCostLegendNoDataLabel', + id: 'chartCostLabelNoData', }, - chartCostLegendTooltip: { + chartCostTooltip: { defaultMessage: 'Cost ({month})', description: 'Cost (Jan)', - id: 'chartCostLegendTooltip', - }, - chartCostSupplementaryLegendLabel: { - defaultMessage: 'Supplementary cost ({dateRange})', - description: 'Supplementary cost (Jan 1-31)', - id: 'chartCostSupplementaryLegendLabel', - }, - chartCostSupplementaryLegendNoDataLabel: { - defaultMessage: 'Supplementary cost (no data)', - description: 'Supplementary cost (no data)', - id: 'chartCostSupplementaryLegendNoDataLabel', - }, - chartCostSupplementaryLegendTooltip: { - defaultMessage: 'Supplementary cost ({month})', - description: 'Supplementary cost (Jan)', - id: 'chartCostSupplementaryLegendTooltip', + id: 'chartCostTooltip', + }, + chartDataInLabel: { + defaultMessage: 'Data in ({dateRange})', + description: 'Data in ({dateRange})', + id: 'chartDataInLabel', + }, + chartDataInLabelNoData: { + defaultMessage: 'Data in (no data)', + description: 'Data in (no data)', + id: 'chartDataInLabelNoData', + }, + chartDataInTooltip: { + defaultMessage: 'Data in ({month})', + description: 'Data in ({month})', + id: 'chartDataInTooltip', + }, + chartDataOutLabel: { + defaultMessage: 'Data out ({dateRange})', + description: 'Data out ({dateRange})', + id: 'chartDataOutLabel', + }, + chartDataOutLabelNoData: { + defaultMessage: 'Data out (no data)', + description: 'Data out (no data)', + id: 'chartDataOutLabelNoData', + }, + chartDataOutTooltip: { + defaultMessage: 'Data out ({month})', + description: 'Data out ({month})', + id: 'chartDataOutTooltip', }, chartDayOfTheMonth: { defaultMessage: 'Day {day}', description: 'The day of the month', id: 'chartDayOfTheMonth', }, - chartLimitLegendLabel: { + chartLimitLabel: { defaultMessage: 'Limit ({dateRange})', description: 'Limit (Jan 1-31)', - id: 'chartLimitLegendLabel', + id: 'chartLimitLabel', }, - chartLimitLegendNoDataLabel: { + chartLimitLabelNoData: { defaultMessage: 'Limit (no data)', description: 'Limit (no data)', - id: 'chartLimitLegendNoDataLabel', + id: 'chartLimitLabelNoData', }, - chartLimitLegendTooltip: { + chartLimitTooltip: { defaultMessage: 'Limit ({month})', description: 'Limit (Jan)', - id: 'chartLimitLegendTooltip', + id: 'chartLimitTooltip', }, chartNoData: { defaultMessage: 'no data', @@ -300,35 +316,50 @@ export default defineMessages({ description: 'Others category for top costliest', id: 'chartOthers', }, - chartRequestsLegendLabel: { + chartRequestsLabel: { defaultMessage: 'Requests ({dateRange})', description: 'Requests (Jan 1-31)', - id: 'chartRequestsLegendLabel', + id: 'chartRequestsLabel', }, - chartRequestsLegendNoDataLabel: { + chartRequestsLabelNoData: { defaultMessage: 'Requests (no data)', description: 'Requests (no data)', - id: 'chartRequestsLegendNoDataLabel', + id: 'chartRequestsLabelNoData', }, - chartRequestsLegendTooltip: { + chartRequestsTooltip: { defaultMessage: 'Requests ({month})', description: 'Requests (Jan)', - id: 'chartRequestsLegendTooltip', + id: 'chartRequestsTooltip', + }, + chartSupplementaryCostLabel: { + defaultMessage: 'Supplementary cost ({dateRange})', + description: 'Supplementary cost (Jan 1-31)', + id: 'chartSupplementaryCostLabel', + }, + chartSupplementaryCostLabelNoData: { + defaultMessage: 'Supplementary cost (no data)', + description: 'Supplementary cost (no data)', + id: 'chartSupplementaryCostLabelNoData', + }, + chartSupplementaryCostTooltip: { + defaultMessage: 'Supplementary cost ({month})', + description: 'Supplementary cost (Jan)', + id: 'chartSupplementaryCostTooltip', }, - chartUsageLegendLabel: { + chartUsageLabel: { defaultMessage: 'Usage ({dateRange})', description: 'Usage (Jan 1-31)', - id: 'chartUsageLegendLabel', + id: 'chartUsageLabel', }, - chartUsageLegendNoDataLabel: { + chartUsageLabelNoData: { defaultMessage: 'Usage (no data)', description: 'Usage (no data)', - id: 'chartUsageLegendNoDataLabel', + id: 'chartUsageLabelNoData', }, - chartUsageLegendTooltip: { + chartUsageTooltip: { defaultMessage: 'Usage ({month})', description: 'Usage (Jan)', - id: 'chartUsageLegendTooltip', + id: 'chartUsageTooltip', }, chooseKeyPlaceholder: { defaultMessage: 'Choose key', @@ -1284,9 +1315,14 @@ export default defineMessages({ 'cluster {Cluster names} ' + 'gcp_project {GCP project names} ' + 'group {Group} ' + + 'instance {Instance names} ' + + 'instance_type {Instance type} ' + + 'memory {Memory} ' + 'name {Name} ' + 'node {Node names} ' + 'org_unit_id {Organizational unit names} ' + + 'os {OS} ' + + 'operating_system {Operating system} ' + 'payer_tenant_id {Account names} ' + 'product_service {Service names} ' + 'project {Project names} ' + @@ -1298,7 +1334,9 @@ export default defineMessages({ 'subscription_guid {Account names} ' + 'source_type {Integration} ' + 'tag {Tag names} ' + + 'tags {Tags} ' + 'tag_key {Tag keys} ' + + 'vcpu {vCPU} ' + 'other {}}', description: 'Details table resource names', id: 'detailsResourceNames', @@ -1331,8 +1369,8 @@ export default defineMessages({ id: 'detailsUnusedCapacityLabel', }, detailsUnusedRequestsLabel: { - defaultMessage: 'Unrequested capacity', - description: 'Unrequested capacity', + defaultMessage: 'Unused requests', + description: 'Unused requests', id: 'detailsUnusedRequestsLabel', }, detailsUnusedUnits: { @@ -1376,6 +1414,7 @@ export default defineMessages({ 'resource_location {View all regions} ' + 'service {View all Services} ' + 'service_name {View all services} ' + + 'storageclass {View all storage types} ' + 'subscription_guid {View all accounts} ' + 'tag {View all tags} ' + 'other {}}', @@ -1410,17 +1449,24 @@ export default defineMessages({ distributeCosts: { defaultMessage: '{value, select, ' + - 'true {Distribute {type, select, platform {platform} worker {worker} other {}} unallocated capacity}' + - 'false {Do not distribute {type, select, platform {platform} worker {worker} other {}} unallocated capacity}' + + 'true {Distribute {type, select, network {network} storage {storage} other {}} costs}' + + 'false {Do not distribute {type, select, network {network} storage {storage} other {}} costs}' + 'other {}}', description: 'distribute costs', id: 'distributeCosts', }, - distributionModelDesc: { + distributeUnallocatedCapacity: { defaultMessage: - 'This choice is for users to direct how their raw costs are distributed either by CPU or Memory on the project level breakdowns.', - description: - 'This choice is for users to direct how their raw costs are distributed either by CPU or Memory on the project level breakdowns.', + '{value, select, ' + + 'true {Distribute {type, select, platform {platform} worker {worker} other {}} unallocated capacity}' + + 'false {Do not distribute {type, select, platform {platform} worker {worker} other {}} unallocated capacity}' + + 'other {}}', + description: 'distribute unallocated capacity', + id: 'distributeUnallocatedCapacity', + }, + distributionModelDesc: { + defaultMessage: 'Choose how your raw costs are distributed at the project level.', + description: 'Choose how your raw costs are distributed at the project level.', id: 'distributionModelDesc', }, distributionType: { @@ -1697,6 +1743,7 @@ export default defineMessages({ 'aws_category {{resolution, select, daily {{provider}_cost_category_daily_{startDate}_{endDate}} monthly {{provider}_cost_category_monthly_{startDate}_{endDate}} other {}}} ' + 'cluster {{resolution, select, daily {{provider}_clusters_daily_{startDate}_{endDate}} monthly {{provider}_clusters_monthly_{startDate}_{endDate}} other {}}} ' + 'gcp_project {{resolution, select, daily {{provider}_gcp-projects_daily_{startDate}_{endDate}} monthly {{provider}_gcp-projects_monthly_{startDate}_{endDate}} other {}}} ' + + 'instance {{resolution, select, daily {{provider}_instances_daily_{startDate}_{endDate}} monthly {{provider}_instances_monthly_{startDate}_{endDate}} other {}}} ' + 'node {{resolution, select, daily {{provider}_node_daily_{startDate}_{endDate}} monthly {{provider}_node_monthly_{startDate}_{endDate}} other {}}} ' + 'org_unit_id {{resolution, select, daily {{provider}_orgs_daily_{startDate}_{endDate}} monthly {{provider}_orgs_monthly_{startDate}_{endDate}} other {}}} ' + 'payer_tenant_id {{resolution, select, daily {{provider}_accounts_daily_{startDate}_{endDate}} monthly {{provider}_accounts_monthly_{startDate}_{endDate}} other {}}} ' + @@ -1734,6 +1781,7 @@ export default defineMessages({ 'aws_category {Aggregates of the following cost categories will be exported to a .csv file.} ' + 'cluster {Aggregates of the following clusters will be exported to a .csv file.} ' + 'gcp_project {Aggregates of the following GCP projects will be exported to a .csv file.} ' + + 'instance {Aggregates of the following instances will be exported to a .csv file.} ' + 'node {Aggregates of the following nodes will be exported to a .csv file.} ' + 'org_unit_id {Aggregates of the following organizational units will be exported to a .csv file.} ' + 'payer_tenant_id {Aggregates of the following accounts will be exported to a .csv file.} ' + @@ -1756,6 +1804,7 @@ export default defineMessages({ 'aws_category {{provider, select, aws {Amazon Web Services grouped by Cost category} aws_ocp {Amazon Web Services filtered by OpenShift grouped by Cost category} azure {Microsoft Azure grouped by Cost category} oci {Oracle Cloud Infrastructure grouped by Cost category} azure_ocp {Microsoft Azure filtered by OpenShift grouped by Cost category} gcp {Google Cloud Platform grouped by Cost category} gcp_ocp {Google Cloud Platform filtered by OpenShift grouped by Cost category} ibm {IBM Cloud grouped by Cost category} ibm_ocp {IBM Cloud filtered by OpenShift grouped by Cost category} ocp {OpenShift grouped by Cost category} ocp_cloud {All cloud filtered by OpenShift grouped by Cost category} other {}}} ' + 'cluster {{provider, select, aws {Amazon Web Services grouped by Cluster} aws_ocp {Amazon Web Services filtered by OpenShift grouped by Cluster} azure {Microsoft Azure grouped by Cluster} oci {Oracle Cloud Infrastructure grouped by Cluster} azure_ocp {Microsoft Azure filtered by OpenShift grouped by Cluster} gcp {Google Cloud Platform grouped by Cluster} gcp_ocp {Google Cloud Platform filtered by OpenShift grouped by Cluster} ibm {IBM Cloud grouped by Cluster} ibm_ocp {IBM Cloud filtered by OpenShift grouped by Cluster} ocp {OpenShift grouped by Cluster} ocp_cloud {All cloud filtered by OpenShift grouped by Cluster} other {}}} ' + 'gcp_project {{provider, select, aws {Amazon Web Services grouped by GCP Project} aws_ocp {Amazon Web Services filtered by OpenShift grouped by GCP Project} azure {Microsoft Azure grouped by GCP Project} oci {Oracle Cloud Infrastructure grouped by GCP Project} azure_ocp {Microsoft Azure filtered by OpenShift grouped by GCP Project} gcp {Google Cloud Platform grouped by GCP Project} gcp_ocp {Google Cloud Platform filtered by OpenShift grouped by GCP Project} ibm {IBM Cloud grouped by GCP Project} ibm_ocp {IBM Cloud filtered by OpenShift grouped by GCP Project} ocp {OpenShift grouped by GCP Project} ocp_cloud {All cloud filtered by OpenShift grouped by GCP Project} other {}}} ' + + 'instance {{provider, select, aws {Amazon Web Services grouped by instance} aws_ocp {Amazon Web Services filtered by OpenShift grouped by instance} azure {Microsoft Azure grouped by instance} oci {Oracle Cloud Infrastructure grouped by instance} azure_ocp {Microsoft Azure filtered by OpenShift grouped by instance} gcp {Google Cloud Platform grouped by instance} gcp_ocp {Google Cloud Platform filtered by OpenShift grouped by instance} ibm {IBM Cloud grouped by instance} ibm_ocp {IBM Cloud filtered by OpenShift grouped by instance} ocp {OpenShift grouped by instance} ocp_cloud {All cloud filtered by OpenShift grouped by instance} other {}}} ' + 'node {{provider, select, aws {Amazon Web Services grouped by Node} aws_ocp {Amazon Web Services filtered by OpenShift grouped by Node} azure {Microsoft Azure grouped by Node} oci {Oracle Cloud Infrastructure grouped by Node} azure_ocp {Microsoft Azure filtered by OpenShift grouped by Node} gcp {Google Cloud Platform grouped by Node} gcp_ocp {Google Cloud Platform filtered by OpenShift grouped by Node} ibm {IBM Cloud grouped by Node} ibm_ocp {IBM Cloud filtered by OpenShift grouped by Node} ocp {OpenShift grouped by Node} ocp_cloud {All cloud filtered by OpenShift grouped by Node} other {}}} ' + 'org_unit_id {{provider, select, aws {Amazon Web Services grouped by Organizational unit} aws_ocp {Amazon Web Services filtered by OpenShift grouped by Organizational unit} azure {Microsoft Azure grouped by Organizational unit} oci {Oracle Cloud Infrastructure grouped by Organizational unit} azure_ocp {Microsoft Azure filtered by OpenShift grouped by Organizational unit} gcp {Google Cloud Platform grouped by Organizational unit} gcp_ocp {Google Cloud Platform filtered by OpenShift grouped by Organizational unit} ibm {IBM Cloud grouped by Organizational unit} ibm_ocp {IBM Cloud filtered by OpenShift grouped by Organizational unit} ocp {OpenShift grouped by Organizational unit} ocp_cloud {All cloud filtered by OpenShift grouped by Organizational unit} other {}}} ' + 'payer_tenant_id {{provider, select, oci {Oracle Cloud Infrastructure grouped by Account} other {}}}' + @@ -1793,6 +1842,7 @@ export default defineMessages({ 'aws_category {Selected cost categories ({count})} ' + 'cluster {Selected clusters ({count})} ' + 'gcp_project {Selected GCP projects ({count})} ' + + 'instance {Selected instances ({count})} ' + 'node {Selected nodes ({count})} ' + 'org_unit_id {Selected organizational units ({count})} ' + 'payer_tenant_id {Selected accounts ({count})} ' + @@ -2012,9 +2062,11 @@ export default defineMessages({ 'default {Default} ' + 'gcp_project {GCP project} ' + 'group {Group} ' + + 'instance {Instance} ' + 'name {Name} ' + 'node {Node} ' + 'org_unit_id {Organizational unit} ' + + 'operating_system {Operating system} ' + 'payer_tenant_id {Account} ' + 'persistent_volume_claim {Persistent volume claim} ' + 'product_service {Service} ' + @@ -2042,6 +2094,16 @@ export default defineMessages({ description: 'Values', id: 'filterByValuesAriaLabel', }, + filteredBy: { + defaultMessage: 'Filtered by', + description: 'Filtered by', + id: 'filteredBy', + }, + filteredByWarning: { + defaultMessage: 'This page shows filtered results. To undo filters, clear filters on the previous page.', + description: 'This page shows filtered results. To undo filters, clear filters on the previous page.', + id: 'filteredByWarning', + }, forDate: { defaultMessage: '{value} for {dateRange}', description: '{value} for {Jan 1-31}', @@ -2215,6 +2277,7 @@ export default defineMessages({ 'instance_type {Compute usage comparison}' + 'memory {Memory usage, request, and limit comparison} ' + 'modal {{name} daily usage comparison} ' + + 'network {Network usage comparison} ' + 'storage {Storage usage comparison} ' + 'virtual_machine {Virtual machine usage comparison}' + 'other {}}', @@ -2281,6 +2344,11 @@ export default defineMessages({ description: 'Infrastructure', id: 'infrastructure', }, + instances: { + defaultMessage: 'Instances', + description: 'Instances', + id: 'instances', + }, lastProcessed: { defaultMessage: 'Last processed', description: 'Last processed', @@ -2452,11 +2520,26 @@ export default defineMessages({ description: 'Month over month change', id: 'monthOverMonthChange', }, + moreOptions: { + defaultMessage: 'More options', + description: 'More options', + id: 'moreOptions', + }, names: { defaultMessage: '{count, plural, one {Name} other {Names}}', description: 'Name plural or singular', id: 'names', }, + network: { + defaultMessage: 'Network', + description: 'Network', + id: 'network', + }, + networkDesc: { + defaultMessage: 'Distribute the cost of network traffic to projects based on distribution type.', + description: 'Distribute the cost of network traffic to projects based on distribution type.', + id: 'networkDesc', + }, next: { defaultMessage: 'next', description: 'next', @@ -2493,6 +2576,16 @@ export default defineMessages({ description: 'There are no export files available', id: 'noExportsStateTitle', }, + noInstancesDesc: { + defaultMessage: 'Add an Amazon EC2 instance to see a total cost breakdown of your spend by instances.', + description: 'Add an Amazon EC2 instance to see a total cost breakdown of your spend by instances.', + id: 'noInstancesDesc', + }, + noInstancesTitle: { + defaultMessage: 'No instances available', + description: 'No instances available', + id: 'noInstancesTitle', + }, noMappedTags: { defaultMessage: 'No mapped tags', description: 'No mapped tags', @@ -2510,18 +2603,6 @@ export default defineMessages({ description: 'Tags must be enabled to be mapped.', id: 'noMappedTagsWarning', }, - noOptimizationsDesc: { - defaultMessage: - 'Resource Optimization is now available in preview for select customers. If your organization wants to participate, tell us through the Feedback button, which is purple and located on the right. Otherwise, there is not enough data available to generate an optimization.', - description: - 'Resource Optimization is now available in preview for select customers. If your organization wants to participate, tell us through the Feedback button, which is purple and located on the right. Otherwise, there is not enough data available to generate an optimization.', - id: 'noOptimizationsDesc', - }, - noOptimizationsTitle: { - defaultMessage: 'No optimizations available', - description: 'No optimizations available', - id: 'noOptimizationsTitle', - }, noProvidersStateAwsDesc: { defaultMessage: 'Add an Amazon Web Services account to see a total cost breakdown of your spend by accounts, organizational units, services, regions, or tags.', @@ -3364,11 +3445,21 @@ export default defineMessages({ description: 'Status/Actions', id: 'statusActions', }, + storage: { + defaultMessage: 'Storage', + description: 'Storage', + id: 'storage', + }, storageClass: { defaultMessage: 'StorageClass', description: 'StorageClass', id: 'storageClass', }, + storageDesc: { + defaultMessage: 'Distribute the cost of storage to projects based on distribution type.', + description: 'Distribute the cost of storage to projects based on distribution type.', + id: 'storageDesc', + }, suggestions: { defaultMessage: 'Suggestions', description: 'Suggestions', @@ -3717,6 +3808,11 @@ export default defineMessages({ description: 'Various', id: 'various', }, + vcpuTitle: { + defaultMessage: 'vCPU', + description: 'vCPU', + id: 'vcpuTitle', + }, volumeTitle: { defaultMessage: 'Volume', description: 'Volume', diff --git a/src/routes/components/charts/common/chartDatum.ts b/src/routes/components/charts/common/chartDatum.ts index 98f007662..bbfae5121 100644 --- a/src/routes/components/charts/common/chartDatum.ts +++ b/src/routes/components/charts/common/chartDatum.ts @@ -56,7 +56,7 @@ export function transformReport( datumType, idKey: any = 'date', reportItem: string = 'cost', - reportItemValue: string = 'total' // useful for infrastructure.usage values and cost distribution + reportItemValue: string // useful for infrastructure.usage values and cost distribution ): ChartDatum[] { if (!report) { return []; @@ -72,14 +72,24 @@ export function transformReport( if (datumType === DatumType.cumulative) { chartDatums = computedItems.reduce((acc, d) => { const prevValue = acc.length ? acc[acc.length - 1].y : 0; - const val = d[reportItem][reportItemValue] ? d[reportItem][reportItemValue].value : d[reportItem].value; - return [...acc, createReportDatum(prevValue + val, d, idKey, reportItem, reportItemValue)]; + if (reportItemValue) { + const val = d[reportItem][reportItemValue] ? d[reportItem][reportItemValue].value : d[reportItem].value; + return [...acc, createReportDatum(prevValue + val, d, idKey, reportItem, reportItemValue)]; + } else { + const val = d[reportItem] ? d[reportItem].value : d[reportItem].value; + return [...acc, createReportDatum(prevValue + val, d, idKey, reportItem, undefined)]; + } }, []); } else { chartDatums = computedItems.map(i => { if (i[reportItem]) { - const val = i[reportItem][reportItemValue] ? i[reportItem][reportItemValue].value : i[reportItem].value; - return createReportDatum(val, i, idKey, reportItem, reportItemValue); + if (reportItemValue) { + const val = i[reportItem][reportItemValue] ? i[reportItem][reportItemValue].value : i[reportItem].value; + return createReportDatum(val, i, idKey, reportItem, reportItemValue); + } else { + const val = i[reportItem] ? i[reportItem].value : i[reportItem].value; + return createReportDatum(val, i, idKey, reportItem, undefined); + } } }); } @@ -91,7 +101,7 @@ export function createReportDatum( computedItem: T, idKey = 'date', reportItem: string = 'cost', - reportItemValue: string = 'total' // useful for infrastructure.usage values + reportItemValue: string // useful for infrastructure.usage values ): ChartDatum { const xVal = idKey === 'date' ? getDate(new Date(computedItem.id + 'T00:00:00')) : computedItem.label; const yVal = isFloat(value) ? parseFloat(value.toFixed(2)) : isInt(value) ? value : 0; @@ -166,7 +176,7 @@ export function padChartDatums(datums: ChartDatum[], datumType): ChartDatum[] { for (let i = padDate.getDate(); i < firstDate.getDate(); i++) { padDate.setDate(i); const id = format(padDate, 'yyyy-MM-dd'); - result.push(createReportDatum(null, { id }, 'date', null)); + result.push(createReportDatum(null, { id }, 'date', undefined, undefined)); } // Fill middle with existing data @@ -177,7 +187,7 @@ export function padChartDatums(datums: ChartDatum[], datumType): ChartDatum[] { for (let i = padDate.getDate() + 1; i <= endOfMonth(lastDate).getDate(); i++) { padDate.setDate(i); const id = format(padDate, 'yyyy-MM-dd'); - result.push(createReportDatum(null, { id }, 'date', null)); + result.push(createReportDatum(null, { id }, 'date', undefined, undefined)); } return fillChartDatums(result, datumType); } @@ -282,7 +292,7 @@ export function getTooltipContent(formatter) { export function getCostRangeString( datums: ChartDatum[], - key: MessageDescriptor = messages.chartCostLegendLabel, + key: MessageDescriptor = messages.chartCostLabel, firstOfMonth: boolean = false, lastOfMonth: boolean = false, offset: number = 0, @@ -304,7 +314,7 @@ export function getCostRangeString( export function getCostRangeTooltip( datums: ChartDatum[], - key: MessageDescriptor = messages.chartCostLegendLabel, + key: MessageDescriptor = messages.chartCostLabel, firstOfMonth: boolean = false, lastOfMonth: boolean = false, offset: number = 0, @@ -325,7 +335,7 @@ export function getCostRangeTooltip( export function getUsageRangeString( datums: ChartDatum[], - key: MessageDescriptor = messages.chartUsageLegendLabel, + key: MessageDescriptor = messages.chartUsageLabel, firstOfMonth: boolean = false, lastOfMonth: boolean = false, offset: number = 0, @@ -336,7 +346,7 @@ export function getUsageRangeString( export function getUsageRangeTooltip( datums: ChartDatum[], - key: MessageDescriptor = messages.chartUsageLegendLabel, + key: MessageDescriptor = messages.chartUsageLabel, firstOfMonth: boolean = false, lastOfMonth: boolean = false, offset: number = 0, diff --git a/src/routes/components/charts/common/chartUtils.ts b/src/routes/components/charts/common/chartUtils.ts index 6c47b9503..2dd2819fd 100644 --- a/src/routes/components/charts/common/chartUtils.ts +++ b/src/routes/components/charts/common/chartUtils.ts @@ -97,7 +97,7 @@ export const getTooltipLabel = (datum: any, formatter: Formatter, formatOptions: datum.y0 !== undefined && datum.y0 !== null ? tooltipFormatter(datum.y0, datum.units, formatOptions) : undefined; if (dy !== undefined && dy0 !== undefined) { - return intl.formatMessage(messages.chartCostForecastConeTooltip, { value0: dy0, value1: dy }); + return intl.formatMessage(messages.chartCostForecastConeRangeTooltip, { value0: dy0, value1: dy }); } return dy !== undefined ? dy : intl.formatMessage(messages.chartNoData); }; diff --git a/src/routes/components/charts/costChart/costChart.tsx b/src/routes/components/charts/costChart/costChart.tsx index 672697766..07f36485c 100644 --- a/src/routes/components/charts/costChart/costChart.tsx +++ b/src/routes/components/charts/costChart/costChart.tsx @@ -93,8 +93,8 @@ class CostChartBase extends React.Component { private initDatum = () => { const { currentCostData, forecastConeData, forecastData, previousCostData, showForecast } = this.props; - const costKey = messages.chartCostLegendLabel; - const costTooltipKey = messages.chartCostLegendTooltip; + const costKey = messages.chartCostLabel; + const costTooltipKey = messages.chartCostTooltip; // Show all legends, regardless of length -- https://github.com/project-koku/koku-ui/issues/248 @@ -103,7 +103,7 @@ class CostChartBase extends React.Component { childName: 'previousCost', data: previousCostData, legendItem: { - name: getCostRangeString(previousCostData, costKey, true, true, 1, messages.chartCostLegendNoDataLabel), + name: getCostRangeString(previousCostData, costKey, true, true, 1, messages.chartCostLabelNoData), symbol: { fill: chartStyles.previousColorScale[0], type: 'minus', @@ -121,7 +121,7 @@ class CostChartBase extends React.Component { childName: 'currentCost', data: currentCostData, legendItem: { - name: getCostRangeString(currentCostData, costKey, true, false, 0, messages.chartCostLegendNoDataLabel), + name: getCostRangeString(currentCostData, costKey, true, false, 0, messages.chartCostLabelNoData), symbol: { fill: chartStyles.currentColorScale[0], type: 'minus', @@ -144,17 +144,17 @@ class CostChartBase extends React.Component { legendItem: { name: getCostRangeString( forecastData, - messages.chartCostForecastLegendLabel, + messages.chartCostForecastLabel, false, false, 0, - messages.chartCostForecastLegendNoDataLabel + messages.chartCostForecastLabelNoData ), symbol: { fill: chartStyles.forecastDataColorScale[0], type: 'minus', }, - tooltip: getCostRangeTooltip(forecastData, messages.chartCostForecastLegendTooltip, false, false), + tooltip: getCostRangeTooltip(forecastData, messages.chartCostForecastTooltip, false, false), }, style: { data: { @@ -169,17 +169,17 @@ class CostChartBase extends React.Component { legendItem: { name: getCostRangeString( forecastConeData, - messages.chartCostForecastConeLegendLabel, + messages.chartCostForecastConeLabel, false, false, 0, - messages.chartCostForecastConeLegendNoDataLabel + messages.chartCostForecastConeLabelNoData ), symbol: { fill: chartStyles.forecastConeDataColorScale[0], type: 'triangleLeft', }, - tooltip: getCostRangeTooltip(forecastConeData, messages.chartCostForecastConeLegendTooltip, false, false), + tooltip: getCostRangeTooltip(forecastConeData, messages.chartCostForecastConeTooltip, false, false), }, style: { data: { diff --git a/src/routes/components/charts/dailyCostChart/dailyCostChart.tsx b/src/routes/components/charts/dailyCostChart/dailyCostChart.tsx index 7ae5bcf50..f07a9d133 100644 --- a/src/routes/components/charts/dailyCostChart/dailyCostChart.tsx +++ b/src/routes/components/charts/dailyCostChart/dailyCostChart.tsx @@ -96,8 +96,8 @@ class DailyCostChartBase extends React.Component { private initDatum = () => { const { currentCostData, forecastConeData, forecastData, previousCostData, showForecast } = this.props; - const costKey = messages.chartCostLegendLabel; - const costTooltipKey = messages.chartCostLegendTooltip; + const costKey = messages.chartCostLabel; + const costTooltipKey = messages.chartCostTooltip; // Show all legends, regardless of length -- https://github.com/project-koku/koku-ui/issues/248 @@ -106,7 +106,7 @@ class DailyCostChartBase extends React.Component { childName: 'previousCost', data: this.initDatumChildName(previousCostData, 'previousCost'), legendItem: { - name: getCostRangeString(previousCostData, costKey, true, true, 1, messages.chartCostLegendNoDataLabel), + name: getCostRangeString(previousCostData, costKey, true, true, 1, messages.chartCostLabelNoData), symbol: { fill: chartStyles.previousColorScale[0], type: 'minus', @@ -124,7 +124,7 @@ class DailyCostChartBase extends React.Component { childName: 'currentCost', data: this.initDatumChildName(currentCostData, 'currentCost'), legendItem: { - name: getCostRangeString(currentCostData, costKey, true, false, 0, messages.chartCostLegendNoDataLabel), + name: getCostRangeString(currentCostData, costKey, true, false, 0, messages.chartCostLabelNoData), symbol: { fill: chartStyles.currentColorScale[0], type: 'minus', @@ -147,17 +147,17 @@ class DailyCostChartBase extends React.Component { legendItem: { name: getCostRangeString( forecastData, - messages.chartCostForecastLegendLabel, + messages.chartCostForecastLabel, false, false, 0, - messages.chartCostForecastLegendNoDataLabel + messages.chartCostForecastLabelNoData ), symbol: { fill: chartStyles.forecastDataColorScale[0], type: 'minus', }, - tooltip: getCostRangeTooltip(forecastData, messages.chartCostForecastLegendTooltip, false, false), + tooltip: getCostRangeTooltip(forecastData, messages.chartCostForecastTooltip, false, false), }, isBar: true, isForecast: true, @@ -173,17 +173,17 @@ class DailyCostChartBase extends React.Component { legendItem: { name: getCostRangeString( forecastConeData, - messages.chartCostForecastConeLegendLabel, + messages.chartCostForecastConeLabel, false, false, 0, - messages.chartCostForecastConeLegendNoDataLabel + messages.chartCostForecastConeLabelNoData ), symbol: { fill: chartStyles.forecastConeDataColorScale[0], type: 'triangleLeft', }, - tooltip: getCostRangeTooltip(forecastConeData, messages.chartCostForecastConeLegendTooltip, false, false), + tooltip: getCostRangeTooltip(forecastConeData, messages.chartCostForecastConeTooltip, false, false), }, isForecast: true, isLine: true, diff --git a/src/routes/components/charts/dailyTrendChart/dailyTrendChart.tsx b/src/routes/components/charts/dailyTrendChart/dailyTrendChart.tsx index 9bd4ef8b2..a5dbf4977 100644 --- a/src/routes/components/charts/dailyTrendChart/dailyTrendChart.tsx +++ b/src/routes/components/charts/dailyTrendChart/dailyTrendChart.tsx @@ -108,22 +108,22 @@ class DailyTrendChartBase extends React.Component { } = this.props; const key = showUsageLegendLabel - ? messages.chartUsageLegendLabel + ? messages.chartUsageLabel : showSupplementaryLabel - ? messages.chartCostSupplementaryLegendLabel - : messages.chartCostLegendLabel; + ? messages.chartSupplementaryCostLabel + : messages.chartCostLabel; const tooltipKey = showUsageLegendLabel - ? messages.chartUsageLegendTooltip + ? messages.chartUsageTooltip : showSupplementaryLabel - ? messages.chartCostSupplementaryLegendTooltip - : messages.chartCostLegendTooltip; + ? messages.chartSupplementaryCostTooltip + : messages.chartCostTooltip; const noDataKey = showUsageLegendLabel - ? messages.chartUsageLegendNoDataLabel + ? messages.chartUsageLabelNoData : showSupplementaryLabel - ? messages.chartCostSupplementaryLegendNoDataLabel - : messages.chartCostLegendNoDataLabel; + ? messages.chartSupplementaryCostLabelNoData + : messages.chartCostLabelNoData; // Show all legends, regardless of length -- https://github.com/project-koku/koku-ui/issues/248 @@ -173,17 +173,17 @@ class DailyTrendChartBase extends React.Component { legendItem: { name: getCostRangeString( forecastData, - messages.chartCostForecastLegendLabel, + messages.chartCostForecastLabel, false, false, 0, - messages.chartCostForecastLegendNoDataLabel + messages.chartCostForecastLabelNoData ), symbol: { fill: chartStyles.forecastDataColorScale[0], type: 'minus', }, - tooltip: getCostRangeTooltip(forecastData, messages.chartCostForecastLegendTooltip, false, false), + tooltip: getCostRangeTooltip(forecastData, messages.chartCostForecastTooltip, false, false), }, isBar: true, isForecast: true, @@ -199,17 +199,17 @@ class DailyTrendChartBase extends React.Component { legendItem: { name: getCostRangeString( forecastConeData, - messages.chartCostForecastConeLegendLabel, + messages.chartCostForecastConeLabel, false, false, 0, - messages.chartCostForecastConeLegendNoDataLabel + messages.chartCostForecastConeLabelNoData ), symbol: { fill: chartStyles.forecastConeDataColorScale[0], type: 'minus', }, - tooltip: getCostRangeTooltip(forecastConeData, messages.chartCostForecastConeLegendTooltip, false, false), + tooltip: getCostRangeTooltip(forecastConeData, messages.chartCostForecastConeTooltip, false, false), }, isForecast: true, isLine: true, diff --git a/src/routes/components/charts/historicalCostChart/historicalCostChart.tsx b/src/routes/components/charts/historicalCostChart/historicalCostChart.tsx index da0c4ed31..a612b872d 100644 --- a/src/routes/components/charts/historicalCostChart/historicalCostChart.tsx +++ b/src/routes/components/charts/historicalCostChart/historicalCostChart.tsx @@ -94,8 +94,8 @@ class HistoricalCostChartBase extends React.Component { const { currentCostData, previousCostData } = this.props; - const costKey = messages.chartCostLegendLabel; - const costTooltipKey = messages.chartCostLegendTooltip; + const costKey = messages.chartCostLabel; + const costTooltipKey = messages.chartCostTooltip; // Show all legends, regardless of length -- https://github.com/project-koku/koku-ui/issues/248 @@ -104,7 +104,7 @@ class HistoricalCostChartBase extends React.Component - 0.00000000005 + 1.0 @@ -588,7 +588,7 @@ exports[`reports are formatted to datums 1`] = ` dx="0" id="exampleTrendChart-ChartAxis-3-ChartLabel-1" x="-7" - y="16.5" + y="20.75" > - 0.00000000010 + 1.5 @@ -609,7 +609,7 @@ exports[`reports are formatted to datums 1`] = ` dx="0" id="exampleTrendChart-ChartAxis-3-ChartLabel-2" x="-7" - y="12.25" + y="16.5" > - 0.00000000015 + 2.0 @@ -630,6 +630,27 @@ exports[`reports are formatted to datums 1`] = ` dx="0" id="exampleTrendChart-ChartAxis-3-ChartLabel-3" x="-7" + y="12.25" + > + + 2.5 + + + + + - 0.00000000020 + 3.0 diff --git a/src/routes/components/charts/historicalTrendChart/historicalTrendChart.tsx b/src/routes/components/charts/historicalTrendChart/historicalTrendChart.tsx index 6d288a19d..678907680 100644 --- a/src/routes/components/charts/historicalTrendChart/historicalTrendChart.tsx +++ b/src/routes/components/charts/historicalTrendChart/historicalTrendChart.tsx @@ -89,8 +89,8 @@ class HistoricalTrendChartBase extends React.Component { const { currentData, previousData, showUsageLegendLabel = false } = this.props; - const key = showUsageLegendLabel ? messages.chartUsageLegendLabel : messages.chartCostLegendLabel; - const toolTipKey = showUsageLegendLabel ? messages.chartUsageLegendTooltip : messages.chartCostLegendTooltip; + const key = showUsageLegendLabel ? messages.chartUsageLabel : messages.chartCostLabel; + const toolTipKey = showUsageLegendLabel ? messages.chartUsageTooltip : messages.chartCostTooltip; // Show all legends, regardless of length -- https://github.com/project-koku/koku-ui/issues/248 @@ -99,7 +99,7 @@ class HistoricalTrendChartBase extends React.Component - 0.00000000005 + 0.5 @@ -226,7 +226,7 @@ exports[`reports are formatted to datums 1`] = ` text-anchor="end" x="-7" > - 0.00000000010 + 1.0 @@ -247,7 +247,7 @@ exports[`reports are formatted to datums 1`] = ` text-anchor="end" x="-7" > - 0.00000000015 + 1.5 @@ -268,7 +268,7 @@ exports[`reports are formatted to datums 1`] = ` text-anchor="end" x="-7" > - 0.00000000020 + 2.0 diff --git a/src/routes/components/charts/trendChart/trendChart.tsx b/src/routes/components/charts/trendChart/trendChart.tsx index 8f6a68a42..2869f75af 100644 --- a/src/routes/components/charts/trendChart/trendChart.tsx +++ b/src/routes/components/charts/trendChart/trendChart.tsx @@ -105,22 +105,22 @@ class TrendChartBase extends React.Component { } = this.props; const key = showUsageLegendLabel - ? messages.chartUsageLegendLabel + ? messages.chartUsageLabel : showSupplementaryLabel - ? messages.chartCostSupplementaryLegendLabel - : messages.chartCostLegendLabel; + ? messages.chartSupplementaryCostLabel + : messages.chartCostLabel; const tooltipKey = showUsageLegendLabel - ? messages.chartUsageLegendTooltip + ? messages.chartUsageTooltip : showSupplementaryLabel - ? messages.chartCostSupplementaryLegendTooltip - : messages.chartCostLegendTooltip; + ? messages.chartSupplementaryCostTooltip + : messages.chartCostTooltip; const noDataKey = showUsageLegendLabel - ? messages.chartUsageLegendNoDataLabel + ? messages.chartUsageLabelNoData : showSupplementaryLabel - ? messages.chartCostSupplementaryLegendNoDataLabel - : messages.chartCostLegendNoDataLabel; + ? messages.chartSupplementaryCostLabelNoData + : messages.chartCostLabelNoData; // Show all legends, regardless of length -- https://github.com/project-koku/koku-ui/issues/248 @@ -170,17 +170,17 @@ class TrendChartBase extends React.Component { legendItem: { name: getCostRangeString( forecastData, - messages.chartCostForecastLegendLabel, + messages.chartCostForecastLabel, false, false, 0, - messages.chartCostForecastLegendNoDataLabel + messages.chartCostForecastLabelNoData ), symbol: { fill: chartStyles.forecastDataColorScale[0], type: 'minus', }, - tooltip: getCostRangeTooltip(forecastData, messages.chartCostForecastLegendTooltip, false, false), + tooltip: getCostRangeTooltip(forecastData, messages.chartCostForecastTooltip, false, false), }, style: { data: { @@ -195,17 +195,17 @@ class TrendChartBase extends React.Component { legendItem: { name: getCostRangeString( forecastConeData, - messages.chartCostForecastConeLegendLabel, + messages.chartCostForecastConeLabel, false, false, 0, - messages.chartCostForecastConeLegendNoDataLabel + messages.chartCostForecastConeLabelNoData ), symbol: { fill: chartStyles.forecastConeDataColorScale[0], type: 'triangleLeft', }, - tooltip: getCostRangeTooltip(forecastConeData, messages.chartCostForecastConeLegendTooltip, false, false), + tooltip: getCostRangeTooltip(forecastConeData, messages.chartCostForecastConeTooltip, false, false), }, style: { data: { diff --git a/src/routes/components/charts/usageChart/usageChart.tsx b/src/routes/components/charts/usageChart/usageChart.tsx index 0c34b6df4..74cb82b72 100644 --- a/src/routes/components/charts/usageChart/usageChart.tsx +++ b/src/routes/components/charts/usageChart/usageChart.tsx @@ -92,10 +92,10 @@ class UsageChartBase extends React.Component { private initDatum = () => { const { currentRequestData, currentUsageData, previousRequestData, previousUsageData } = this.props; - const usageKey = messages.chartUsageLegendLabel; - const usageTooltipKey = messages.chartUsageLegendTooltip; - const requestKey = messages.chartRequestsLegendLabel; - const requestTooltipKey = messages.chartRequestsLegendTooltip; + const usageKey = messages.chartUsageLabel; + const usageTooltipKey = messages.chartUsageTooltip; + const requestKey = messages.chartRequestsLabel; + const requestTooltipKey = messages.chartRequestsTooltip; // Show all legends, regardless of length -- https://github.com/project-koku/koku-ui/issues/248 @@ -104,7 +104,7 @@ class UsageChartBase extends React.Component { childName: 'previousUsage', data: previousUsageData, legendItem: { - name: getUsageRangeString(previousUsageData, usageKey, true, true, 1, messages.chartUsageLegendNoDataLabel), + name: getUsageRangeString(previousUsageData, usageKey, true, true, 1, messages.chartUsageLabelNoData), symbol: { fill: chartStyles.legendColorScale[0], type: 'minus', @@ -117,7 +117,7 @@ class UsageChartBase extends React.Component { childName: 'currentUsage', data: currentUsageData, legendItem: { - name: getUsageRangeString(currentUsageData, usageKey, true, false, 0, messages.chartUsageLegendNoDataLabel), + name: getUsageRangeString(currentUsageData, usageKey, true, false, 0, messages.chartUsageLabelNoData), symbol: { fill: chartStyles.legendColorScale[1], type: 'minus', @@ -130,14 +130,7 @@ class UsageChartBase extends React.Component { childName: 'previousRequest', data: previousRequestData, legendItem: { - name: getUsageRangeString( - previousRequestData, - requestKey, - true, - true, - 1, - messages.chartRequestsLegendNoDataLabel - ), + name: getUsageRangeString(previousRequestData, requestKey, true, true, 1, messages.chartRequestsLabelNoData), symbol: { fill: chartStyles.legendColorScale[2], type: 'dash', @@ -150,14 +143,7 @@ class UsageChartBase extends React.Component { childName: 'currentRequest', data: currentRequestData, legendItem: { - name: getUsageRangeString( - currentRequestData, - requestKey, - true, - false, - 0, - messages.chartRequestsLegendNoDataLabel - ), + name: getUsageRangeString(currentRequestData, requestKey, true, false, 0, messages.chartRequestsLabelNoData), symbol: { fill: chartStyles.legendColorScale[3], type: 'dash', diff --git a/src/routes/components/dataTable/dataTable.tsx b/src/routes/components/dataTable/dataTable.tsx index af3fe975f..4871f9f03 100644 --- a/src/routes/components/dataTable/dataTable.tsx +++ b/src/routes/components/dataTable/dataTable.tsx @@ -155,6 +155,7 @@ class DataTable extends React.Component { {row.cells.map((item, cellIndex) => cellIndex === 0 && isSelectable ? ( { /> ) : ( { - return anySelected ? ( - onBulkSelectToggle(!isBulkSelectOpen)}> - {intl.formatMessage(messages.selected, { value: numSelected })} - - ) : null; + const handleOnBulkSelectClicked = (checked: boolean) => { + if (onBulkSelectClicked) { + checked ? onBulkSelectClicked('all') : onBulkSelectClicked('none'); + } + onBulkSelectToggle(false); }; const toggle = toggleRef => { @@ -87,15 +84,13 @@ export const getBulkSelect = ({ anySelected ? messages.toolBarBulkSelectAriaDeselect : messages.toolBarBulkSelectAriaSelect )} isChecked={isChecked} - onChange={() => { - anySelected ? onBulkSelectClicked('none') : onBulkSelectClicked('all'); - }} - > - {getSelectedLabel()} - , + onChange={handleOnBulkSelectClicked} + />, ], }} - /> + > + {anySelected ? intl.formatMessage(messages.selected, { value: numSelected }) : null} + ); }; diff --git a/src/routes/components/dropdownWrapper/dropdownWrapper.tsx b/src/routes/components/dropdownWrapper/dropdownWrapper.tsx index b3be23a35..4b7eb9e35 100644 --- a/src/routes/components/dropdownWrapper/dropdownWrapper.tsx +++ b/src/routes/components/dropdownWrapper/dropdownWrapper.tsx @@ -1,8 +1,10 @@ import './dropdownWrapper.scss'; -import { Dropdown, DropdownItem, DropdownList, MenuToggle } from '@patternfly/react-core'; +import { Dropdown, DropdownItem, DropdownList, MenuToggle, Tooltip } from '@patternfly/react-core'; import { EllipsisVIcon } from '@patternfly/react-icons/dist/esm/icons/ellipsis-v-icon'; +import messages from 'locales/messages'; import React, { useState } from 'react'; +import { useIntl } from 'react-intl'; export interface DropdownWrapperItem { description?: string; // Item description @@ -33,6 +35,7 @@ const DropdownWrapper: React.FC = ({ placeholder = null, position, }) => { + const intl = useIntl(); const [isOpen, setIsOpen] = useState(false); const getDropdownItem = (item, index) => { @@ -58,17 +61,23 @@ const DropdownWrapper: React.FC = ({ setIsOpen(!isOpen); }; - const toggle = toggleRef => ( - - {isKebab ? : placeholder} - - ); + const toggle = toggleRef => { + const msg = intl.formatMessage(messages.moreOptions); + return ( + + + {isKebab ? : placeholder} + + + ); + }; return ( - - - - - diff --git a/src/routes/components/icons/optimizationIcon/index.ts b/src/routes/components/icons/optimizationIcon/index.ts deleted file mode 100644 index e7b5d2e6f..000000000 --- a/src/routes/components/icons/optimizationIcon/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as OptimizationIcon } from './optimizationIcon'; diff --git a/src/routes/components/icons/optimizationIcon/optimizationIcon.scss b/src/routes/components/icons/optimizationIcon/optimizationIcon.scss deleted file mode 100644 index 81d67d428..000000000 --- a/src/routes/components/icons/optimizationIcon/optimizationIcon.scss +++ /dev/null @@ -1,5 +0,0 @@ -@import url("~@patternfly/patternfly/base/patternfly-variables.css"); - -.optimization-icon { - height: 54px; -} diff --git a/src/routes/components/icons/optimizationIcon/optimizationIcon.tsx b/src/routes/components/icons/optimizationIcon/optimizationIcon.tsx deleted file mode 100644 index 9ebe127f2..000000000 --- a/src/routes/components/icons/optimizationIcon/optimizationIcon.tsx +++ /dev/null @@ -1,25 +0,0 @@ -import './optimizationIcon.scss'; - -import messages from 'locales/messages'; -import React from 'react'; -import type { WrappedComponentProps } from 'react-intl'; -import { injectIntl } from 'react-intl'; - -interface OptimizationIconProps extends WrappedComponentProps { - className?: string; -} - -const icon = require('./Red_Hat-IT_Optimization-Gray.svg'); - -const OptimizationIcon: React.FC = ({ className, intl }) => { - return ( - - ); -}; - -export default injectIntl(OptimizationIcon); diff --git a/src/routes/components/page/noInstances/index.ts b/src/routes/components/page/noInstances/index.ts new file mode 100644 index 000000000..8c0559e75 --- /dev/null +++ b/src/routes/components/page/noInstances/index.ts @@ -0,0 +1 @@ +export { default as NoInstances } from './noInstances'; diff --git a/src/routes/components/page/noOptimizations/noOptimizations.tsx b/src/routes/components/page/noInstances/noInstances.tsx similarity index 60% rename from src/routes/components/page/noOptimizations/noOptimizations.tsx rename to src/routes/components/page/noInstances/noInstances.tsx index 5fba9e195..627d33420 100644 --- a/src/routes/components/page/noOptimizations/noOptimizations.tsx +++ b/src/routes/components/page/noInstances/noInstances.tsx @@ -2,15 +2,15 @@ import { PageSection } from '@patternfly/react-core'; import { PageHeader, PageHeaderTitle } from '@redhat-cloud-services/frontend-components/PageHeader'; import React from 'react'; -import { NoOptimizationsState } from './noOptimizationsState'; +import { NoInstancesState } from './noInstancesState'; -interface NoProvidersOwnProps { +interface NoInstancesOwnProps { title?: string; } -type NoProvidersProps = NoProvidersOwnProps; +type NoInstancesProps = NoInstancesOwnProps; -const NoOptimizations = ({ title }: NoProvidersProps) => { +const NoInstances = ({ title }: NoInstancesProps) => { return ( <> {title && ( @@ -19,10 +19,10 @@ const NoOptimizations = ({ title }: NoProvidersProps) => { )} - + ); }; -export default NoOptimizations; +export default NoInstances; diff --git a/src/routes/components/page/noInstances/noInstancesState.tsx b/src/routes/components/page/noInstances/noInstancesState.tsx new file mode 100644 index 000000000..4a242d7b3 --- /dev/null +++ b/src/routes/components/page/noInstances/noInstancesState.tsx @@ -0,0 +1,39 @@ +import { + EmptyState, + EmptyStateBody, + EmptyStateHeader, + EmptyStateIcon, + EmptyStateVariant, +} from '@patternfly/react-core'; +import { PlusCircleIcon } from '@patternfly/react-icons/dist/esm/icons/plus-circle-icon'; +import messages from 'locales/messages'; +import React from 'react'; +import type { WrappedComponentProps } from 'react-intl'; +import { injectIntl } from 'react-intl'; + +interface NoInstancesStateOwnProps { + // TBD... +} + +type NoInstancesStateProps = NoInstancesStateOwnProps & WrappedComponentProps; + +class NoInstancesStateBase extends React.Component { + public render() { + const { intl } = this.props; + + return ( + + } + headingLevel="h1" + /> + {intl.formatMessage(messages.noInstancesDesc)} + + ); + } +} + +const NoInstancesState = injectIntl(NoInstancesStateBase); + +export { NoInstancesState }; diff --git a/src/routes/components/page/noOptimizations/index.ts b/src/routes/components/page/noOptimizations/index.ts deleted file mode 100644 index a9e1caa71..000000000 --- a/src/routes/components/page/noOptimizations/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as NoOptimizations } from './noOptimizations'; diff --git a/src/routes/components/page/noOptimizations/noOptimizationsState.tsx b/src/routes/components/page/noOptimizations/noOptimizationsState.tsx deleted file mode 100644 index 4b78a7148..000000000 --- a/src/routes/components/page/noOptimizations/noOptimizationsState.tsx +++ /dev/null @@ -1,39 +0,0 @@ -import { - EmptyState, - EmptyStateBody, - EmptyStateHeader, - EmptyStateIcon, - EmptyStateVariant, -} from '@patternfly/react-core'; -import messages from 'locales/messages'; -import React from 'react'; -import type { WrappedComponentProps } from 'react-intl'; -import { injectIntl } from 'react-intl'; -import { OptimizationIcon } from 'routes/components/icons/optimizationIcon'; - -interface NoOptimizationsStateOwnProps { - // TBD... -} - -type NoOptimizationsStateProps = NoOptimizationsStateOwnProps & WrappedComponentProps; - -class NoOptimizationsStateBase extends React.Component { - public render() { - const { intl } = this.props; - - return ( - - } - headingLevel="h1" - /> - {intl.formatMessage(messages.noOptimizationsDesc)} - - ); - } -} - -const NoOptimizationsState = injectIntl(NoOptimizationsStateBase); - -export { NoOptimizationsState }; diff --git a/src/routes/components/selectWrapper/selectWrapper.tsx b/src/routes/components/selectWrapper/selectWrapper.tsx index 27f5245c6..42478553d 100644 --- a/src/routes/components/selectWrapper/selectWrapper.tsx +++ b/src/routes/components/selectWrapper/selectWrapper.tsx @@ -12,30 +12,40 @@ export interface SelectWrapperOption { } interface SelectWrapperOwnProps { + appendTo?: HTMLElement | (() => HTMLElement) | 'inline' | 'parent'; ariaLabel?: string; className?: string; + direction?: 'up' | 'down'; id?: string; isDisabled?: boolean; + maxMenuHeight?: string; onSelect?: (event, value: SelectWrapperOption) => void; placeholder?: string; options?: SelectWrapperOption[]; position?: 'right' | 'left' | 'center' | 'start' | 'end'; selection?: string | SelectWrapperOption; + status?: 'success' | 'warning' | 'danger'; + toggleAriaLabel?: string; toggleIcon?: React.ReactNode; } type SelectWrapperProps = SelectWrapperOwnProps; const SelectWrapper: React.FC = ({ + appendTo, ariaLabel, className, + direction, id, isDisabled, + maxMenuHeight, onSelect = () => {}, options, placeholder = null, position, selection, + status, + toggleAriaLabel, toggleIcon, }) => { const [isOpen, setIsOpen] = useState(false); @@ -72,28 +82,34 @@ const SelectWrapper: React.FC = ({ const toggle = toggleRef => ( {toggleIcon}} isDisabled={isDisabled} isExpanded={isOpen} + isFullWidth onClick={handleOnToggle} ref={toggleRef} + status={status} > {getPlaceholder()} ); return ( -
+
{ - setSelection(sel); - onChange(null, sel.value); - setIsOpen(false); - }} - onToggle={() => setIsOpen(!isOpen)} - selections={selection} - validated={isInvalid ? 'error' : 'default'} - > - {getSelectorOptions().map(opt => ( - - ))} - + /> {isInvalid && typeof helpText === 'object' && ( {intl.formatMessage(helpText)} diff --git a/src/routes/settings/costModels/components/rateForm/rateForm.tsx b/src/routes/settings/costModels/components/rateForm/rateForm.tsx index 69ec14508..cf0f47f4b 100644 --- a/src/routes/settings/costModels/components/rateForm/rateForm.tsx +++ b/src/routes/settings/costModels/components/rateForm/rateForm.tsx @@ -113,7 +113,7 @@ const RateFormBase: React.FC = ({ currencyUnits, intl = defaultIn label={intl.formatMessage(messages.metric)} placeholderText={intl.formatMessage(messages.select)} value={metric} - onChange={(_evt, value) => setMetric(value)} + onSelect={(_evt, value) => setMetric(value)} options={[ ...metricOptions.map(opt => { return { @@ -140,8 +140,8 @@ const RateFormBase: React.FC = ({ currencyUnits, intl = defaultIn ? measurement : getMeasurementLabel(measurement, metricsHash[metric][measurement].label_measurement_unit) } - onChange={(_evt, value) => setMeasurement(value)} - placeholderText="Select..." + onSelect={(_evt, value) => setMeasurement(value)} + placeholderText={intl.formatMessage(messages.select)} options={[ ...measurementOptions.map(opt => { const unit = metricsHash[metric][opt].label_measurement_unit; diff --git a/src/routes/settings/costModels/components/rateForm/utils.tsx b/src/routes/settings/costModels/components/rateForm/utils.tsx index a4f7ad582..1952cb985 100644 --- a/src/routes/settings/costModels/components/rateForm/utils.tsx +++ b/src/routes/settings/costModels/components/rateForm/utils.tsx @@ -173,7 +173,9 @@ export const mergeToRequest = ( description: costModel.description, distribution_info: { distribution_type: costModel.distribution_info ? costModel.distribution_info.distribution_type : undefined, + network_cost: costModel.distribution_info ? costModel.distribution_info.network_cost : undefined, platform_cost: costModel.distribution_info ? costModel.distribution_info.platform_cost : undefined, + storage_cost: costModel.distribution_info ? costModel.distribution_info.storage_cost : undefined, worker_cost: costModel.distribution_info ? costModel.distribution_info.worker_cost : undefined, }, source_uuids: costModel.sources.map(src => src.uuid), diff --git a/src/routes/settings/costModels/components/rateTable.tsx b/src/routes/settings/costModels/components/rateTable.tsx index da0cc9f57..5bbc3063f 100644 --- a/src/routes/settings/costModels/components/rateTable.tsx +++ b/src/routes/settings/costModels/components/rateTable.tsx @@ -1,3 +1,4 @@ +import { Tooltip } from '@patternfly/react-core'; import type { IActions, ThProps } from '@patternfly/react-table'; import { ActionsColumn, @@ -149,16 +150,18 @@ const RateTableBase: React.FC = ({ ))} {!!actions.length && ( - { - return { - ...a, - onClick: () => { - a.onClick(null, rowIndex, row, null); - }, - }; - })} - /> + + { + return { + ...a, + onClick: () => { + a.onClick(null, rowIndex, row, null); + }, + }; + })} + /> + )} diff --git a/src/routes/settings/costModels/costModel/addRateModal.tsx b/src/routes/settings/costModels/costModel/addRateModal.tsx index d13ac5fcd..335c6de4e 100644 --- a/src/routes/settings/costModels/costModel/addRateModal.tsx +++ b/src/routes/settings/costModels/costModel/addRateModal.tsx @@ -60,6 +60,7 @@ export const AddRateModalBase: React.FC = ({ return ( = ({ isUpdateDialogOpen, }) => { const intl = useIntl(); + const isOcpCloudNetworkingToggleEnabled = useIsOcpCloudNetworkingToggleEnabled(); + const isOcpProjectStorageToggleEnabled = useIsOcpProjectStorageToggleEnabled(); return ( <> @@ -62,17 +65,33 @@ const DistributionCardBase: React.FC = ({ })}
- {intl.formatMessage(messages.distributeCosts, { + {intl.formatMessage(messages.distributeUnallocatedCapacity, { value: current.distribution_info.platform_cost, type: 'platform', })}
- {intl.formatMessage(messages.distributeCosts, { + {intl.formatMessage(messages.distributeUnallocatedCapacity, { value: current.distribution_info.worker_cost, type: 'worker', })}
+ {isOcpCloudNetworkingToggleEnabled && ( +
+ {intl.formatMessage(messages.distributeCosts, { + value: current.distribution_info.network_cost || false, + type: 'network', + })} +
+ )} + {isOcpProjectStorageToggleEnabled && ( +
+ {intl.formatMessage(messages.distributeCosts, { + value: current.distribution_info.storage_cost || false, + type: 'storage', + })} +
+ )} diff --git a/src/routes/settings/costModels/costModel/updateCostModel.tsx b/src/routes/settings/costModels/costModel/updateCostModel.tsx index 54e961278..27a373d66 100644 --- a/src/routes/settings/costModels/costModel/updateCostModel.tsx +++ b/src/routes/settings/costModels/costModel/updateCostModel.tsx @@ -146,10 +146,10 @@ class UpdateCostModelBase extends React.Component this.setState({ currency: value })} + onSelect={(_evt, value) => this.setState({ currency: value })} id="currency-units-selector" options={currencyOptions.map(o => { return { diff --git a/src/routes/settings/costModels/costModel/updateDistributionDialog.tsx b/src/routes/settings/costModels/costModel/updateDistributionDialog.tsx index 9f087123a..1ef01e463 100644 --- a/src/routes/settings/costModels/costModel/updateDistributionDialog.tsx +++ b/src/routes/settings/costModels/costModel/updateDistributionDialog.tsx @@ -21,6 +21,7 @@ import { injectIntl } from 'react-intl'; import { connect } from 'react-redux'; import { createMapStateToProps } from 'store/common'; import { costModelsActions, costModelsSelectors } from 'store/costModels'; +import { FeatureToggleSelectors } from 'store/featureToggle'; import { styles } from './costCalc.styles'; @@ -31,6 +32,8 @@ interface UpdateDistributionDialogOwnProps extends WrappedComponentProps { interface UpdateDistributionDialogStateProps { error?: string; isLoading?: boolean; + isOcpCloudNetworkingToggleEnabled?: boolean; + isOcpProjectStorageToggleEnabled?: boolean; } interface UpdateDistributionDialogDispatchProps { @@ -40,7 +43,9 @@ interface UpdateDistributionDialogDispatchProps { interface UpdateDistributionDialogState { distribution?: string; + distributeNetwork?: boolean; distributePlatformUnallocated?: boolean; + distributeStorage?: boolean; distributeWorkerUnallocated?: boolean; } @@ -56,7 +61,9 @@ class UpdateDistributionDialogBase extends React.Component< super(props); this.state = { distribution: this.props.current.distribution_info.distribution_type, + distributeNetwork: this.props.current.distribution_info.network_cost === true, distributePlatformUnallocated: this.props.current.distribution_info.platform_cost === true, + distributeStorage: this.props.current.distribution_info.storage_cost === true, distributeWorkerUnallocated: this.props.current.distribution_info.worker_cost === true, }; } @@ -76,8 +83,27 @@ class UpdateDistributionDialogBase extends React.Component< this.setState({ distributeWorkerUnallocated: value === 'true' }); }; + private handleDistributeNetworkChange = event => { + const { value } = event.currentTarget; + this.setState({ distributeNetwork: value === 'true' }); + }; + + private handleDistributeStorageChange = event => { + const { value } = event.currentTarget; + this.setState({ distributeStorage: value === 'true' }); + }; + public render() { - const { error, current, intl, isLoading, onClose, updateCostModel } = this.props; + const { + error, + current, + intl, + isLoading, + isOcpCloudNetworkingToggleEnabled, + isOcpProjectStorageToggleEnabled, + onClose, + updateCostModel, + } = this.props; return ( + {isOcpCloudNetworkingToggleEnabled && ( + <> + + + {intl.formatMessage(messages.network)} + + + {intl.formatMessage(messages.networkDesc)} + + + +
+ + + + +
+
+ + )} + {isOcpProjectStorageToggleEnabled && ( + <> + + + {intl.formatMessage(messages.storage)} + + + {intl.formatMessage(messages.storageDesc)} + + + +
+ + + + +
+
+ + )}
); @@ -228,6 +328,8 @@ const mapStateToProps = createMapStateToProps { return { isLoading: costModelsSelectors.updateProcessing(state), + isOcpCloudNetworkingToggleEnabled: FeatureToggleSelectors.selectIsOcpCloudNetworkingToggleEnabled(state), + isOcpProjectStorageToggleEnabled: FeatureToggleSelectors.selectIsOcpProjectStorageToggleEnabled(state), error: costModelsSelectors.updateError(state), }; } diff --git a/src/routes/settings/costModels/costModel/updateRateModel.test.tsx b/src/routes/settings/costModels/costModel/updateRateModel.test.tsx index f0472967e..060c62196 100644 --- a/src/routes/settings/costModels/costModel/updateRateModel.test.tsx +++ b/src/routes/settings/costModels/costModel/updateRateModel.test.tsx @@ -267,13 +267,17 @@ describe('update-rate', () => { test('Description', async () => { const user = userEvent.setup({ advanceTimers: jest.advanceTimersByTime }); + render(); + const descInput = screen.getByDisplayValue('openshift-aws-node'); const saveButton = screen.getByText(regExp(messages.save)); expect(saveButton.getAttribute('disabled')).not.toBeNull(); + await act(async () => user.clear(descInput)); await act(async () => user.type(descInput, 'a new description')); expect(saveButton.getAttribute('disabled')).toBeNull(); + await act(async () => user.clear(descInput)); await act(async () => user.type(descInput, 'openshift-aws-node')); expect(saveButton.getAttribute('disabled')).not.toBeNull(); @@ -282,7 +286,9 @@ describe('update-rate', () => { test('Select Measurement', async () => { const user = userEvent.setup({ advanceTimers: jest.advanceTimersByTime }); let options = null; + render(); + const saveButton = screen.getByText(regExp(messages.save)); await act(async () => user.click(screen.getByLabelText('Select Measurement'))); @@ -303,7 +309,7 @@ describe('update-rate', () => { await act(async () => user.click(screen.getByLabelText('Select Measurement'))); options = await screen.findAllByRole('option'); - await act(async () => user.click(options[0])); + await act(async () => user.click(options[5])); // Previous select options are not being removed from page expect(saveButton.getAttribute('disabled')).toBeNull(); @@ -316,7 +322,7 @@ describe('update-rate', () => { await act(async () => user.click(options[0])); expect(saveButton.getAttribute('disabled')).not.toBeNull(); - }); + }, 10000); test('regular', async () => { const user = userEvent.setup({ advanceTimers: jest.advanceTimersByTime }); diff --git a/src/routes/settings/costModels/costModel/updateRateModel.tsx b/src/routes/settings/costModels/costModel/updateRateModel.tsx index f8ce9511e..b57dcf706 100644 --- a/src/routes/settings/costModels/costModel/updateRateModel.tsx +++ b/src/routes/settings/costModels/costModel/updateRateModel.tsx @@ -99,8 +99,10 @@ const UpdateRateModalBase: React.FC = ({ ) ); }, [isOpen]); + return ( = ({ key="proceed" variant="primary" onClick={onProceed} - isDisabled={!canSubmit || isProcessing || !gotDiffs} + isDisabled={isProcessing || !canSubmit || !gotDiffs} > {intl.formatMessage(messages.save)} , diff --git a/src/routes/settings/costModels/costModelWizard/context.ts b/src/routes/settings/costModels/costModelWizard/context.ts index 8af17a7aa..501643864 100644 --- a/src/routes/settings/costModels/costModelWizard/context.ts +++ b/src/routes/settings/costModels/costModelWizard/context.ts @@ -15,7 +15,9 @@ export const defaultCostModelContext = { description: '', dirtyName: false, distribution: '', + distributeNetwork: true, distributePlatformUnallocated: true, + distributeStorage: true, distributeWorkerUnallocated: true, error: null, fetchSources: (type: string, query: any, page: number, perPage: number) => null, @@ -24,7 +26,9 @@ export const defaultCostModelContext = { isDiscount: false, handleMarkupDiscountChange: (...args: any[]) => null, handleDistributionChange: (...args: any[]) => null, + handleDistributeNetworkChange: (...args: any[]) => null, handleDistributePlatformUnallocatedChange: (...args: any[]) => null, + handleDistributeStorageChange: (...args: any[]) => null, handleDistributeWorkerUnallocatedChange: (...args: any[]) => null, handleSignChange: (...args: any[]) => null, loading: false, diff --git a/src/routes/settings/costModels/costModelWizard/costModelWizard.tsx b/src/routes/settings/costModels/costModelWizard/costModelWizard.tsx index 76a0bae82..d5dfea849 100644 --- a/src/routes/settings/costModels/costModelWizard/costModelWizard.tsx +++ b/src/routes/settings/costModels/costModelWizard/costModelWizard.tsx @@ -93,6 +93,7 @@ const InternalWizardBase: React.FC = ({ return isOpen ? ( = ({ currency, description, distribution, + distributeNetwork, distributePlatformUnallocated, + distributeStorage, distributeWorkerUnallocated, isDiscount, markup, @@ -124,7 +127,9 @@ const InternalWizardBase: React.FC = ({ description, distribution_info: { distribution_type: distribution, + network_cost: distributeNetwork, platform_cost: distributePlatformUnallocated, + storage_cost: distributeStorage, worker_cost: distributeWorkerUnallocated, }, rates: tiers, @@ -165,7 +170,9 @@ interface CostModelWizardState { description?: string; dirtyName?: boolean; distribution?: string; + distributeNetwork?: boolean; distributePlatformUnallocated?: boolean; + distributeStorage?: boolean; distributeWorkerUnallocated?: boolean; error?: any; filterName?: string; @@ -206,7 +213,9 @@ class CostModelWizardBase extends React.Component { + const { value } = event.currentTarget; + this.setState({ distributeNetwork: value === 'true' }); + }, handleDistributePlatformUnallocatedChange: event => { const { value } = event.currentTarget; this.setState({ distributePlatformUnallocated: value === 'true' }); }, + handleDistributeStorageChange: event => { + const { value } = event.currentTarget; + this.setState({ distributeStorage: value === 'true' }); + }, handleDistributeWorkerUnallocatedChange: event => { const { value } = event.currentTarget; this.setState({ distributeWorkerUnallocated: value === 'true' }); @@ -530,7 +549,9 @@ class CostModelWizardBase extends React.Component { public render() { - const { intl } = this.props; + const { isOcpCloudNetworkingToggleEnabled, isOcpProjectStorageToggleEnabled, intl } = this.props; return ( {({ handleDistributionChange, + handleDistributeNetworkChange, handleDistributePlatformUnallocatedChange, + handleDistributeStorageChange, handleDistributeWorkerUnallocatedChange, distribution, + distributeNetwork, distributePlatformUnallocated, + distributeStorage, distributeWorkerUnallocated, }) => { return ( @@ -57,7 +63,7 @@ class DistributionBase extends React.Component + {isOcpCloudNetworkingToggleEnabled && ( + <> + + + {intl.formatMessage(messages.network)} + + + {intl.formatMessage(messages.networkDesc)} + + + +
+ + + + +
+
+ + )} + {isOcpProjectStorageToggleEnabled && ( + <> + + + {intl.formatMessage(messages.storage)} + + + {intl.formatMessage(messages.storageDesc)} + + + +
+ + + + +
+
+ + )} ); }} @@ -148,9 +226,10 @@ class DistributionBase extends React.Component(() => { +const mapStateToProps = createMapStateToProps(state => { return { - // TBD... + isOcpCloudNetworkingToggleEnabled: FeatureToggleSelectors.selectIsOcpCloudNetworkingToggleEnabled(state), + isOcpProjectStorageToggleEnabled: FeatureToggleSelectors.selectIsOcpProjectStorageToggleEnabled(state), }; }); diff --git a/src/routes/settings/costModels/costModelWizard/generalInformation.tsx b/src/routes/settings/costModels/costModelWizard/generalInformation.tsx index 2ec099b61..2ff795329 100644 --- a/src/routes/settings/costModels/costModelWizard/generalInformation.tsx +++ b/src/routes/settings/costModels/costModelWizard/generalInformation.tsx @@ -133,22 +133,22 @@ class GeneralInformation extends React.Component { id="source-type-selector" direction="up" appendMenuTo="inline" - maxHeight={styles.selector.maxHeight} + maxMenuHeight={styles.selector.maxHeight as string} label={messages.sourceType} toggleAriaLabel={intl.formatMessage(messages.costModelsWizardEmptySourceTypeLabel)} placeholderText={intl.formatMessage(messages.costModelsWizardEmptySourceTypeLabel)} value={getValueLabel(type, sourceTypeOptions)} - onChange={(_evt, value) => onTypeChange(value)} + onSelect={(_evt, value) => onTypeChange(value)} options={sourceTypeOptions} /> onCurrencyChange(value)} + onSelect={(_evt, value) => onCurrencyChange(value)} id="currency-units-selector" options={currencyOptions.map(o => { return { diff --git a/src/routes/settings/costModels/costModelWizard/review.tsx b/src/routes/settings/costModels/costModelWizard/review.tsx index 338fee686..bccbc52ac 100644 --- a/src/routes/settings/costModels/costModelWizard/review.tsx +++ b/src/routes/settings/costModels/costModelWizard/review.tsx @@ -28,6 +28,7 @@ import { connect } from 'react-redux'; import { RateTable } from 'routes/settings/costModels/components/rateTable'; import { WarningIcon } from 'routes/settings/costModels/components/warningIcon'; import { createMapStateToProps } from 'store/common'; +import { FeatureToggleSelectors } from 'store/featureToggle'; import { CostModelContext } from './context'; @@ -66,12 +67,17 @@ interface ReviewDetailsOwnProps extends WrappedComponentProps { } interface ReviewDetailsStateProps { - // TBD... + isOcpCloudNetworkingToggleEnabled?: boolean; + isOcpProjectStorageToggleEnabled?: boolean; } type ReviewDetailsProps = ReviewDetailsOwnProps & ReviewDetailsStateProps; -const ReviewDetailsBase: React.FC = ({ intl }) => ( +const ReviewDetailsBase: React.FC = ({ + intl, + isOcpCloudNetworkingToggleEnabled, + isOcpProjectStorageToggleEnabled, +}) => ( {({ checked, @@ -79,7 +85,9 @@ const ReviewDetailsBase: React.FC = ({ intl }) => ( currencyUnits, description, distribution, + distributeNetwork, distributePlatformUnallocated, + distributeStorage, distributeWorkerUnallocated, isDiscount, markup, @@ -155,17 +163,33 @@ const ReviewDetailsBase: React.FC = ({ intl }) => ( {intl.formatMessage(messages.distributionTypeDesc, { type: distribution })} - {intl.formatMessage(messages.distributeCosts, { + {intl.formatMessage(messages.distributeUnallocatedCapacity, { value: distributePlatformUnallocated, type: 'platform', })} - {intl.formatMessage(messages.distributeCosts, { + {intl.formatMessage(messages.distributeUnallocatedCapacity, { value: distributeWorkerUnallocated, type: 'worker', })} + {isOcpCloudNetworkingToggleEnabled && ( + + {intl.formatMessage(messages.distributeCosts, { + value: distributeNetwork, + type: 'network', + })} + + )} + {isOcpProjectStorageToggleEnabled && ( + + {intl.formatMessage(messages.distributeCosts, { + value: distributeStorage, + type: 'storage', + })} + + )} )} @@ -187,9 +211,10 @@ const ReviewDetailsBase: React.FC = ({ intl }) => ( ); -const mapStateToProps = createMapStateToProps(() => { +const mapStateToProps = createMapStateToProps(state => { return { - // TBD... + isOcpCloudNetworkingToggleEnabled: FeatureToggleSelectors.selectIsOcpCloudNetworkingToggleEnabled(state), + isOcpProjectStorageToggleEnabled: FeatureToggleSelectors.selectIsOcpProjectStorageToggleEnabled(state), }; }); diff --git a/src/routes/settings/platformProjects/platformProjects.scss b/src/routes/settings/platformProjects/platformProjects.scss new file mode 100644 index 000000000..31a1a9a99 --- /dev/null +++ b/src/routes/settings/platformProjects/platformProjects.scss @@ -0,0 +1,10 @@ +@media only screen and (min-width: 1450px) { + .pf-v5-c-table__td { + &.defaultColumn { + width: 70%; + } + &.groupColumn { + width: 20%; + } + } +} diff --git a/src/routes/settings/platformProjects/platformProjects.styles.ts b/src/routes/settings/platformProjects/platformProjects.styles.ts index 87c471d9e..19d3215ba 100644 --- a/src/routes/settings/platformProjects/platformProjects.styles.ts +++ b/src/routes/settings/platformProjects/platformProjects.styles.ts @@ -6,21 +6,12 @@ export const styles = { action: { marginLeft: global_spacer_md.var, }, - defaultColumn: { - width: '20%', - }, descContainer: { backgroundColor: global_BackgroundColor_light_100.value, paddingLeft: global_spacer_md.value, paddingRight: global_spacer_md.value, paddingTop: global_spacer_md.value, }, - groupColumn: { - width: '20%', - }, - nameColumn: { - width: '1%', - }, pagination: { backgroundColor: global_BackgroundColor_light_100.value, paddingBottom: global_spacer_md.value, diff --git a/src/routes/settings/platformProjects/platformProjectsTable.tsx b/src/routes/settings/platformProjects/platformProjectsTable.tsx index 8e0458385..fd6633591 100644 --- a/src/routes/settings/platformProjects/platformProjectsTable.tsx +++ b/src/routes/settings/platformProjects/platformProjectsTable.tsx @@ -1,4 +1,5 @@ import 'routes/components/dataTable/dataTable.scss'; +import './platformProjects.scss'; import { Label } from '@patternfly/react-core'; import type { Settings, SettingsData } from 'api/settings'; @@ -8,8 +9,6 @@ import { useIntl } from 'react-intl'; import { Cluster } from 'routes/components/cluster'; import { DataTable } from 'routes/components/dataTable'; -import { styles } from './platformProjects.styles'; - interface PlatformProjectsTableOwnProps { canWrite?: boolean; filterBy?: any; @@ -75,17 +74,17 @@ const PlatformProjectsTable: React.FC = ({ {}, // Empty cell for row selection { value: item.project ? item.project : '', - style: styles.nameColumn, }, { + className: 'defaultColumn', value: item.default ? : null, }, { + className: 'groupColumn', value: item.group === 'Platform' ? : null, - style: styles.defaultColumn, }, - { value: , style: styles.groupColumn }, + { value: }, ], item, selected: selectedItems && selectedItems.find(val => val.project === item.project) !== undefined, diff --git a/src/routes/settings/settings.tsx b/src/routes/settings/settings.tsx index 43a15d510..8dd92effc 100644 --- a/src/routes/settings/settings.tsx +++ b/src/routes/settings/settings.tsx @@ -19,7 +19,6 @@ import { PlatformProjects } from 'routes/settings/platformProjects'; import { TagLabels } from 'routes/settings/tagLabels'; import type { RootState } from 'store'; import { FetchStatus } from 'store/common'; -import { FeatureToggleSelectors } from 'store/featureToggle'; import { userAccessQuery, userAccessSelectors } from 'store/userAccess'; import type { ChromeComponentProps } from 'utils/chrome'; import { withChrome } from 'utils/chrome'; @@ -67,7 +66,6 @@ export interface SettingsMapProps { } export interface SettingsStateProps { - isSettingsPlatformEnabled?: boolean; userAccess: UserAccess; userAccessError: AxiosError; userAccessFetchStatus: FetchStatus; @@ -78,7 +76,7 @@ type SettingsProps = SettingsOwnProps; const Settings: React.FC = () => { const [activeTabKey, setActiveTabKey] = useState(0); - const { isSettingsPlatformEnabled, userAccess, userAccessFetchStatus } = useMapToProps(); + const { userAccess, userAccessFetchStatus } = useMapToProps(); const intl = useIntl(); const canWrite = () => { @@ -108,13 +106,11 @@ const Settings: React.FC = () => { contentRef: React.createRef(), tab: SettingsTab.costCategory, }, - ]; - if (isSettingsPlatformEnabled) { - availableTabs.push({ + { contentRef: React.createRef(), tab: SettingsTab.platformProjects, - }); - } + }, + ]; return availableTabs; }; @@ -236,9 +232,6 @@ const useMapToProps = (): SettingsStateProps => { ); return { - isSettingsPlatformEnabled: useSelector((state: RootState) => - FeatureToggleSelectors.selectIsSettingsPlatformToggleEnabled(state) - ), userAccess, userAccessError, userAccessFetchStatus, diff --git a/src/routes/settings/tagLabels/tagLabels.tsx b/src/routes/settings/tagLabels/tagLabels.tsx index 1325395d8..b11c7e622 100644 --- a/src/routes/settings/tagLabels/tagLabels.tsx +++ b/src/routes/settings/tagLabels/tagLabels.tsx @@ -1,5 +1,4 @@ import { Accordion, AccordionContent, AccordionItem, AccordionToggle, PageSection } from '@patternfly/react-core'; -import { useIsTagMappingToggleEnabled } from 'components/featureToggle'; import messages from 'locales/messages'; import React, { useState } from 'react'; import { useIntl } from 'react-intl'; @@ -36,7 +35,6 @@ type TagLabelsProps = TagLabelsOwnProps; const TagLabels: React.FC = ({ canWrite }) => { const [activeKey, setActiveKey] = useState(0); - const isTagMappingToggleEnabled = useIsTagMappingToggleEnabled(); const intl = useIntl(); const getAvailableItems = () => { @@ -104,11 +102,7 @@ const TagLabels: React.FC = ({ canWrite }) => { return (
- {isTagMappingToggleEnabled ? ( - {getAccordionItem(availableItems)} - ) : ( - - )} + {getAccordionItem(availableItems)}
); diff --git a/src/routes/utils/computedReport/getComputedReportItems.ts b/src/routes/utils/computedReport/getComputedReportItems.ts index 3fd3fa97b..80223c67d 100644 --- a/src/routes/utils/computedReport/getComputedReportItems.ts +++ b/src/routes/utils/computedReport/getComputedReportItems.ts @@ -50,6 +50,7 @@ export interface ComputedReportItem extends ComputedReportOcpItem, ComputedRepor export interface ComputedReportItemsParams { idKey: keyof T; isDateMap?: boolean; + isGroupBy?: boolean; report: R; sortKey?: keyof ComputedReportItem; sortDirection?: SortDirection; @@ -156,6 +157,10 @@ function getCostData(val, key, item?: any) { : defaultUnits, }, }), + ...(val.cost && { + value: val.cost.value + (item?.cost ? item.cost.value : 0), + units: val.cost.units ? val.cost.units : defaultUnits, + }), }; } @@ -209,9 +214,10 @@ function getUsageData(val, item?: any) { // Details pages typically use this function with filter[resolution]=monthly export function getUnsortedComputedReportItems({ + idKey, // Note: The idKey must use org_entities for reports, while group_by uses org_unit_id isDateMap = false, + isGroupBy = true, report, - idKey, // Note: The idKey must use org_entities for reports, while group_by uses org_unit_id }: ComputedReportItemsParams) { if (!report) { return []; @@ -223,133 +229,36 @@ export function getUnsortedComputedReportItems { const type = dataPoint.type; // Org unit type - if (dataPoint && dataPoint.values) { - dataPoint.values.forEach((val: any) => { - let id = val.id ? val.id : val[idKey]; - if (!id) { - id = val.date; - } - - // Ensure unique map IDs -- https://github.com/project-koku/koku-ui/issues/706 - const idSuffix = idKey !== 'date' && idKey !== 'cluster' && val.cluster ? `-${val.cluster}` : ''; - const mapId = `${id}${idSuffix}`; - - // 'clusters' will contain either the cluster alias or default cluster ID - const classification = val.classification; - const cluster_alias = val.clusters && val.clusters.length > 0 ? val.clusters[0] : undefined; - const cluster = cluster_alias || val.cluster; - const date = val.date; - const default_project = val.default_project && val.default_project.toLowerCase() === 'true'; - const delta_percent = val.delta_percent ? val.delta_percent : 0; - const delta_value = val.delta_value ? val.delta_value : 0; - const persistent_volume_claim = val.persistent_volume_claim ? val.persistent_volume_claim : []; - const storage_class = val.storage_class ? val.storage_class : []; - const source_uuid = val.source_uuid ? val.source_uuid : []; - - let label; - if (report.meta && report.meta.others && (id === 'Other' || id === 'Others')) { - // Add count to "Others" label - label = intl.formatMessage(messages.chartOthers, { count: report.meta.others }); - } else { - const itemLabelKey = getItemLabel({ report, idKey, value: val }); - if (itemLabelKey === 'org_entities' && val.alias) { - label = val.alias; - } else if (itemLabelKey === 'account' && val.account_alias) { - label = val.account_alias; - } else if (itemLabelKey === 'cluster' && cluster_alias) { - label = cluster_alias; - } else if (itemLabelKey === 'subscription_guid' && val.subscription_name) { - label = val.subscription_name; - } else if (val[itemLabelKey] instanceof Object) { - label = val[itemLabelKey].value; - } else { - label = val[itemLabelKey]; - } - if (label === undefined || label.trim().length === 0) { - label = val.alias && val.alias.trim().length > 0 ? val.alias : val[idKey]; - } + if (isGroupBy) { + dataPoint?.values?.forEach((val: any) => { + initReportItems({ + idKey, + isDateMap, + itemMap, + report, + type, + val, + }); + }); + for (const key in dataPoint) { + if (dataPoint[key] instanceof Array) { + return dataPoint[key].forEach(visitDataPoint); } - - if (isDateMap) { - const data = { - ...getUsageData(val), // capacity, limit, request, & usage - classification, - cluster, - clusters: getClusters(val), - cost: getCostData(val, 'cost'), - date, - default_project, - delta_percent, - delta_value, - id, - infrastructure: getCostData(val, 'infrastructure'), - label, - persistent_volume_claim, - source_uuid, - storage_class, - supplementary: getCostData(val, 'supplementary'), - type, - }; - const item = itemMap.get(mapId); - if (item) { - item.set(date, data); - } else { - const dateMap = new Map(); - dateMap.set(date, data); - itemMap.set(mapId, dateMap); - } - } else { - const item = itemMap.get(mapId); - if (item) { - // When applying multiple group_by params, costs may be split between regions. We need to sum those costs - // See https://issues.redhat.com/browse/COST-1131 - itemMap.set(mapId, { - ...item, - ...getUsageData(val, item), // capacity, limit, request, & usage - classification, - cluster, - clusters: getClusters(val, item), - cost: getCostData(val, 'cost', item), - date, - default_project, - delta_percent, - delta_value, - id, - infrastructure: getCostData(val, 'infrastructure', item), - label, - persistent_volume_claim, - source_uuid, - storage_class, - supplementary: getCostData(val, 'supplementary', item), - type, - }); - } else { - itemMap.set(mapId, { - ...getUsageData(val), // capacity, limit, request, & usage - classification, - cluster, - clusters: getClusters(val), - cost: getCostData(val, 'cost'), - date, - default_project, - delta_percent, - delta_value, - id, - infrastructure: getCostData(val, 'infrastructure'), - label, - persistent_volume_claim, - source_uuid, - storage_class, - supplementary: getCostData(val, 'supplementary'), + } + } else { + for (const key in dataPoint) { + if (dataPoint[key] instanceof Array) { + dataPoint[key].forEach(val => { + initReportItems({ + idKey, + isDateMap, + itemMap, + report, type, + val, }); - } + }); } - }); - } - for (const key in dataPoint) { - if (dataPoint[key] instanceof Array) { - return dataPoint[key].forEach(visitDataPoint); } } }; @@ -358,3 +267,105 @@ export function getUnsortedComputedReportItems 0 ? val.clusters[0] : undefined; + const cluster = cluster_alias || val.cluster; + const date = val.date; + const default_project = val.default_project && val.default_project.toLowerCase() === 'true'; + + let label; + if (report.meta && report.meta.others && (id === 'Other' || id === 'Others')) { + // Add count to "Others" label + label = intl.formatMessage(messages.chartOthers, { count: report.meta.others }); + } else { + const itemLabelKey = getItemLabel({ report, idKey, value: val }); + if (itemLabelKey === 'org_entities' && val.alias) { + label = val.alias; + } else if (itemLabelKey === 'account' && val.account_alias) { + label = val.account_alias; + } else if (itemLabelKey === 'cluster' && cluster_alias) { + label = cluster_alias; + } else if (itemLabelKey === 'subscription_guid' && val.subscription_name) { + label = val.subscription_name; + } else if (itemLabelKey === 'resource_id' && val.instance_name) { + label = val.instance_name; + } else if (val[itemLabelKey] instanceof Object) { + label = val[itemLabelKey].value; + } else { + label = val[itemLabelKey]; + } + if (label === undefined || label.trim().length === 0) { + label = val.alias && val.alias.trim().length > 0 ? val.alias : val[idKey]; + } + } + + if (isDateMap) { + const data = { + ...val, + ...getUsageData(val), // capacity, limit, request, & usage + cluster, + clusters: getClusters(val), + cost: getCostData(val, 'cost'), + default_project, + id, + infrastructure: getCostData(val, 'infrastructure'), + label, + supplementary: getCostData(val, 'supplementary'), + type, + }; + const item = itemMap.get(mapId); + if (item) { + item.set(date, data); + } else { + const dateMap = new Map(); + dateMap.set(date, data); + itemMap.set(mapId, dateMap); + } + } else { + const item = itemMap.get(mapId); + if (item) { + // When applying multiple group_by params, costs may be split between regions. We need to sum those costs + // See https://issues.redhat.com/browse/COST-1131 + itemMap.set(mapId, { + ...item, + ...getUsageData(val, item), // capacity, limit, request, & usage + cluster, + clusters: getClusters(val, item), + cost: getCostData(val, 'cost', item), + date, + default_project, + id, + infrastructure: getCostData(val, 'infrastructure', item), + label, + supplementary: getCostData(val, 'supplementary', item), + type, + }); + } else { + itemMap.set(mapId, { + ...val, + ...getUsageData(val), // capacity, limit, request, & usage + cluster, + clusters: getClusters(val), + cost: getCostData(val, 'cost'), + date, + default_project, + id, + infrastructure: getCostData(val, 'infrastructure'), + label, + supplementary: getCostData(val, 'supplementary'), + type, + }); + } + } +} diff --git a/src/routes/utils/groupBy.ts b/src/routes/utils/groupBy.ts index a8fd6a3bf..85d7d5672 100644 --- a/src/routes/utils/groupBy.ts +++ b/src/routes/utils/groupBy.ts @@ -54,3 +54,18 @@ export const getGroupByTagKey = (query: Query) => { } return groupByTagKey; }; + +export const getFilterByTagKey = (query: Query) => { + let filterByTagKey; + + if (query?.filter_by) { + for (const groupBy of Object.keys(query.filter_by)) { + const tagIndex = groupBy.indexOf(tagPrefix); + if (tagIndex !== -1) { + filterByTagKey = groupBy.substring(tagIndex + tagPrefix.length) as any; + break; + } + } + } + return filterByTagKey; +}; diff --git a/src/store/breakdown/costOverview/common/costOverviewCommon.ts b/src/store/breakdown/costOverview/common/costOverviewCommon.ts index ef2b830fe..4d0c367ed 100644 --- a/src/store/breakdown/costOverview/common/costOverviewCommon.ts +++ b/src/store/breakdown/costOverview/common/costOverviewCommon.ts @@ -17,10 +17,10 @@ export interface CostOverviewWidget { id: number; cluster?: { reportGroupBy: string; // Report group_by - showWidgetOnGroupBy?: string[]; // Show widget when group_by is matched + showWidgetOnGroupBy?: string[]; // Show cluster card when group_by is matched }; pvc?: { - showWidgetOnGroupBy?: string[]; // Show widget when group_by is matched + showWidgetOnGroupBy?: string[]; // Show pvc chart when group_by is matched }; usage?: { showCapacityOnGroupBy?: string[]; // Show capacity when group_by is matched @@ -28,13 +28,13 @@ export interface CostOverviewWidget { reportSummary?: { reportGroupBy: string; // Report group_by showWidgetOnPlatformCategory?: string[]; - showWidgetOnGroupBy?: string[]; // Show widget when group_by is matched + showWidgetOnGroupBy?: string[]; // Show summary card when group_by is matched usePlaceholder?: boolean; // Use placeholder to keep card placement when widget is not shown }; reportPathsType: ReportPathsType; // Report URL path reportType: ReportType; // Report type; cost, storage, etc. type: CostOverviewWidgetType; volume?: { - showWidgetOnGroupBy?: string[]; // Show widget when group_by is matched + showWidgetOnGroupBy?: string[]; // Show volume usage chart when group_by is matched }; } diff --git a/src/store/breakdown/costOverview/ocpCostOverview/ocpCostOverview.test.ts b/src/store/breakdown/costOverview/ocpCostOverview/ocpCostOverview.test.ts index f425aaa85..fbc3f0518 100644 --- a/src/store/breakdown/costOverview/ocpCostOverview/ocpCostOverview.test.ts +++ b/src/store/breakdown/costOverview/ocpCostOverview/ocpCostOverview.test.ts @@ -14,6 +14,7 @@ import { memoryUsageWidget, projectSummaryWidget, pvcWidget, + volumeSummaryWidget, volumeUsageWidget, } from './ocpCostOverviewWidgets'; @@ -33,8 +34,9 @@ test('default state', () => { expect(selectors.selectCurrentWidgets(state)).toEqual([ costWidget.id, costDistributionWidget.id, - clusterWidget.id, projectSummaryWidget.id, + volumeSummaryWidget.id, + clusterWidget.id, cpuUsageWidget.id, memoryUsageWidget.id, pvcWidget.id, diff --git a/src/store/breakdown/costOverview/ocpCostOverview/ocpCostOverviewReducer.ts b/src/store/breakdown/costOverview/ocpCostOverview/ocpCostOverviewReducer.ts index 44063eaee..e10eeaf2c 100644 --- a/src/store/breakdown/costOverview/ocpCostOverview/ocpCostOverviewReducer.ts +++ b/src/store/breakdown/costOverview/ocpCostOverview/ocpCostOverviewReducer.ts @@ -7,6 +7,7 @@ import { memoryUsageWidget, projectSummaryWidget, pvcWidget, + volumeSummaryWidget, volumeUsageWidget, } from './ocpCostOverviewWidgets'; @@ -19,8 +20,9 @@ export const defaultState: OcpCostOverviewState = { currentWidgets: [ costWidget.id, costDistributionWidget.id, - clusterWidget.id, projectSummaryWidget.id, + volumeSummaryWidget.id, + clusterWidget.id, cpuUsageWidget.id, memoryUsageWidget.id, pvcWidget.id, @@ -29,8 +31,9 @@ export const defaultState: OcpCostOverviewState = { widgets: { [costWidget.id]: costWidget, [costDistributionWidget.id]: costDistributionWidget, - [clusterWidget.id]: clusterWidget, [projectSummaryWidget.id]: projectSummaryWidget, + [volumeSummaryWidget.id]: volumeSummaryWidget, + [clusterWidget.id]: clusterWidget, [cpuUsageWidget.id]: cpuUsageWidget, [memoryUsageWidget.id]: memoryUsageWidget, [pvcWidget.id]: pvcWidget, diff --git a/src/store/breakdown/costOverview/ocpCostOverview/ocpCostOverviewWidgets.ts b/src/store/breakdown/costOverview/ocpCostOverview/ocpCostOverviewWidgets.ts index 20d422382..b30e70a91 100644 --- a/src/store/breakdown/costOverview/ocpCostOverview/ocpCostOverviewWidgets.ts +++ b/src/store/breakdown/costOverview/ocpCostOverview/ocpCostOverviewWidgets.ts @@ -80,6 +80,18 @@ export const pvcWidget: OcpCostOverviewWidget = { type: CostOverviewWidgetType.pvc, }; +export const volumeSummaryWidget: OcpCostOverviewWidget = { + id: getId(), + reportSummary: { + reportGroupBy: 'storageclass', + showWidgetOnGroupBy: ['cluster', 'node', 'project'], + usePlaceholder: true, + }, + reportType: ReportType.volume, + reportPathsType: ReportPathsType.ocp, + type: CostOverviewWidgetType.reportSummary, +}; + export const volumeUsageWidget: OcpCostOverviewWidget = { chartName: 'ocpVolumeWidget', id: getId(), diff --git a/src/store/breakdown/historicalData/common/historicalDataCommon.ts b/src/store/breakdown/historicalData/common/historicalDataCommon.ts index 98ad275fa..7bdb0f9a2 100644 --- a/src/store/breakdown/historicalData/common/historicalDataCommon.ts +++ b/src/store/breakdown/historicalData/common/historicalDataCommon.ts @@ -3,13 +3,18 @@ import type { ReportPathsType, ReportType } from 'api/reports/report'; // eslint-disable-next-line no-shadow export const enum HistoricalDataWidgetType { cost = 'cost', // This type displays historical cost chart + network = 'network', // This type displays historical network chart trend = 'trend', // This type displays historical trend chart usage = 'usage', // This type displays historical usage chart + volume = 'volume', // This type displays historical volume chart } export interface HistoricalDataWidget { chartName: string; // Will be the prefix for ids within the chart id: number; + network?: { + showWidgetOnGroupBy?: string[]; // Show network chart when group_by is matched + }; reportPathsType: ReportPathsType; // Report URL path reportType: ReportType; // Report type; cost, storage, etc. type: HistoricalDataWidgetType; diff --git a/src/store/breakdown/historicalData/ocpHistoricalData/ocpHistoricalData.test.ts b/src/store/breakdown/historicalData/ocpHistoricalData/ocpHistoricalData.test.ts index 67a8ef645..9414178e7 100644 --- a/src/store/breakdown/historicalData/ocpHistoricalData/ocpHistoricalData.test.ts +++ b/src/store/breakdown/historicalData/ocpHistoricalData/ocpHistoricalData.test.ts @@ -6,7 +6,13 @@ import { reportActions } from 'store/reports'; import { ocpHistoricalDataStateKey } from './ocpHistoricalDataCommon'; import { ocpHistoricalDataReducer } from './ocpHistoricalDataReducer'; import * as selectors from './ocpHistoricalDataSelectors'; -import { costWidget, cpuUsageWidget, memoryUsageWidget } from './ocpHistoricalDataWidgets'; +import { + costWidget, + cpuUsageWidget, + memoryUsageWidget, + networkUsageWidget, + volumeUsageWidget, +} from './ocpHistoricalDataWidgets'; const createOcpHistoricalDataStore = createMockStoreCreator({ [ocpHistoricalDataStateKey]: ocpHistoricalDataReducer, @@ -21,6 +27,12 @@ beforeEach(() => { test('default state', () => { const store = createOcpHistoricalDataStore(); const state = store.getState(); - expect(selectors.selectCurrentWidgets(state)).toEqual([costWidget.id, cpuUsageWidget.id, memoryUsageWidget.id]); + expect(selectors.selectCurrentWidgets(state)).toEqual([ + costWidget.id, + cpuUsageWidget.id, + memoryUsageWidget.id, + networkUsageWidget.id, + volumeUsageWidget.id, + ]); expect(selectors.selectWidget(state, costWidget.id)).toEqual(costWidget); }); diff --git a/src/store/breakdown/historicalData/ocpHistoricalData/ocpHistoricalDataReducer.ts b/src/store/breakdown/historicalData/ocpHistoricalData/ocpHistoricalDataReducer.ts index 19f738a85..a6e572cfa 100644 --- a/src/store/breakdown/historicalData/ocpHistoricalData/ocpHistoricalDataReducer.ts +++ b/src/store/breakdown/historicalData/ocpHistoricalData/ocpHistoricalDataReducer.ts @@ -1,5 +1,11 @@ import type { OcpHistoricalDataWidget } from './ocpHistoricalDataCommon'; -import { costWidget, cpuUsageWidget, memoryUsageWidget } from './ocpHistoricalDataWidgets'; +import { + costWidget, + cpuUsageWidget, + memoryUsageWidget, + networkUsageWidget, + volumeUsageWidget, +} from './ocpHistoricalDataWidgets'; export type OcpHistoricalDataState = Readonly<{ widgets: Record; @@ -7,11 +13,13 @@ export type OcpHistoricalDataState = Readonly<{ }>; export const defaultState: OcpHistoricalDataState = { - currentWidgets: [costWidget.id, cpuUsageWidget.id, memoryUsageWidget.id], + currentWidgets: [costWidget.id, cpuUsageWidget.id, memoryUsageWidget.id, networkUsageWidget.id, volumeUsageWidget.id], widgets: { [costWidget.id]: costWidget, [cpuUsageWidget.id]: cpuUsageWidget, [memoryUsageWidget.id]: memoryUsageWidget, + [networkUsageWidget.id]: networkUsageWidget, + [volumeUsageWidget.id]: volumeUsageWidget, }, }; diff --git a/src/store/breakdown/historicalData/ocpHistoricalData/ocpHistoricalDataWidgets.ts b/src/store/breakdown/historicalData/ocpHistoricalData/ocpHistoricalDataWidgets.ts index c8c9b9aa1..7468b14ec 100644 --- a/src/store/breakdown/historicalData/ocpHistoricalData/ocpHistoricalDataWidgets.ts +++ b/src/store/breakdown/historicalData/ocpHistoricalData/ocpHistoricalDataWidgets.ts @@ -29,3 +29,22 @@ export const memoryUsageWidget: OcpHistoricalDataWidget = { reportType: ReportType.memory, type: HistoricalDataWidgetType.usage, }; + +export const networkUsageWidget: OcpHistoricalDataWidget = { + chartName: 'ocpNetworkChart', + id: getId(), + network: { + showWidgetOnGroupBy: ['cluster', 'node'], + }, + reportPathsType: ReportPathsType.ocp, + reportType: ReportType.network, + type: HistoricalDataWidgetType.network, +}; + +export const volumeUsageWidget: OcpHistoricalDataWidget = { + chartName: 'ocpVolumeChart', + id: getId(), + reportPathsType: ReportPathsType.ocp, + reportType: ReportType.volume, + type: HistoricalDataWidgetType.volume, +}; diff --git a/src/store/featureToggle/__snapshots__/featureToggle.test.ts.snap b/src/store/featureToggle/__snapshots__/featureToggle.test.ts.snap index 38f05a822..ce0f17673 100644 --- a/src/store/featureToggle/__snapshots__/featureToggle.test.ts.snap +++ b/src/store/featureToggle/__snapshots__/featureToggle.test.ts.snap @@ -3,13 +3,13 @@ exports[`default state 1`] = ` { "hasFeatureToggle": false, - "isClusterInfoToggleEnabled": false, + "isAwsEc2InstancesToggleEnabled": false, "isDebugToggleEnabled": false, "isExportsToggleEnabled": false, "isFinsightsToggleEnabled": false, "isIbmToggleEnabled": false, + "isOcpCloudNetworkingToggleEnabled": false, + "isOcpProjectStorageToggleEnabled": false, "isRosToggleEnabled": false, - "isSettingsPlatformToggleEnabled": false, - "isTagMappingToggleEnabled": false, } `; diff --git a/src/store/featureToggle/featureToggle.test.ts b/src/store/featureToggle/featureToggle.test.ts index f5bab857c..7ff31eb53 100644 --- a/src/store/featureToggle/featureToggle.test.ts +++ b/src/store/featureToggle/featureToggle.test.ts @@ -14,6 +14,18 @@ test('default state', async () => { expect(selectors.selectFeatureToggleState(store.getState())).toMatchSnapshot(); }); +test('AWS EC2 instances feature is enabled', async () => { + const store = createUIStore(); + store.dispatch(actions.setFeatureToggle({ isAwsEc2InstancesToggleEnabled: true })); + expect(FeatureToggleSelectors.selectIsAwsEc2InstancesToggleEnabled(store.getState())).toBe(true); +}); + +test('Debug feature is enabled', async () => { + const store = createUIStore(); + store.dispatch(actions.setFeatureToggle({ isDebugToggleEnabled: true })); + expect(FeatureToggleSelectors.selectIsDebugToggleEnabled(store.getState())).toBe(true); +}); + test('Exports feature is enabled', async () => { const store = createUIStore(); store.dispatch(actions.setFeatureToggle({ isExportsToggleEnabled: true })); @@ -32,6 +44,18 @@ test('IBM feature is enabled', async () => { expect(FeatureToggleSelectors.selectIsIbmToggleEnabled(store.getState())).toBe(true); }); +test('OCP on cloud networking feature is enabled', async () => { + const store = createUIStore(); + store.dispatch(actions.setFeatureToggle({ isOcpCloudNetworkingToggleEnabled: true })); + expect(FeatureToggleSelectors.selectIsOcpCloudNetworkingToggleEnabled(store.getState())).toBe(true); +}); + +test('OCP project storage feature is enabled', async () => { + const store = createUIStore(); + store.dispatch(actions.setFeatureToggle({ isOcpProjectStorageToggleEnabled: true })); + expect(FeatureToggleSelectors.selectIsOcpProjectStorageToggleEnabled(store.getState())).toBe(true); +}); + test('ROS feature is enabled', async () => { const store = createUIStore(); store.dispatch(actions.setFeatureToggle({ isRosToggleEnabled: true })); diff --git a/src/store/featureToggle/featureToggleActions.ts b/src/store/featureToggle/featureToggleActions.ts index 6a7df2a8c..c5f487069 100644 --- a/src/store/featureToggle/featureToggleActions.ts +++ b/src/store/featureToggle/featureToggleActions.ts @@ -1,14 +1,14 @@ import { createAction } from 'typesafe-actions'; export interface FeatureToggleActionMeta { - isClusterInfoToggleEnabled?: boolean; + isAwsEc2InstancesToggleEnabled?: boolean; isDebugToggleEnabled?: boolean; isExportsToggleEnabled?: boolean; isFinsightsToggleEnabled?: boolean; isIbmToggleEnabled?: boolean; + isOcpCloudNetworkingToggleEnabled?: boolean; + isOcpProjectStorageToggleEnabled?: boolean; isRosToggleEnabled?: boolean; - isSettingsPlatformToggleEnabled?: boolean; - isTagMappingToggleEnabled?: boolean; } export const setFeatureToggle = createAction('feature/init_feature_toggle')(); diff --git a/src/store/featureToggle/featureToggleReducer.ts b/src/store/featureToggle/featureToggleReducer.ts index b2927f9a7..68222df27 100644 --- a/src/store/featureToggle/featureToggleReducer.ts +++ b/src/store/featureToggle/featureToggleReducer.ts @@ -8,26 +8,26 @@ export type FeatureToggleAction = ActionType; export const defaultState: FeatureToggleState = { hasFeatureToggle: false, - isClusterInfoToggleEnabled: false, + isAwsEc2InstancesToggleEnabled: false, isDebugToggleEnabled: false, isExportsToggleEnabled: false, isFinsightsToggleEnabled: false, isIbmToggleEnabled: false, + isOcpCloudNetworkingToggleEnabled: false, + isOcpProjectStorageToggleEnabled: false, isRosToggleEnabled: false, - isSettingsPlatformToggleEnabled: false, - isTagMappingToggleEnabled: false, }; export const stateKey = 'FeatureToggle'; @@ -38,14 +38,14 @@ export function FeatureToggleReducer(state = defaultState, action: FeatureToggle return { ...state, hasFeatureToggle: true, - isClusterInfoToggleEnabled: action.payload.isClusterInfoToggleEnabled, + isAwsEc2InstancesToggleEnabled: action.payload.isAwsEc2InstancesToggleEnabled, isDebugToggleEnabled: action.payload.isDebugToggleEnabled, isExportsToggleEnabled: action.payload.isExportsToggleEnabled, isFinsightsToggleEnabled: action.payload.isFinsightsToggleEnabled, isIbmToggleEnabled: action.payload.isIbmToggleEnabled, + isOcpCloudNetworkingToggleEnabled: action.payload.isOcpCloudNetworkingToggleEnabled, + isOcpProjectStorageToggleEnabled: action.payload.isOcpProjectStorageToggleEnabled, isRosToggleEnabled: action.payload.isRosToggleEnabled, - isSettingsPlatformToggleEnabled: action.payload.isSettingsPlatformToggleEnabled, - isTagMappingToggleEnabled: action.payload.isTagMappingToggleEnabled, }; default: diff --git a/src/store/featureToggle/featureToggleSelectors.ts b/src/store/featureToggle/featureToggleSelectors.ts index a5d243350..3e5771cdd 100644 --- a/src/store/featureToggle/featureToggleSelectors.ts +++ b/src/store/featureToggle/featureToggleSelectors.ts @@ -6,16 +6,16 @@ export const selectFeatureToggleState = (state: RootState) => state[stateKey]; export const selectHasFeatureToggle = (state: RootState) => selectFeatureToggleState(state).hasFeatureToggle; -export const selectIsClusterInfoToggleEnabled = (state: RootState) => - selectFeatureToggleState(state).isClusterInfoToggleEnabled; +export const selectIsAwsEc2InstancesToggleEnabled = (state: RootState) => + selectFeatureToggleState(state).isAwsEc2InstancesToggleEnabled; export const selectIsDebugToggleEnabled = (state: RootState) => selectFeatureToggleState(state).isDebugToggleEnabled; export const selectIsExportsToggleEnabled = (state: RootState) => selectFeatureToggleState(state).isExportsToggleEnabled; export const selectIsFinsightsToggleEnabled = (state: RootState) => selectFeatureToggleState(state).isFinsightsToggleEnabled; export const selectIsIbmToggleEnabled = (state: RootState) => selectFeatureToggleState(state).isIbmToggleEnabled; +export const selectIsOcpCloudNetworkingToggleEnabled = (state: RootState) => + selectFeatureToggleState(state).isOcpCloudNetworkingToggleEnabled; +export const selectIsOcpProjectStorageToggleEnabled = (state: RootState) => + selectFeatureToggleState(state).isOcpProjectStorageToggleEnabled; export const selectIsRosToggleEnabled = (state: RootState) => selectFeatureToggleState(state).isRosToggleEnabled; -export const selectIsSettingsPlatformToggleEnabled = (state: RootState) => - selectFeatureToggleState(state).isSettingsPlatformToggleEnabled; -export const selectIsTagMappingToggleEnabled = (state: RootState) => - selectFeatureToggleState(state).isTagMappingToggleEnabled; diff --git a/src/store/reports/reportReducer.ts b/src/store/reports/reportReducer.ts index 4d265ea93..f6a8acbd7 100644 --- a/src/store/reports/reportReducer.ts +++ b/src/store/reports/reportReducer.ts @@ -8,7 +8,7 @@ import { getType } from 'typesafe-actions'; import { fetchReportFailure, fetchReportRequest, fetchReportSuccess } from './reportActions'; export interface CachedReport extends Report { - timeRequested: number; + timeRequested?: number; } export type ReportState = Readonly<{ diff --git a/src/utils/hooks.ts b/src/utils/hooks.ts index 4a3fe3807..e112965da 100644 --- a/src/utils/hooks.ts +++ b/src/utils/hooks.ts @@ -1,5 +1,9 @@ // Hook +import type { Query } from 'api/queries/query'; +import { parseQuery } from 'api/queries/query'; import { useCallback, useEffect, useRef, useState } from 'react'; +import { useLocation } from 'react-router-dom'; +import { getQueryState } from 'routes/utils/queryState'; export const usePrevious = value => { // The ref object is a generic container whose current property is mutable ... @@ -34,3 +38,13 @@ export const useStateCallback = (initialState: T): [T, (state: T, cb?: (_stat return [state, setStateCallback]; }; + +export const useQueryFromRoute = () => { + const location = useLocation(); + return parseQuery(location.search); +}; + +export const useQueryState = (key = 'details') => { + const location = useLocation(); + return getQueryState(location, key); +}; diff --git a/src/utils/props.ts b/src/utils/props.ts index 82917e92a..0c42cd91a 100644 --- a/src/utils/props.ts +++ b/src/utils/props.ts @@ -4,6 +4,7 @@ export const logicalAndPrefix = 'and:'; // logical AND prefix for group_by export const noPrefix = 'No-'; // no-project, no-region, no- export const tagPrefix = 'tag:'; // Tag prefix for group_by +export const accountKey = 'account'; // Account key for group_by export const awsCategoryKey = 'aws_category'; // AWS category for group_by export const breadcrumbLabelKey = 'breadcrumb_label'; // Used to display a breadcrumb in the breakdown header export const breakdownDescKey = 'breakdown_desc'; // Used to display a description in the breakdown header @@ -11,6 +12,8 @@ export const breakdownTitleKey = 'breakdown_title'; // Used to display a title i export const orgUnitIdKey = 'org_unit_id'; // Org unit ID for group_by export const orgUnitNameKey = 'org_unit_name'; // Org unit name for group_by export const platformCategoryKey = 'Platform'; // Used to display platform costs +export const regionKey = 'region'; // Region key for group_by +export const serviceKey = 'service'; // Service key for group_by export const tagKey = 'tag'; // Tag key for group_by export const classificationDefault = 'default'; // Classification default costs