diff --git a/backend/lib/edgehog/containers/container/deployment/deployment.ex b/backend/lib/edgehog/containers/container/deployment/deployment.ex index 1867d7590..9c8036774 100644 --- a/backend/lib/edgehog/containers/container/deployment/deployment.ex +++ b/backend/lib/edgehog/containers/container/deployment/deployment.ex @@ -1,7 +1,7 @@ # # This file is part of Edgehog. # -# Copyright 2025 SECO Mind Srl +# Copyright 2025-2026 SECO Mind Srl # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -201,7 +201,9 @@ defmodule Edgehog.Containers.Container.Deployment do end calculations do - calculate :is_ready, :boolean, Calculations.Ready + calculate :is_ready, :boolean, Calculations.Ready do + public? true + end calculate :dangling?, :boolean, diff --git a/backend/lib/edgehog/containers/device_mapping/deployment/deployment.ex b/backend/lib/edgehog/containers/device_mapping/deployment/deployment.ex index 9c5e898d6..33bee156f 100644 --- a/backend/lib/edgehog/containers/device_mapping/deployment/deployment.ex +++ b/backend/lib/edgehog/containers/device_mapping/deployment/deployment.ex @@ -1,7 +1,7 @@ # # This file is part of Edgehog. # -# Copyright 2025 SECO Mind Srl +# Copyright 2025-2026 SECO Mind Srl # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -144,7 +144,9 @@ defmodule Edgehog.Containers.DeviceMapping.Deployment do end calculations do - calculate :is_ready, :boolean, expr(state in [:present, :not_present]) + calculate :is_ready, :boolean, expr(state in [:present, :not_present]) do + public? true + end calculate :dangling?, :boolean, diff --git a/backend/lib/edgehog/containers/image/deployment/deployment.ex b/backend/lib/edgehog/containers/image/deployment/deployment.ex index d87c3de7c..4e1c1db28 100644 --- a/backend/lib/edgehog/containers/image/deployment/deployment.ex +++ b/backend/lib/edgehog/containers/image/deployment/deployment.ex @@ -1,7 +1,7 @@ # # This file is part of Edgehog. # -# Copyright 2025 SECO Mind Srl +# Copyright 2025-2026 SECO Mind Srl # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -143,7 +143,9 @@ defmodule Edgehog.Containers.Image.Deployment do end calculations do - calculate :is_ready, :boolean, expr(state in [:pulled, :unpulled]) + calculate :is_ready, :boolean, expr(state in [:pulled, :unpulled]) do + public? true + end calculate :dangling?, :boolean, diff --git a/backend/lib/edgehog/containers/network/deployment/deployment.ex b/backend/lib/edgehog/containers/network/deployment/deployment.ex index 2ad1ae107..e228413d1 100644 --- a/backend/lib/edgehog/containers/network/deployment/deployment.ex +++ b/backend/lib/edgehog/containers/network/deployment/deployment.ex @@ -1,7 +1,7 @@ # # This file is part of Edgehog. # -# Copyright 2025 SECO Mind Srl +# Copyright 2025-2026 SECO Mind Srl # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -143,7 +143,9 @@ defmodule Edgehog.Containers.Network.Deployment do end calculations do - calculate :is_ready, :boolean, expr(state in [:available, :unavailable]) + calculate :is_ready, :boolean, expr(state in [:available, :unavailable]) do + public? true + end calculate :dangling?, :boolean, diff --git a/backend/lib/edgehog/containers/volume/deployment/deployment.ex b/backend/lib/edgehog/containers/volume/deployment/deployment.ex index 8a5b151d5..a90be4be9 100644 --- a/backend/lib/edgehog/containers/volume/deployment/deployment.ex +++ b/backend/lib/edgehog/containers/volume/deployment/deployment.ex @@ -1,7 +1,7 @@ # # This file is part of Edgehog. # -# Copyright 2025 SECO Mind Srl +# Copyright 2025-2026 SECO Mind Srl # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -145,7 +145,9 @@ defmodule Edgehog.Containers.Volume.Deployment do end calculations do - calculate :is_ready, :boolean, expr(state in [:available, :unavailable]) + calculate :is_ready, :boolean, expr(state in [:available, :unavailable]) do + public? true + end calculate :dangling?, :boolean, diff --git a/backend/test/edgehog_web/schema/query/deployment_test.exs b/backend/test/edgehog_web/schema/query/deployment_test.exs index 03079b924..e9e4bccf4 100644 --- a/backend/test/edgehog_web/schema/query/deployment_test.exs +++ b/backend/test/edgehog_web/schema/query/deployment_test.exs @@ -1,7 +1,7 @@ # # This file is part of Edgehog. # -# Copyright 2025 SECO Mind Srl +# Copyright 2025-2026 SECO Mind Srl # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -83,11 +83,13 @@ defmodule EdgehogWeb.Schema.Query.DeploymentTest do state imageDeployment { state + isReady } networkDeployments { edges { node { state + isReady } } } @@ -95,6 +97,15 @@ defmodule EdgehogWeb.Schema.Query.DeploymentTest do edges { node { state + isReady + } + } + } + deviceMappingDeployments { + edges { + node { + state + isReady } } } @@ -118,16 +129,27 @@ defmodule EdgehogWeb.Schema.Query.DeploymentTest do container_deployment = container_deployment["node"] assert container_deployment["imageDeployment"]["state"] == "created" + refute container_deployment["imageDeployment"]["isReady"] assert [network_deployment] = container_deployment["networkDeployments"]["edges"] network_deployment = network_deployment["node"] assert network_deployment["state"] == "created" + refute network_deployment["isReady"] assert [volume_deployment] = container_deployment["volumeDeployments"]["edges"] volume_deployment = volume_deployment["node"] assert volume_deployment["state"] == "created" + refute volume_deployment["isReady"] + + assert [device_mapping_deployment] = + container_deployment["deviceMappingDeployments"]["edges"] + + device_mapping_deployment = device_mapping_deployment["node"] + + assert device_mapping_deployment["state"] == "created" + refute device_mapping_deployment["isReady"] end defp get_deployment(opts) do diff --git a/frontend/package-lock.json b/frontend/package-lock.json index a87194d9d..dd9848c85 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -13,6 +13,7 @@ "@formatjs/cli": "^6.2.12", "@fortawesome/fontawesome-svg-core": "^7.1.0", "@fortawesome/free-brands-svg-icons": "^7.1.0", + "@fortawesome/free-regular-svg-icons": "^7.1.0", "@fortawesome/free-solid-svg-icons": "^7.1.0", "@fortawesome/react-fontawesome": "^3.1.1", "@hookform/resolvers": "^5.2.2", @@ -1923,6 +1924,18 @@ "node": ">=6" } }, + "node_modules/@fortawesome/free-regular-svg-icons": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@fortawesome/free-regular-svg-icons/-/free-regular-svg-icons-7.2.0.tgz", + "integrity": "sha512-iycmlN51EULlQ4D/UU9WZnHiN0CvjJ2TuuCrAh+1MVdzD+4ViKYH2deNAll4XAAYlZa8WAefHR5taSK8hYmSMw==", + "license": "(CC-BY-4.0 AND MIT)", + "dependencies": { + "@fortawesome/fontawesome-common-types": "7.2.0" + }, + "engines": { + "node": ">=6" + } + }, "node_modules/@fortawesome/free-solid-svg-icons": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/@fortawesome/free-solid-svg-icons/-/free-solid-svg-icons-7.2.0.tgz", diff --git a/frontend/package.json b/frontend/package.json index 46875040c..a4747aa24 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -15,6 +15,7 @@ "@formatjs/cli": "^6.2.12", "@fortawesome/fontawesome-svg-core": "^7.1.0", "@fortawesome/free-brands-svg-icons": "^7.1.0", + "@fortawesome/free-regular-svg-icons": "^7.1.0", "@fortawesome/free-solid-svg-icons": "^7.1.0", "@fortawesome/react-fontawesome": "^3.1.1", "@hookform/resolvers": "^5.2.2", diff --git a/frontend/src/api/schema.graphql b/frontend/src/api/schema.graphql index 4cca80617..8e95501e6 100644 --- a/frontend/src/api/schema.graphql +++ b/frontend/src/api/schema.graphql @@ -40,13 +40,6 @@ input CampaignCampaignMechanismFileDownloadInput { fileId: ID - """ - The maximum percentage of failures allowed over the number of total targets. - If the failures exceed this threshold, the File Download Campaign terminates with - a failure. - """ - maxFailurePercentage: Float - """ Optional compression type for the file (e.g., "tar.gz"). Other values are: ['tar.gz']. Defaults to empty string (no compression). @@ -77,6 +70,13 @@ input CampaignCampaignMechanismFileDownloadInput { """ ttlSeconds: Int + """ + The maximum percentage of failures allowed over the number of total targets. + If the failures exceed this threshold, the File Download Campaign terminates with + a failure. + """ + maxFailurePercentage: Float + """ The maximum number of in progress file downloads. The File Download Campaign will have at most this number of File Download Requests that are started but not yet @@ -1259,8 +1259,8 @@ input BaseImageCollectionFilterId { greaterThan: Int lessThanOrEqual: Int greaterThanOrEqual: Int - isDistinctFrom: String - isNotDistinctFrom: String + isDistinctFrom: Int + isNotDistinctFrom: Int } input BaseImageCollectionFilterInput { @@ -1486,8 +1486,8 @@ input BaseImageFilterId { greaterThan: Int lessThanOrEqual: Int greaterThanOrEqual: Int - isDistinctFrom: String - isNotDistinctFrom: String + isDistinctFrom: Int + isNotDistinctFrom: Int } input BaseImageFilterInput { @@ -1675,8 +1675,8 @@ input ContainerVolumeFilterVolumeId { greaterThan: ID lessThanOrEqual: ID greaterThanOrEqual: ID - isDistinctFrom: String - isNotDistinctFrom: String + isDistinctFrom: ID + isNotDistinctFrom: ID } input ContainerVolumeFilterTarget { @@ -1724,6 +1724,7 @@ enum DeviceMappingDeploymentSortField { ID STATE DEVICE_MAPPING_ID + IS_READY } ":device_mapping_deployment connection" @@ -1747,6 +1748,19 @@ type DeviceMappingDeploymentEdge { node: DeviceMappingDeployment! } +input DeviceMappingDeploymentFilterIsReady { + isNil: Boolean + eq: Boolean + notEq: Boolean + in: [Boolean!] + lessThan: Boolean + greaterThan: Boolean + lessThanOrEqual: Boolean + greaterThanOrEqual: Boolean + isDistinctFrom: Boolean + isNotDistinctFrom: Boolean +} + input DeviceMappingDeploymentFilterDeviceMappingId { isNil: Boolean eq: ID @@ -1756,8 +1770,8 @@ input DeviceMappingDeploymentFilterDeviceMappingId { greaterThan: ID lessThanOrEqual: ID greaterThanOrEqual: ID - isDistinctFrom: String - isNotDistinctFrom: String + isDistinctFrom: ID + isNotDistinctFrom: ID } input DeviceMappingDeploymentFilterState { @@ -1782,8 +1796,8 @@ input DeviceMappingDeploymentFilterId { greaterThan: ID lessThanOrEqual: ID greaterThanOrEqual: ID - isDistinctFrom: String - isNotDistinctFrom: String + isDistinctFrom: ID + isNotDistinctFrom: ID } input DeviceMappingDeploymentFilterInput { @@ -1795,6 +1809,7 @@ input DeviceMappingDeploymentFilterInput { deviceMappingId: DeviceMappingDeploymentFilterDeviceMappingId deviceMapping: DeviceMappingFilterInput containerDeployments: ContainerDeploymentFilterInput + isReady: DeviceMappingDeploymentFilterIsReady } input DeviceMappingDeploymentSortInput { @@ -1820,6 +1835,7 @@ type DeviceMappingDeployment { "The number of records to skip." offset: Int ): [ContainerDeployment!]! + isReady: Boolean } enum DeviceMappingSortField { @@ -1860,8 +1876,8 @@ input DeviceMappingFilterContainerId { greaterThan: ID lessThanOrEqual: ID greaterThanOrEqual: ID - isDistinctFrom: String - isNotDistinctFrom: String + isDistinctFrom: ID + isNotDistinctFrom: ID } input DeviceMappingFilterCgroupPermissions { @@ -1921,8 +1937,8 @@ input DeviceMappingFilterId { greaterThan: ID lessThanOrEqual: ID greaterThanOrEqual: ID - isDistinctFrom: String - isNotDistinctFrom: String + isDistinctFrom: ID + isNotDistinctFrom: ID } input DeviceMappingFilterInput { @@ -1955,6 +1971,7 @@ enum VolumeDeploymentSortField { ID STATE VOLUME_ID + IS_READY } ":volume_deployment connection" @@ -1978,6 +1995,19 @@ type VolumeDeploymentEdge { node: VolumeDeployment! } +input VolumeDeploymentFilterIsReady { + isNil: Boolean + eq: Boolean + notEq: Boolean + in: [Boolean!] + lessThan: Boolean + greaterThan: Boolean + lessThanOrEqual: Boolean + greaterThanOrEqual: Boolean + isDistinctFrom: Boolean + isNotDistinctFrom: Boolean +} + input VolumeDeploymentFilterVolumeId { isNil: Boolean eq: ID @@ -1987,8 +2017,8 @@ input VolumeDeploymentFilterVolumeId { greaterThan: ID lessThanOrEqual: ID greaterThanOrEqual: ID - isDistinctFrom: String - isNotDistinctFrom: String + isDistinctFrom: ID + isNotDistinctFrom: ID } input VolumeDeploymentFilterState { @@ -2013,8 +2043,8 @@ input VolumeDeploymentFilterId { greaterThan: ID lessThanOrEqual: ID greaterThanOrEqual: ID - isDistinctFrom: String - isNotDistinctFrom: String + isDistinctFrom: ID + isNotDistinctFrom: ID } input VolumeDeploymentFilterInput { @@ -2026,6 +2056,7 @@ input VolumeDeploymentFilterInput { volumeId: VolumeDeploymentFilterVolumeId volume: VolumeFilterInput containerDeployments: ContainerDeploymentFilterInput + isReady: VolumeDeploymentFilterIsReady } input VolumeDeploymentSortInput { @@ -2051,6 +2082,7 @@ type VolumeDeployment { "The number of records to skip." offset: Int ): [ContainerDeployment!]! + isReady: Boolean } type volume_result { @@ -2119,8 +2151,8 @@ input VolumeFilterOptions { greaterThan: JsonString lessThanOrEqual: JsonString greaterThanOrEqual: JsonString - isDistinctFrom: String - isNotDistinctFrom: String + isDistinctFrom: JsonString + isNotDistinctFrom: JsonString } input VolumeFilterDriver { @@ -2164,8 +2196,8 @@ input VolumeFilterId { greaterThan: ID lessThanOrEqual: ID greaterThanOrEqual: ID - isDistinctFrom: String - isNotDistinctFrom: String + isDistinctFrom: ID + isNotDistinctFrom: ID } input VolumeFilterInput { @@ -2214,6 +2246,7 @@ enum NetworkDeploymentSortField { ID STATE NETWORK_ID + IS_READY } ":network_deployment connection" @@ -2237,6 +2270,19 @@ type NetworkDeploymentEdge { node: NetworkDeployment! } +input NetworkDeploymentFilterIsReady { + isNil: Boolean + eq: Boolean + notEq: Boolean + in: [Boolean!] + lessThan: Boolean + greaterThan: Boolean + lessThanOrEqual: Boolean + greaterThanOrEqual: Boolean + isDistinctFrom: Boolean + isNotDistinctFrom: Boolean +} + input NetworkDeploymentFilterNetworkId { isNil: Boolean eq: ID @@ -2246,8 +2292,8 @@ input NetworkDeploymentFilterNetworkId { greaterThan: ID lessThanOrEqual: ID greaterThanOrEqual: ID - isDistinctFrom: String - isNotDistinctFrom: String + isDistinctFrom: ID + isNotDistinctFrom: ID } input NetworkDeploymentFilterState { @@ -2272,8 +2318,8 @@ input NetworkDeploymentFilterId { greaterThan: ID lessThanOrEqual: ID greaterThanOrEqual: ID - isDistinctFrom: String - isNotDistinctFrom: String + isDistinctFrom: ID + isNotDistinctFrom: ID } input NetworkDeploymentFilterInput { @@ -2285,6 +2331,7 @@ input NetworkDeploymentFilterInput { networkId: NetworkDeploymentFilterNetworkId network: NetworkFilterInput containerDeployments: ContainerDeploymentFilterInput + isReady: NetworkDeploymentFilterIsReady } input NetworkDeploymentSortInput { @@ -2310,6 +2357,7 @@ type NetworkDeployment { "The number of records to skip." offset: Int ): [ContainerDeployment!]! + isReady: Boolean } type network_result { @@ -2383,8 +2431,8 @@ input NetworkFilterOptions { greaterThan: JsonString lessThanOrEqual: JsonString greaterThanOrEqual: JsonString - isDistinctFrom: String - isNotDistinctFrom: String + isDistinctFrom: JsonString + isNotDistinctFrom: JsonString } input NetworkFilterEnableIpv6 { @@ -2396,8 +2444,8 @@ input NetworkFilterEnableIpv6 { greaterThan: Boolean lessThanOrEqual: Boolean greaterThanOrEqual: Boolean - isDistinctFrom: String - isNotDistinctFrom: String + isDistinctFrom: Boolean + isNotDistinctFrom: Boolean } input NetworkFilterInternal { @@ -2409,8 +2457,8 @@ input NetworkFilterInternal { greaterThan: Boolean lessThanOrEqual: Boolean greaterThanOrEqual: Boolean - isDistinctFrom: String - isNotDistinctFrom: String + isDistinctFrom: Boolean + isNotDistinctFrom: Boolean } input NetworkFilterDriver { @@ -2454,8 +2502,8 @@ input NetworkFilterId { greaterThan: ID lessThanOrEqual: ID greaterThanOrEqual: ID - isDistinctFrom: String - isNotDistinctFrom: String + isDistinctFrom: ID + isNotDistinctFrom: ID } input NetworkFilterInput { @@ -2590,8 +2638,8 @@ input ReleaseFilterApplicationId { greaterThan: ID lessThanOrEqual: ID greaterThanOrEqual: ID - isDistinctFrom: String - isNotDistinctFrom: String + isDistinctFrom: ID + isNotDistinctFrom: ID } input ReleaseFilterVersion { @@ -2619,8 +2667,8 @@ input ReleaseFilterId { greaterThan: ID lessThanOrEqual: ID greaterThanOrEqual: ID - isDistinctFrom: String - isNotDistinctFrom: String + isDistinctFrom: ID + isNotDistinctFrom: ID } input ReleaseFilterInput { @@ -2796,8 +2844,8 @@ input ImageCredentialsFilterId { greaterThan: ID lessThanOrEqual: ID greaterThanOrEqual: ID - isDistinctFrom: String - isNotDistinctFrom: String + isDistinctFrom: ID + isNotDistinctFrom: ID } input ImageCredentialsFilterInput { @@ -2827,6 +2875,19 @@ type ImageCredentials implements Node { username: String! } +input ImageDeploymentFilterIsReady { + isNil: Boolean + eq: Boolean + notEq: Boolean + in: [Boolean!] + lessThan: Boolean + greaterThan: Boolean + lessThanOrEqual: Boolean + greaterThanOrEqual: Boolean + isDistinctFrom: Boolean + isNotDistinctFrom: Boolean +} + input ImageDeploymentFilterImageId { isNil: Boolean eq: ID @@ -2836,8 +2897,8 @@ input ImageDeploymentFilterImageId { greaterThan: ID lessThanOrEqual: ID greaterThanOrEqual: ID - isDistinctFrom: String - isNotDistinctFrom: String + isDistinctFrom: ID + isNotDistinctFrom: ID } input ImageDeploymentFilterState { @@ -2862,8 +2923,8 @@ input ImageDeploymentFilterId { greaterThan: ID lessThanOrEqual: ID greaterThanOrEqual: ID - isDistinctFrom: String - isNotDistinctFrom: String + isDistinctFrom: ID + isNotDistinctFrom: ID } input ImageDeploymentFilterInput { @@ -2874,6 +2935,7 @@ input ImageDeploymentFilterInput { state: ImageDeploymentFilterState imageId: ImageDeploymentFilterImageId image: ImageFilterInput + isReady: ImageDeploymentFilterIsReady } type ImageDeployment { @@ -2881,6 +2943,7 @@ type ImageDeployment { state: String imageId: ID image: Image + isReady: Boolean } type image_result { @@ -2897,8 +2960,8 @@ input ImageFilterImageCredentialsId { greaterThan: ID lessThanOrEqual: ID greaterThanOrEqual: ID - isDistinctFrom: String - isNotDistinctFrom: String + isDistinctFrom: ID + isNotDistinctFrom: ID } input ImageFilterReference { @@ -2926,8 +2989,8 @@ input ImageFilterId { greaterThan: ID lessThanOrEqual: ID greaterThanOrEqual: ID - isDistinctFrom: String - isNotDistinctFrom: String + isDistinctFrom: ID + isNotDistinctFrom: ID } input ImageFilterInput { @@ -3023,8 +3086,8 @@ input DeploymentEventFilterUpdatedAt { greaterThan: DateTime lessThanOrEqual: DateTime greaterThanOrEqual: DateTime - isDistinctFrom: String - isNotDistinctFrom: String + isDistinctFrom: DateTime + isNotDistinctFrom: DateTime } input DeploymentEventFilterInsertedAt { @@ -3036,8 +3099,8 @@ input DeploymentEventFilterInsertedAt { greaterThan: DateTime lessThanOrEqual: DateTime greaterThanOrEqual: DateTime - isDistinctFrom: String - isNotDistinctFrom: String + isDistinctFrom: DateTime + isNotDistinctFrom: DateTime } input DeploymentEventFilterMessage { @@ -3065,8 +3128,8 @@ input DeploymentEventFilterType { greaterThan: DeploymentEventType lessThanOrEqual: DeploymentEventType greaterThanOrEqual: DeploymentEventType - isDistinctFrom: String - isNotDistinctFrom: String + isDistinctFrom: DeploymentEventType + isNotDistinctFrom: DeploymentEventType } input DeploymentEventFilterId { @@ -3078,8 +3141,8 @@ input DeploymentEventFilterId { greaterThan: ID lessThanOrEqual: ID greaterThanOrEqual: ID - isDistinctFrom: String - isNotDistinctFrom: String + isDistinctFrom: ID + isNotDistinctFrom: ID } input DeploymentEventFilterInput { @@ -3220,8 +3283,8 @@ input DeploymentFilterReleaseId { greaterThan: ID lessThanOrEqual: ID greaterThanOrEqual: ID - isDistinctFrom: String - isNotDistinctFrom: String + isDistinctFrom: ID + isNotDistinctFrom: ID } input DeploymentFilterDeviceId { @@ -3233,8 +3296,8 @@ input DeploymentFilterDeviceId { greaterThan: Int lessThanOrEqual: Int greaterThanOrEqual: Int - isDistinctFrom: String - isNotDistinctFrom: String + isDistinctFrom: Int + isNotDistinctFrom: Int } input DeploymentFilterTimedOut { @@ -3246,8 +3309,8 @@ input DeploymentFilterTimedOut { greaterThan: Boolean lessThanOrEqual: Boolean greaterThanOrEqual: Boolean - isDistinctFrom: String - isNotDistinctFrom: String + isDistinctFrom: Boolean + isNotDistinctFrom: Boolean } input DeploymentFilterState { @@ -3259,8 +3322,8 @@ input DeploymentFilterState { greaterThan: ApplicationDeploymentState lessThanOrEqual: ApplicationDeploymentState greaterThanOrEqual: ApplicationDeploymentState - isDistinctFrom: String - isNotDistinctFrom: String + isDistinctFrom: ApplicationDeploymentState + isNotDistinctFrom: ApplicationDeploymentState } input DeploymentFilterId { @@ -3272,8 +3335,8 @@ input DeploymentFilterId { greaterThan: ID lessThanOrEqual: ID greaterThanOrEqual: ID - isDistinctFrom: String - isNotDistinctFrom: String + isDistinctFrom: ID + isNotDistinctFrom: ID } input DeploymentFilterInput { @@ -3417,8 +3480,8 @@ input ContainerDeploymentFilterImageDeploymentId { greaterThan: ID lessThanOrEqual: ID greaterThanOrEqual: ID - isDistinctFrom: String - isNotDistinctFrom: String + isDistinctFrom: ID + isNotDistinctFrom: ID } input ContainerDeploymentFilterDeviceId { @@ -3430,8 +3493,8 @@ input ContainerDeploymentFilterDeviceId { greaterThan: Int lessThanOrEqual: Int greaterThanOrEqual: Int - isDistinctFrom: String - isNotDistinctFrom: String + isDistinctFrom: Int + isNotDistinctFrom: Int } input ContainerDeploymentFilterContainerId { @@ -3443,8 +3506,8 @@ input ContainerDeploymentFilterContainerId { greaterThan: ID lessThanOrEqual: ID greaterThanOrEqual: ID - isDistinctFrom: String - isNotDistinctFrom: String + isDistinctFrom: ID + isNotDistinctFrom: ID } input ContainerDeploymentFilterState { @@ -3469,8 +3532,8 @@ input ContainerDeploymentFilterId { greaterThan: ID lessThanOrEqual: ID greaterThanOrEqual: ID - isDistinctFrom: String - isNotDistinctFrom: String + isDistinctFrom: ID + isNotDistinctFrom: ID } input ContainerDeploymentFilterInput { @@ -3561,6 +3624,7 @@ type ContainerDeployment { "The number of records to return to the end. Maximum 250" last: Int ): DeviceMappingDeploymentConnection! + isReady: Boolean } type container_result { @@ -3618,8 +3682,8 @@ input ContainerFilterImageId { greaterThan: ID lessThanOrEqual: ID greaterThanOrEqual: ID - isDistinctFrom: String - isNotDistinctFrom: String + isDistinctFrom: ID + isNotDistinctFrom: ID } input ContainerFilterReadOnlyRootfs { @@ -3631,8 +3695,8 @@ input ContainerFilterReadOnlyRootfs { greaterThan: Boolean lessThanOrEqual: Boolean greaterThanOrEqual: Boolean - isDistinctFrom: String - isNotDistinctFrom: String + isDistinctFrom: Boolean + isNotDistinctFrom: Boolean } input ContainerFilterVolumeDriver { @@ -3660,8 +3724,8 @@ input ContainerFilterMemorySwappiness { greaterThan: Int lessThanOrEqual: Int greaterThanOrEqual: Int - isDistinctFrom: String - isNotDistinctFrom: String + isDistinctFrom: Int + isNotDistinctFrom: Int } input ContainerFilterMemorySwap { @@ -3673,8 +3737,8 @@ input ContainerFilterMemorySwap { greaterThan: Int lessThanOrEqual: Int greaterThanOrEqual: Int - isDistinctFrom: String - isNotDistinctFrom: String + isDistinctFrom: Int + isNotDistinctFrom: Int } input ContainerFilterMemoryReservation { @@ -3686,8 +3750,8 @@ input ContainerFilterMemoryReservation { greaterThan: Int lessThanOrEqual: Int greaterThanOrEqual: Int - isDistinctFrom: String - isNotDistinctFrom: String + isDistinctFrom: Int + isNotDistinctFrom: Int } input ContainerFilterMemory { @@ -3699,8 +3763,8 @@ input ContainerFilterMemory { greaterThan: Int lessThanOrEqual: Int greaterThanOrEqual: Int - isDistinctFrom: String - isNotDistinctFrom: String + isDistinctFrom: Int + isNotDistinctFrom: Int } input ContainerFilterCpuRealtimeRuntime { @@ -3712,8 +3776,8 @@ input ContainerFilterCpuRealtimeRuntime { greaterThan: Int lessThanOrEqual: Int greaterThanOrEqual: Int - isDistinctFrom: String - isNotDistinctFrom: String + isDistinctFrom: Int + isNotDistinctFrom: Int } input ContainerFilterCpuRealtimePeriod { @@ -3725,8 +3789,8 @@ input ContainerFilterCpuRealtimePeriod { greaterThan: Int lessThanOrEqual: Int greaterThanOrEqual: Int - isDistinctFrom: String - isNotDistinctFrom: String + isDistinctFrom: Int + isNotDistinctFrom: Int } input ContainerFilterCpuQuota { @@ -3738,8 +3802,8 @@ input ContainerFilterCpuQuota { greaterThan: Int lessThanOrEqual: Int greaterThanOrEqual: Int - isDistinctFrom: String - isNotDistinctFrom: String + isDistinctFrom: Int + isNotDistinctFrom: Int } input ContainerFilterCpuPeriod { @@ -3751,8 +3815,8 @@ input ContainerFilterCpuPeriod { greaterThan: Int lessThanOrEqual: Int greaterThanOrEqual: Int - isDistinctFrom: String - isNotDistinctFrom: String + isDistinctFrom: Int + isNotDistinctFrom: Int } input ContainerFilterNetworkMode { @@ -3780,8 +3844,8 @@ input ContainerFilterPrivileged { greaterThan: Boolean lessThanOrEqual: Boolean greaterThanOrEqual: Boolean - isDistinctFrom: String - isNotDistinctFrom: String + isDistinctFrom: Boolean + isNotDistinctFrom: Boolean } input ContainerFilterHostname { @@ -3822,8 +3886,8 @@ input ContainerFilterId { greaterThan: ID lessThanOrEqual: ID greaterThanOrEqual: ID - isDistinctFrom: String - isNotDistinctFrom: String + isDistinctFrom: ID + isNotDistinctFrom: ID } input ContainerFilterInput { @@ -4081,8 +4145,8 @@ input ApplicationFilterId { greaterThan: ID lessThanOrEqual: ID greaterThanOrEqual: ID - isDistinctFrom: String - isNotDistinctFrom: String + isDistinctFrom: ID + isNotDistinctFrom: ID } input ApplicationFilterInput { @@ -4182,8 +4246,8 @@ input SystemModelPartNumberFilterId { greaterThan: Int lessThanOrEqual: Int greaterThanOrEqual: Int - isDistinctFrom: String - isNotDistinctFrom: String + isDistinctFrom: Int + isNotDistinctFrom: Int } input SystemModelPartNumberFilterInput { @@ -4383,8 +4447,8 @@ input SystemModelFilterId { greaterThan: Int lessThanOrEqual: Int greaterThanOrEqual: Int - isDistinctFrom: String - isNotDistinctFrom: String + isDistinctFrom: Int + isNotDistinctFrom: Int } input SystemModelFilterInput { @@ -4546,8 +4610,8 @@ input HardwareTypePartNumberFilterId { greaterThan: Int lessThanOrEqual: Int greaterThanOrEqual: Int - isDistinctFrom: String - isNotDistinctFrom: String + isDistinctFrom: Int + isNotDistinctFrom: Int } input HardwareTypePartNumberFilterInput { @@ -4709,8 +4773,8 @@ input HardwareTypeFilterId { greaterThan: Int lessThanOrEqual: Int greaterThanOrEqual: Int - isDistinctFrom: String - isNotDistinctFrom: String + isDistinctFrom: Int + isNotDistinctFrom: Int } input HardwareTypeFilterInput { @@ -4933,8 +4997,8 @@ input DeviceFilterLastDisconnection { greaterThan: DateTime lessThanOrEqual: DateTime greaterThanOrEqual: DateTime - isDistinctFrom: String - isNotDistinctFrom: String + isDistinctFrom: DateTime + isNotDistinctFrom: DateTime } input DeviceFilterLastConnection { @@ -4946,8 +5010,8 @@ input DeviceFilterLastConnection { greaterThan: DateTime lessThanOrEqual: DateTime greaterThanOrEqual: DateTime - isDistinctFrom: String - isNotDistinctFrom: String + isDistinctFrom: DateTime + isNotDistinctFrom: DateTime } input DeviceFilterOnline { @@ -4959,8 +5023,8 @@ input DeviceFilterOnline { greaterThan: Boolean lessThanOrEqual: Boolean greaterThanOrEqual: Boolean - isDistinctFrom: String - isNotDistinctFrom: String + isDistinctFrom: Boolean + isNotDistinctFrom: Boolean } input DeviceFilterName { @@ -5004,8 +5068,8 @@ input DeviceFilterId { greaterThan: Int lessThanOrEqual: Int greaterThanOrEqual: Int - isDistinctFrom: String - isNotDistinctFrom: String + isDistinctFrom: Int + isNotDistinctFrom: Int } input DeviceFilterInput { @@ -5463,8 +5527,8 @@ input FileDownloadRequestFilterResponseCode { greaterThan: Int lessThanOrEqual: Int greaterThanOrEqual: Int - isDistinctFrom: String - isNotDistinctFrom: String + isDistinctFrom: Int + isNotDistinctFrom: Int } input FileDownloadRequestFilterProgressPercentage { @@ -5476,8 +5540,8 @@ input FileDownloadRequestFilterProgressPercentage { greaterThan: Int lessThanOrEqual: Int greaterThanOrEqual: Int - isDistinctFrom: String - isNotDistinctFrom: String + isDistinctFrom: Int + isNotDistinctFrom: Int } input FileDownloadRequestFilterStatus { @@ -5489,8 +5553,8 @@ input FileDownloadRequestFilterStatus { greaterThan: FileDownloadRequestStatus lessThanOrEqual: FileDownloadRequestStatus greaterThanOrEqual: FileDownloadRequestStatus - isDistinctFrom: String - isNotDistinctFrom: String + isDistinctFrom: FileDownloadRequestStatus + isNotDistinctFrom: FileDownloadRequestStatus } input FileDownloadRequestFilterProgressTracked { @@ -5502,8 +5566,8 @@ input FileDownloadRequestFilterProgressTracked { greaterThan: Boolean lessThanOrEqual: Boolean greaterThanOrEqual: Boolean - isDistinctFrom: String - isNotDistinctFrom: String + isDistinctFrom: Boolean + isNotDistinctFrom: Boolean } input FileDownloadRequestFilterPathOnDevice { @@ -5547,8 +5611,8 @@ input FileDownloadRequestFilterDestinationType { greaterThan: FileDestination lessThanOrEqual: FileDestination greaterThanOrEqual: FileDestination - isDistinctFrom: String - isNotDistinctFrom: String + isDistinctFrom: FileDestination + isNotDistinctFrom: FileDestination } input FileDownloadRequestFilterGroupId { @@ -5560,8 +5624,8 @@ input FileDownloadRequestFilterGroupId { greaterThan: Int lessThanOrEqual: Int greaterThanOrEqual: Int - isDistinctFrom: String - isNotDistinctFrom: String + isDistinctFrom: Int + isNotDistinctFrom: Int } input FileDownloadRequestFilterUserId { @@ -5573,8 +5637,8 @@ input FileDownloadRequestFilterUserId { greaterThan: Int lessThanOrEqual: Int greaterThanOrEqual: Int - isDistinctFrom: String - isNotDistinctFrom: String + isDistinctFrom: Int + isNotDistinctFrom: Int } input FileDownloadRequestFilterFileMode { @@ -5586,8 +5650,8 @@ input FileDownloadRequestFilterFileMode { greaterThan: Int lessThanOrEqual: Int greaterThanOrEqual: Int - isDistinctFrom: String - isNotDistinctFrom: String + isDistinctFrom: Int + isNotDistinctFrom: Int } input FileDownloadRequestFilterTtlSeconds { @@ -5599,8 +5663,8 @@ input FileDownloadRequestFilterTtlSeconds { greaterThan: Int lessThanOrEqual: Int greaterThanOrEqual: Int - isDistinctFrom: String - isNotDistinctFrom: String + isDistinctFrom: Int + isNotDistinctFrom: Int } input FileDownloadRequestFilterCompression { @@ -5644,8 +5708,8 @@ input FileDownloadRequestFilterUncompressedFileSizeBytes { greaterThan: Int lessThanOrEqual: Int greaterThanOrEqual: Int - isDistinctFrom: String - isNotDistinctFrom: String + isDistinctFrom: Int + isNotDistinctFrom: Int } input FileDownloadRequestFilterFileName { @@ -5689,8 +5753,8 @@ input FileDownloadRequestFilterId { greaterThan: ID lessThanOrEqual: ID greaterThanOrEqual: ID - isDistinctFrom: String - isNotDistinctFrom: String + isDistinctFrom: ID + isNotDistinctFrom: ID } input FileDownloadRequestFilterInput { @@ -5973,8 +6037,8 @@ input RepositoryFilterId { greaterThan: ID lessThanOrEqual: ID greaterThanOrEqual: ID - isDistinctFrom: String - isNotDistinctFrom: String + isDistinctFrom: ID + isNotDistinctFrom: ID } input RepositoryFilterInput { @@ -6131,8 +6195,8 @@ input FileFilterFileUploaded { greaterThan: Boolean lessThanOrEqual: Boolean greaterThanOrEqual: Boolean - isDistinctFrom: String - isNotDistinctFrom: String + isDistinctFrom: Boolean + isNotDistinctFrom: Boolean } input FileFilterDigest { @@ -6160,8 +6224,8 @@ input FileFilterSize { greaterThan: Int lessThanOrEqual: Int greaterThanOrEqual: Int - isDistinctFrom: String - isNotDistinctFrom: String + isDistinctFrom: Int + isNotDistinctFrom: Int } input FileFilterName { @@ -6189,8 +6253,8 @@ input FileFilterId { greaterThan: ID lessThanOrEqual: ID greaterThanOrEqual: ID - isDistinctFrom: String - isNotDistinctFrom: String + isDistinctFrom: ID + isNotDistinctFrom: ID } input FileFilterInput { @@ -6444,8 +6508,8 @@ input DeviceGroupFilterId { greaterThan: Int lessThanOrEqual: Int greaterThanOrEqual: Int - isDistinctFrom: String - isNotDistinctFrom: String + isDistinctFrom: Int + isNotDistinctFrom: Int } input DeviceGroupFilterInput { @@ -6576,8 +6640,8 @@ input TagFilterId { greaterThan: Int lessThanOrEqual: Int greaterThanOrEqual: Int - isDistinctFrom: String - isNotDistinctFrom: String + isDistinctFrom: Int + isNotDistinctFrom: Int } input TagFilterInput { @@ -6675,8 +6739,8 @@ input OtaOperationFilterUpdatedAt { greaterThan: DateTime lessThanOrEqual: DateTime greaterThanOrEqual: DateTime - isDistinctFrom: String - isNotDistinctFrom: String + isDistinctFrom: DateTime + isNotDistinctFrom: DateTime } input OtaOperationFilterCreatedAt { @@ -6688,8 +6752,8 @@ input OtaOperationFilterCreatedAt { greaterThan: DateTime lessThanOrEqual: DateTime greaterThanOrEqual: DateTime - isDistinctFrom: String - isNotDistinctFrom: String + isDistinctFrom: DateTime + isNotDistinctFrom: DateTime } input OtaOperationFilterMessage { @@ -6717,8 +6781,8 @@ input OtaOperationFilterStatusCode { greaterThan: OtaOperationStatusCode lessThanOrEqual: OtaOperationStatusCode greaterThanOrEqual: OtaOperationStatusCode - isDistinctFrom: String - isNotDistinctFrom: String + isDistinctFrom: OtaOperationStatusCode + isNotDistinctFrom: OtaOperationStatusCode } input OtaOperationFilterStatusProgress { @@ -6730,8 +6794,8 @@ input OtaOperationFilterStatusProgress { greaterThan: Int lessThanOrEqual: Int greaterThanOrEqual: Int - isDistinctFrom: String - isNotDistinctFrom: String + isDistinctFrom: Int + isNotDistinctFrom: Int } input OtaOperationFilterStatus { @@ -6743,8 +6807,8 @@ input OtaOperationFilterStatus { greaterThan: OtaOperationStatus lessThanOrEqual: OtaOperationStatus greaterThanOrEqual: OtaOperationStatus - isDistinctFrom: String - isNotDistinctFrom: String + isDistinctFrom: OtaOperationStatus + isNotDistinctFrom: OtaOperationStatus } input OtaOperationFilterBaseImageUrl { @@ -6772,8 +6836,8 @@ input OtaOperationFilterId { greaterThan: ID lessThanOrEqual: ID greaterThanOrEqual: ID - isDistinctFrom: String - isNotDistinctFrom: String + isDistinctFrom: ID + isNotDistinctFrom: ID } input OtaOperationFilterInput { @@ -7000,8 +7064,8 @@ input ChannelFilterId { greaterThan: Int lessThanOrEqual: Int greaterThanOrEqual: Int - isDistinctFrom: String - isNotDistinctFrom: String + isDistinctFrom: Int + isNotDistinctFrom: Int } input ChannelFilterInput { @@ -7132,8 +7196,8 @@ input CampaignTargetFilterCompletionTimestamp { greaterThan: DateTime lessThanOrEqual: DateTime greaterThanOrEqual: DateTime - isDistinctFrom: String - isNotDistinctFrom: String + isDistinctFrom: DateTime + isNotDistinctFrom: DateTime } input CampaignTargetFilterLatestAttempt { @@ -7145,8 +7209,8 @@ input CampaignTargetFilterLatestAttempt { greaterThan: DateTime lessThanOrEqual: DateTime greaterThanOrEqual: DateTime - isDistinctFrom: String - isNotDistinctFrom: String + isDistinctFrom: DateTime + isNotDistinctFrom: DateTime } input CampaignTargetFilterRetryCount { @@ -7158,8 +7222,8 @@ input CampaignTargetFilterRetryCount { greaterThan: Int lessThanOrEqual: Int greaterThanOrEqual: Int - isDistinctFrom: String - isNotDistinctFrom: String + isDistinctFrom: Int + isNotDistinctFrom: Int } input CampaignTargetFilterStatus { @@ -7171,8 +7235,8 @@ input CampaignTargetFilterStatus { greaterThan: CampaignTargetStatus lessThanOrEqual: CampaignTargetStatus greaterThanOrEqual: CampaignTargetStatus - isDistinctFrom: String - isNotDistinctFrom: String + isDistinctFrom: CampaignTargetStatus + isNotDistinctFrom: CampaignTargetStatus } input CampaignTargetFilterId { @@ -7184,8 +7248,8 @@ input CampaignTargetFilterId { greaterThan: ID lessThanOrEqual: ID greaterThanOrEqual: ID - isDistinctFrom: String - isNotDistinctFrom: String + isDistinctFrom: ID + isNotDistinctFrom: ID } input CampaignTargetFilterInput { @@ -7375,8 +7439,8 @@ input CampaignFilterSuccessfulTargetCount { greaterThan: Int lessThanOrEqual: Int greaterThanOrEqual: Int - isDistinctFrom: String - isNotDistinctFrom: String + isDistinctFrom: Int + isNotDistinctFrom: Int } input CampaignFilterFailedTargetCount { @@ -7388,8 +7452,8 @@ input CampaignFilterFailedTargetCount { greaterThan: Int lessThanOrEqual: Int greaterThanOrEqual: Int - isDistinctFrom: String - isNotDistinctFrom: String + isDistinctFrom: Int + isNotDistinctFrom: Int } input CampaignFilterInProgressTargetCount { @@ -7401,8 +7465,8 @@ input CampaignFilterInProgressTargetCount { greaterThan: Int lessThanOrEqual: Int greaterThanOrEqual: Int - isDistinctFrom: String - isNotDistinctFrom: String + isDistinctFrom: Int + isNotDistinctFrom: Int } input CampaignFilterIdleTargetCount { @@ -7414,8 +7478,8 @@ input CampaignFilterIdleTargetCount { greaterThan: Int lessThanOrEqual: Int greaterThanOrEqual: Int - isDistinctFrom: String - isNotDistinctFrom: String + isDistinctFrom: Int + isNotDistinctFrom: Int } input CampaignFilterTotalTargetCount { @@ -7427,8 +7491,8 @@ input CampaignFilterTotalTargetCount { greaterThan: Int lessThanOrEqual: Int greaterThanOrEqual: Int - isDistinctFrom: String - isNotDistinctFrom: String + isDistinctFrom: Int + isNotDistinctFrom: Int } input CampaignFilterOutcome { @@ -7440,8 +7504,8 @@ input CampaignFilterOutcome { greaterThan: CampaignOutcome lessThanOrEqual: CampaignOutcome greaterThanOrEqual: CampaignOutcome - isDistinctFrom: String - isNotDistinctFrom: String + isDistinctFrom: CampaignOutcome + isNotDistinctFrom: CampaignOutcome } input CampaignFilterStatus { @@ -7453,8 +7517,8 @@ input CampaignFilterStatus { greaterThan: CampaignStatus lessThanOrEqual: CampaignStatus greaterThanOrEqual: CampaignStatus - isDistinctFrom: String - isNotDistinctFrom: String + isDistinctFrom: CampaignStatus + isNotDistinctFrom: CampaignStatus } input CampaignFilterName { @@ -7482,8 +7546,8 @@ input CampaignFilterId { greaterThan: ID lessThanOrEqual: ID greaterThanOrEqual: ID - isDistinctFrom: String - isNotDistinctFrom: String + isDistinctFrom: ID + isNotDistinctFrom: ID } input CampaignFilterInput { diff --git a/frontend/src/components/DeploymentDetails.tsx b/frontend/src/components/DeploymentDetails.tsx index 48157fa8b..f69cb79cf 100644 --- a/frontend/src/components/DeploymentDetails.tsx +++ b/frontend/src/components/DeploymentDetails.tsx @@ -51,6 +51,7 @@ import DeploymentStateComponent, { parseDeploymentState, } from "./DeploymentState"; import CollapseItem, { useCollapseToggle } from "@/components/CollapseItem"; +import ResourceStateIcon from "@/components/ResourceStateIcon"; const DEPLOYMENT_DETAILS_EVENTS_PAGINATION_FRAGMENT = graphql` fragment DeploymentDetails_events on Deployment @@ -88,6 +89,7 @@ const DEPLOYMENT_DETAILS_CONTAINER_DEPLOYMENTS_FRAGMENT = graphql` } imageDeployment { state + isReady image { id reference @@ -109,6 +111,7 @@ const DEPLOYMENT_DETAILS_NETWORK_DEPLOYMENTS_FRAGMENT = graphql` node { id state + isReady network { id label @@ -127,6 +130,7 @@ const DEPLOYMENT_DETAILS_VOLUME_DEPLOYMENTS_FRAGMENT = graphql` node { id state + isReady volume { id label @@ -145,6 +149,7 @@ const DEPLOYMENT_DETAILS_DEVICE_MAPPING_DEPLOYMENTS_FRAGMENT = graphql` node { id state + isReady deviceMapping { id pathOnHost @@ -277,7 +282,12 @@ const networkColumns = [ defaultMessage="State" /> ), - cell: ({ row }) => row.original.state ?? "", + cell: ({ row }) => ( + + ), }), ]; @@ -307,7 +317,12 @@ const volumeColumns = [ defaultMessage="State" /> ), - cell: ({ row }) => row.original.state ?? "", + cell: ({ row }) => ( + + ), }), ]; @@ -340,7 +355,12 @@ const deviceMappingColumns = [ defaultMessage="State" /> ), - cell: ({ row }) => row.original.state ?? "", + cell: ({ row }) => ( + + ), }), ]; @@ -427,7 +447,10 @@ const ContainerDeploymentItem = ({ defaultMessage={" Image Status: "} /> - {imageDeployment.state} + )} diff --git a/frontend/src/components/Icon.tsx b/frontend/src/components/Icon.tsx index 449a32d26..0f8223363 100644 --- a/frontend/src/components/Icon.tsx +++ b/frontend/src/components/Icon.tsx @@ -19,6 +19,10 @@ */ import { faGithub } from "@fortawesome/free-brands-svg-icons"; +import { + faCircle as faCircleRegular, + faCircleCheck as faCircleCheckRegular, +} from "@fortawesome/free-regular-svg-icons"; import { faAngleDown, faAngleUp, @@ -63,6 +67,8 @@ const icons = { caretDown: faAngleDown, caretUp: faAngleUp, circle: faCircle, + circleCheck: faCircleCheckRegular, + circleEmpty: faCircleRegular, delete: faTrash, devices: faTabletAlt, deviceGroups: faDatabase, diff --git a/frontend/src/components/ResourceStateIcon.tsx b/frontend/src/components/ResourceStateIcon.tsx new file mode 100644 index 000000000..622ecafa0 --- /dev/null +++ b/frontend/src/components/ResourceStateIcon.tsx @@ -0,0 +1,60 @@ +// This file is part of Edgehog. +// +// Copyright 2026 SECO Mind Srl +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// SPDX-License-Identifier: Apache-2.0 + +import Icon from "@/components/Icon"; + +const AVAILABLE_STATES = new Set(["available", "pulled", "present"]); + +type ResourceStateIconProps = { + state: string | null | undefined; + isReady: boolean | null | undefined; +}; + +const ResourceStateIcon = ({ state, isReady }: ResourceStateIconProps) => { + if (!isReady) { + return ( + + ); + } + + const normalizedState = state?.toLowerCase(); + + if (normalizedState && AVAILABLE_STATES.has(normalizedState)) { + return ( + + ); + } + + return ( + + ); +}; + +export default ResourceStateIcon;