@flightctl/ui-components 0.4.0 → 0.5.0-rc2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (384) hide show
  1. package/dist/src/components/DetailsPage/DetailsPageActions.d.ts +11 -4
  2. package/dist/src/components/DetailsPage/DetailsPageActions.d.ts.map +1 -1
  3. package/dist/src/components/DetailsPage/DetailsPageActions.js +15 -4
  4. package/dist/src/components/DetailsPage/DetailsPageActions.js.map +1 -1
  5. package/dist/src/components/DetailsPage/Tables/ApplicationsTable.js +1 -1
  6. package/dist/src/components/DetailsPage/Tables/ApplicationsTable.js.map +1 -1
  7. package/dist/src/components/Device/DeviceDetails/DeviceApplications.d.ts +1 -1
  8. package/dist/src/components/Device/DeviceDetails/DeviceApplications.d.ts.map +1 -1
  9. package/dist/src/components/Device/DeviceDetails/DeviceApplications.js +2 -2
  10. package/dist/src/components/Device/DeviceDetails/DeviceApplications.js.map +1 -1
  11. package/dist/src/components/Device/DeviceDetails/DeviceDetailsPage.d.ts.map +1 -1
  12. package/dist/src/components/Device/DeviceDetails/DeviceDetailsPage.js +22 -15
  13. package/dist/src/components/Device/DeviceDetails/DeviceDetailsPage.js.map +1 -1
  14. package/dist/src/components/Device/DeviceDetails/DeviceDetailsTab.d.ts.map +1 -1
  15. package/dist/src/components/Device/DeviceDetails/DeviceDetailsTab.js +42 -39
  16. package/dist/src/components/Device/DeviceDetails/DeviceDetailsTab.js.map +1 -1
  17. package/dist/src/components/Device/DeviceDetails/DeviceDetailsTabContent/StatusContent.d.ts +7 -0
  18. package/dist/src/components/Device/DeviceDetails/DeviceDetailsTabContent/StatusContent.d.ts.map +1 -0
  19. package/dist/src/components/Device/DeviceDetails/DeviceDetailsTabContent/StatusContent.js +41 -0
  20. package/dist/src/components/Device/DeviceDetails/DeviceDetailsTabContent/StatusContent.js.map +1 -0
  21. package/dist/src/components/Device/DeviceDetails/DeviceDetailsTabContent/SystemResourcesContent.d.ts +7 -0
  22. package/dist/src/components/Device/DeviceDetails/DeviceDetailsTabContent/SystemResourcesContent.d.ts.map +1 -0
  23. package/dist/src/components/Device/DeviceDetails/DeviceDetailsTabContent/SystemResourcesContent.js +30 -0
  24. package/dist/src/components/Device/DeviceDetails/DeviceDetailsTabContent/SystemResourcesContent.js.map +1 -0
  25. package/dist/src/components/Device/DeviceDetails/TerminalTab.d.ts.map +1 -1
  26. package/dist/src/components/Device/DeviceDetails/TerminalTab.js +1 -1
  27. package/dist/src/components/Device/DeviceDetails/TerminalTab.js.map +1 -1
  28. package/dist/src/components/Device/DevicesPage/DecommissionedDeviceTableRow.d.ts +16 -0
  29. package/dist/src/components/Device/DevicesPage/DecommissionedDeviceTableRow.d.ts.map +1 -0
  30. package/dist/src/components/Device/DevicesPage/DecommissionedDeviceTableRow.js +57 -0
  31. package/dist/src/components/Device/DevicesPage/DecommissionedDeviceTableRow.js.map +1 -0
  32. package/dist/src/components/Device/DevicesPage/DecommissionedDevicesTable.d.ts +16 -0
  33. package/dist/src/components/Device/DevicesPage/DecommissionedDevicesTable.d.ts.map +1 -0
  34. package/dist/src/components/Device/DevicesPage/DecommissionedDevicesTable.js +73 -0
  35. package/dist/src/components/Device/DevicesPage/DecommissionedDevicesTable.js.map +1 -0
  36. package/dist/src/components/Device/DevicesPage/DeviceNameOnlyToolbarFilter.d.ts +10 -0
  37. package/dist/src/components/Device/DevicesPage/DeviceNameOnlyToolbarFilter.d.ts.map +1 -0
  38. package/dist/src/components/Device/DevicesPage/DeviceNameOnlyToolbarFilter.js +19 -0
  39. package/dist/src/components/Device/DevicesPage/DeviceNameOnlyToolbarFilter.js.map +1 -0
  40. package/dist/src/components/Device/DevicesPage/DevicesEmptyStates.d.ts +8 -0
  41. package/dist/src/components/Device/DevicesPage/DevicesEmptyStates.d.ts.map +1 -0
  42. package/dist/src/components/Device/DevicesPage/DevicesEmptyStates.js +34 -0
  43. package/dist/src/components/Device/DevicesPage/DevicesEmptyStates.js.map +1 -0
  44. package/dist/src/components/Device/DevicesPage/DevicesPage.d.ts +0 -22
  45. package/dist/src/components/Device/DevicesPage/DevicesPage.d.ts.map +1 -1
  46. package/dist/src/components/Device/DevicesPage/DevicesPage.js +9 -92
  47. package/dist/src/components/Device/DevicesPage/DevicesPage.js.map +1 -1
  48. package/dist/src/components/Device/DevicesPage/EnrolledDeviceTableRow.d.ts +16 -0
  49. package/dist/src/components/Device/DevicesPage/EnrolledDeviceTableRow.d.ts.map +1 -0
  50. package/dist/src/components/Device/DevicesPage/{DeviceTableRow.js → EnrolledDeviceTableRow.js} +9 -13
  51. package/dist/src/components/Device/DevicesPage/EnrolledDeviceTableRow.js.map +1 -0
  52. package/dist/src/components/Device/DevicesPage/EnrolledDevicesTable.d.ts +23 -0
  53. package/dist/src/components/Device/DevicesPage/EnrolledDevicesTable.d.ts.map +1 -0
  54. package/dist/src/components/Device/DevicesPage/EnrolledDevicesTable.js +99 -0
  55. package/dist/src/components/Device/DevicesPage/EnrolledDevicesTable.js.map +1 -0
  56. package/dist/src/components/Device/DevicesPage/useDevices.d.ts +2 -0
  57. package/dist/src/components/Device/DevicesPage/useDevices.d.ts.map +1 -1
  58. package/dist/src/components/Device/DevicesPage/useDevices.js +16 -1
  59. package/dist/src/components/Device/DevicesPage/useDevices.js.map +1 -1
  60. package/dist/src/components/Device/EditDeviceWizard/EditDeviceWizard.d.ts.map +1 -1
  61. package/dist/src/components/Device/EditDeviceWizard/EditDeviceWizard.js +5 -3
  62. package/dist/src/components/Device/EditDeviceWizard/EditDeviceWizard.js.map +1 -1
  63. package/dist/src/components/Device/EditDeviceWizard/EditDeviceWizardNav.js +1 -1
  64. package/dist/src/components/Device/EditDeviceWizard/EditDeviceWizardNav.js.map +1 -1
  65. package/dist/src/components/Device/EditDeviceWizard/steps/ApplicationTemplates.d.ts.map +1 -1
  66. package/dist/src/components/Device/EditDeviceWizard/steps/ApplicationTemplates.js +2 -2
  67. package/dist/src/components/Device/EditDeviceWizard/steps/ApplicationTemplates.js.map +1 -1
  68. package/dist/src/components/Device/EditDeviceWizard/steps/ConfigInlineTemplateForm.d.ts.map +1 -1
  69. package/dist/src/components/Device/EditDeviceWizard/steps/ConfigInlineTemplateForm.js +1 -1
  70. package/dist/src/components/Device/EditDeviceWizard/steps/ConfigInlineTemplateForm.js.map +1 -1
  71. package/dist/src/components/Device/EditDeviceWizard/steps/ConfigurationTemplates.d.ts.map +1 -1
  72. package/dist/src/components/Device/EditDeviceWizard/steps/ConfigurationTemplates.js +1 -1
  73. package/dist/src/components/Device/EditDeviceWizard/steps/ConfigurationTemplates.js.map +1 -1
  74. package/dist/src/components/Device/EditDeviceWizard/steps/ReviewDeviceStep.d.ts.map +1 -1
  75. package/dist/src/components/Device/EditDeviceWizard/steps/ReviewDeviceStep.js +7 -7
  76. package/dist/src/components/Device/EditDeviceWizard/steps/ReviewDeviceStep.js.map +1 -1
  77. package/dist/src/components/Device/EditDeviceWizard/steps/ReviewUpdatePolicy.d.ts +9 -0
  78. package/dist/src/components/Device/EditDeviceWizard/steps/ReviewUpdatePolicy.d.ts.map +1 -0
  79. package/dist/src/components/Device/EditDeviceWizard/steps/ReviewUpdatePolicy.js +37 -0
  80. package/dist/src/components/Device/EditDeviceWizard/steps/ReviewUpdatePolicy.js.map +1 -0
  81. package/dist/src/components/Device/EditDeviceWizard/steps/SystemdUnitsForm.d.ts.map +1 -1
  82. package/dist/src/components/Device/EditDeviceWizard/steps/SystemdUnitsForm.js +6 -4
  83. package/dist/src/components/Device/EditDeviceWizard/steps/SystemdUnitsForm.js.map +1 -1
  84. package/dist/src/components/Device/EditDeviceWizard/utils.d.ts +1 -1
  85. package/dist/src/components/EnrollmentRequest/EnrollmentRequestDetails/EnrollmentRequestDetails.d.ts.map +1 -1
  86. package/dist/src/components/EnrollmentRequest/EnrollmentRequestDetails/EnrollmentRequestDetails.js +4 -13
  87. package/dist/src/components/EnrollmentRequest/EnrollmentRequestDetails/EnrollmentRequestDetails.js.map +1 -1
  88. package/dist/src/components/EnrollmentRequest/EnrollmentRequestList.js +2 -2
  89. package/dist/src/components/EnrollmentRequest/EnrollmentRequestList.js.map +1 -1
  90. package/dist/src/components/EnrollmentRequest/EnrollmentRequestTableRow.d.ts +2 -2
  91. package/dist/src/components/EnrollmentRequest/EnrollmentRequestTableRow.d.ts.map +1 -1
  92. package/dist/src/components/EnrollmentRequest/useEnrollmentRequests.d.ts +2 -2
  93. package/dist/src/components/EnrollmentRequest/useEnrollmentRequests.d.ts.map +1 -1
  94. package/dist/src/components/EnrollmentRequest/useEnrollmentRequests.js.map +1 -1
  95. package/dist/src/components/Fleet/CreateFleet/CreateFleetWizard.d.ts.map +1 -1
  96. package/dist/src/components/Fleet/CreateFleet/CreateFleetWizard.js +32 -3
  97. package/dist/src/components/Fleet/CreateFleet/CreateFleetWizard.js.map +1 -1
  98. package/dist/src/components/Fleet/CreateFleet/CreateFleetWizardFooter.d.ts.map +1 -1
  99. package/dist/src/components/Fleet/CreateFleet/CreateFleetWizardFooter.js +4 -0
  100. package/dist/src/components/Fleet/CreateFleet/CreateFleetWizardFooter.js.map +1 -1
  101. package/dist/src/components/Fleet/CreateFleet/fleetSpecUtils.d.ts +26 -0
  102. package/dist/src/components/Fleet/CreateFleet/fleetSpecUtils.d.ts.map +1 -0
  103. package/dist/src/components/Fleet/CreateFleet/fleetSpecUtils.js +63 -0
  104. package/dist/src/components/Fleet/CreateFleet/fleetSpecUtils.js.map +1 -0
  105. package/dist/src/components/Fleet/CreateFleet/steps/ReviewStep.d.ts.map +1 -1
  106. package/dist/src/components/Fleet/CreateFleet/steps/ReviewStep.js +19 -10
  107. package/dist/src/components/Fleet/CreateFleet/steps/ReviewStep.js.map +1 -1
  108. package/dist/src/components/Fleet/CreateFleet/steps/UpdateConfirmChangesModal.d.ts +9 -0
  109. package/dist/src/components/Fleet/CreateFleet/steps/UpdateConfirmChangesModal.d.ts.map +1 -0
  110. package/dist/src/components/Fleet/CreateFleet/steps/UpdateConfirmChangesModal.js +52 -0
  111. package/dist/src/components/Fleet/CreateFleet/steps/UpdateConfirmChangesModal.js.map +1 -0
  112. package/dist/src/components/Fleet/CreateFleet/steps/UpdatePolicyStep.d.ts +8 -0
  113. package/dist/src/components/Fleet/CreateFleet/steps/UpdatePolicyStep.d.ts.map +1 -0
  114. package/dist/src/components/Fleet/CreateFleet/steps/UpdatePolicyStep.js +95 -0
  115. package/dist/src/components/Fleet/CreateFleet/steps/UpdatePolicyStep.js.map +1 -0
  116. package/dist/src/components/Fleet/CreateFleet/steps/UpdateStepDisruptionBudget.d.ts +4 -0
  117. package/dist/src/components/Fleet/CreateFleet/steps/UpdateStepDisruptionBudget.d.ts.map +1 -0
  118. package/dist/src/components/Fleet/CreateFleet/steps/UpdateStepDisruptionBudget.js +31 -0
  119. package/dist/src/components/Fleet/CreateFleet/steps/UpdateStepDisruptionBudget.js.map +1 -0
  120. package/dist/src/components/Fleet/CreateFleet/steps/UpdateStepRolloutPolicy.d.ts +4 -0
  121. package/dist/src/components/Fleet/CreateFleet/steps/UpdateStepRolloutPolicy.d.ts.map +1 -0
  122. package/dist/src/components/Fleet/CreateFleet/steps/UpdateStepRolloutPolicy.js +78 -0
  123. package/dist/src/components/Fleet/CreateFleet/steps/UpdateStepRolloutPolicy.js.map +1 -0
  124. package/dist/src/components/Fleet/CreateFleet/types.d.ts +21 -0
  125. package/dist/src/components/Fleet/CreateFleet/types.d.ts.map +1 -1
  126. package/dist/src/components/Fleet/CreateFleet/types.js +6 -0
  127. package/dist/src/components/Fleet/CreateFleet/types.js.map +1 -1
  128. package/dist/src/components/Fleet/CreateFleet/utils.d.ts.map +1 -1
  129. package/dist/src/components/Fleet/CreateFleet/utils.js +15 -1
  130. package/dist/src/components/Fleet/CreateFleet/utils.js.map +1 -1
  131. package/dist/src/components/Fleet/FleetDetails/FleetDetailsContent.d.ts.map +1 -1
  132. package/dist/src/components/Fleet/FleetDetails/FleetDetailsContent.js +9 -7
  133. package/dist/src/components/Fleet/FleetDetails/FleetDetailsContent.js.map +1 -1
  134. package/dist/src/components/Fleet/FleetDetails/FleetDevicesCharts.d.ts +9 -0
  135. package/dist/src/components/Fleet/FleetDetails/FleetDevicesCharts.d.ts.map +1 -0
  136. package/dist/src/components/Fleet/FleetDetails/{FleetDevices.js → FleetDevicesCharts.js} +4 -4
  137. package/dist/src/components/Fleet/FleetDetails/FleetDevicesCharts.js.map +1 -0
  138. package/dist/src/components/Fleet/FleetDetails/FleetDevicesCount.d.ts +10 -0
  139. package/dist/src/components/Fleet/FleetDetails/FleetDevicesCount.d.ts.map +1 -0
  140. package/dist/src/components/Fleet/FleetDetails/FleetDevicesCount.js +30 -0
  141. package/dist/src/components/Fleet/FleetDetails/FleetDevicesCount.js.map +1 -0
  142. package/dist/src/components/Fleet/FleetResourceSyncs.js +2 -2
  143. package/dist/src/components/Fleet/FleetResourceSyncs.js.map +1 -1
  144. package/dist/src/components/Fleet/FleetRow.d.ts.map +1 -1
  145. package/dist/src/components/Fleet/FleetRow.js +7 -5
  146. package/dist/src/components/Fleet/FleetRow.js.map +1 -1
  147. package/dist/src/components/Fleet/FleetsPage.js +2 -2
  148. package/dist/src/components/Fleet/FleetsPage.js.map +1 -1
  149. package/dist/src/components/Fleet/useFleets.d.ts +3 -3
  150. package/dist/src/components/Fleet/useFleets.d.ts.map +1 -1
  151. package/dist/src/components/Fleet/useFleets.js +3 -3
  152. package/dist/src/components/Fleet/useFleets.js.map +1 -1
  153. package/dist/src/components/ListPage/ListPage.d.ts.map +1 -1
  154. package/dist/src/components/ListPage/ListPage.js +6 -1
  155. package/dist/src/components/ListPage/ListPage.js.map +1 -1
  156. package/dist/src/components/ListPage/ListPageActions.d.ts +8 -15
  157. package/dist/src/components/ListPage/ListPageActions.d.ts.map +1 -1
  158. package/dist/src/components/ListPage/ListPageActions.js +25 -5
  159. package/dist/src/components/ListPage/ListPageActions.js.map +1 -1
  160. package/dist/src/components/ListPage/types.d.ts +11 -11
  161. package/dist/src/components/ListPage/types.d.ts.map +1 -1
  162. package/dist/src/components/OverviewPage/Cards/Status/DeviceStatusChart.d.ts.map +1 -1
  163. package/dist/src/components/OverviewPage/Cards/Status/DeviceStatusChart.js +0 -1
  164. package/dist/src/components/OverviewPage/Cards/Status/DeviceStatusChart.js.map +1 -1
  165. package/dist/src/components/OverviewPage/OverviewPage.d.ts.map +1 -1
  166. package/dist/src/components/OverviewPage/OverviewPage.js +6 -1
  167. package/dist/src/components/OverviewPage/OverviewPage.js.map +1 -1
  168. package/dist/src/components/Repository/RepositoryDetails/RepositoryResourceSyncsCard.js +1 -1
  169. package/dist/src/components/Repository/RepositoryDetails/RepositoryResourceSyncsCard.js.map +1 -1
  170. package/dist/src/components/Repository/useRepositories.d.ts +2 -2
  171. package/dist/src/components/Repository/useRepositories.d.ts.map +1 -1
  172. package/dist/src/components/Repository/useRepositories.js.map +1 -1
  173. package/dist/src/components/ResourceSync/RepositoryResourceSyncList.js +2 -2
  174. package/dist/src/components/ResourceSync/RepositoryResourceSyncList.js.map +1 -1
  175. package/dist/src/components/Status/DeviceLifecycleStatus.d.ts +7 -0
  176. package/dist/src/components/Status/DeviceLifecycleStatus.d.ts.map +1 -0
  177. package/dist/src/components/Status/DeviceLifecycleStatus.js +25 -0
  178. package/dist/src/components/Status/DeviceLifecycleStatus.js.map +1 -0
  179. package/dist/src/components/Status/StatusDisplay.d.ts +1 -1
  180. package/dist/src/components/Status/StatusDisplay.d.ts.map +1 -1
  181. package/dist/src/components/Status/StatusDisplay.js +3 -3
  182. package/dist/src/components/Status/StatusDisplay.js.map +1 -1
  183. package/dist/src/components/Table/Table.d.ts.map +1 -1
  184. package/dist/src/components/Table/Table.js +2 -2
  185. package/dist/src/components/Table/Table.js.map +1 -1
  186. package/dist/src/components/Table/TablePagination.d.ts +4 -3
  187. package/dist/src/components/Table/TablePagination.d.ts.map +1 -1
  188. package/dist/src/components/Table/TablePagination.js +6 -5
  189. package/dist/src/components/Table/TablePagination.js.map +1 -1
  190. package/dist/src/components/common/EditableLabelControl.d.ts.map +1 -1
  191. package/dist/src/components/common/EditableLabelControl.js +5 -7
  192. package/dist/src/components/common/EditableLabelControl.js.map +1 -1
  193. package/dist/src/components/common/TechPreviewBadge.d.ts +4 -0
  194. package/dist/src/components/common/TechPreviewBadge.d.ts.map +1 -0
  195. package/dist/src/components/common/TechPreviewBadge.js +23 -0
  196. package/dist/src/components/common/TechPreviewBadge.js.map +1 -0
  197. package/dist/src/components/form/LabelsField.d.ts.map +1 -1
  198. package/dist/src/components/form/LabelsField.js +4 -1
  199. package/dist/src/components/form/LabelsField.js.map +1 -1
  200. package/dist/src/components/form/NumberField.d.ts +10 -0
  201. package/dist/src/components/form/NumberField.d.ts.map +1 -0
  202. package/dist/src/components/form/NumberField.js +51 -0
  203. package/dist/src/components/form/NumberField.js.map +1 -0
  204. package/dist/src/components/form/TextListField.d.ts +12 -0
  205. package/dist/src/components/form/TextListField.d.ts.map +1 -0
  206. package/dist/src/components/form/TextListField.js +46 -0
  207. package/dist/src/components/form/TextListField.js.map +1 -0
  208. package/dist/src/components/form/validations.d.ts +34 -6
  209. package/dist/src/components/form/validations.d.ts.map +1 -1
  210. package/dist/src/components/form/validations.js +78 -4
  211. package/dist/src/components/form/validations.js.map +1 -1
  212. package/dist/src/components/modals/DecommissionModal/DecommissionModal.d.ts +9 -0
  213. package/dist/src/components/modals/DecommissionModal/DecommissionModal.d.ts.map +1 -0
  214. package/dist/src/components/modals/DecommissionModal/DecommissionModal.js +51 -0
  215. package/dist/src/components/modals/DecommissionModal/DecommissionModal.js.map +1 -0
  216. package/dist/src/components/modals/EditLabelsModal/EditLabelsForm.d.ts +4 -2
  217. package/dist/src/components/modals/EditLabelsModal/EditLabelsForm.d.ts.map +1 -1
  218. package/dist/src/components/modals/EditLabelsModal/EditLabelsForm.js +11 -4
  219. package/dist/src/components/modals/EditLabelsModal/EditLabelsForm.js.map +1 -1
  220. package/dist/src/components/modals/massModals/MassDecommissionDeviceModal/MassDecommissionDeviceModal.d.ts +10 -0
  221. package/dist/src/components/modals/massModals/MassDecommissionDeviceModal/MassDecommissionDeviceModal.d.ts.map +1 -0
  222. package/dist/src/components/modals/massModals/MassDecommissionDeviceModal/MassDecommissionDeviceModal.js +67 -0
  223. package/dist/src/components/modals/massModals/MassDecommissionDeviceModal/MassDecommissionDeviceModal.js.map +1 -0
  224. package/dist/src/constants.d.ts +1 -1
  225. package/dist/src/constants.d.ts.map +1 -1
  226. package/dist/src/constants.js +1 -1
  227. package/dist/src/constants.js.map +1 -1
  228. package/dist/src/hooks/useAppContext.d.ts +1 -1
  229. package/dist/src/hooks/useAppContext.d.ts.map +1 -1
  230. package/dist/src/hooks/useFetch.d.ts +1 -1
  231. package/dist/src/hooks/useFetchPeriodically.js +10 -10
  232. package/dist/src/hooks/useFetchPeriodically.js.map +1 -1
  233. package/dist/src/hooks/useTablePagination.d.ts +5 -3
  234. package/dist/src/hooks/useTablePagination.d.ts.map +1 -1
  235. package/dist/src/hooks/useTablePagination.js +9 -5
  236. package/dist/src/hooks/useTablePagination.js.map +1 -1
  237. package/dist/src/hooks/useWebSocket.d.ts +1 -1
  238. package/dist/src/hooks/useWebSocket.js +4 -4
  239. package/dist/src/hooks/useWebSocket.js.map +1 -1
  240. package/dist/src/links.d.ts +1 -0
  241. package/dist/src/links.d.ts.map +1 -1
  242. package/dist/src/links.js +2 -1
  243. package/dist/src/links.js.map +1 -1
  244. package/dist/src/types/rbac.d.ts +3 -1
  245. package/dist/src/types/rbac.d.ts.map +1 -1
  246. package/dist/src/types/rbac.js +2 -0
  247. package/dist/src/types/rbac.js.map +1 -1
  248. package/dist/src/utils/api.d.ts +3 -6
  249. package/dist/src/utils/api.d.ts.map +1 -1
  250. package/dist/src/utils/api.js.map +1 -1
  251. package/dist/src/utils/apiCalls.d.ts +2 -0
  252. package/dist/src/utils/apiCalls.d.ts.map +1 -0
  253. package/dist/src/utils/apiCalls.js +23 -0
  254. package/dist/src/utils/apiCalls.js.map +1 -0
  255. package/dist/src/utils/devices.d.ts +6 -3
  256. package/dist/src/utils/devices.d.ts.map +1 -1
  257. package/dist/src/utils/devices.js +20 -1
  258. package/dist/src/utils/devices.js.map +1 -1
  259. package/dist/src/utils/patch.d.ts +4 -1
  260. package/dist/src/utils/patch.d.ts.map +1 -1
  261. package/dist/src/utils/patch.js +166 -9
  262. package/dist/src/utils/patch.js.map +1 -1
  263. package/dist/src/utils/status/common.js +13 -12
  264. package/dist/src/utils/status/common.js.map +1 -1
  265. package/dist/src/utils/status/devices.d.ts +3 -3
  266. package/dist/src/utils/status/devices.d.ts.map +1 -1
  267. package/dist/src/utils/status/devices.js +40 -5
  268. package/dist/src/utils/status/devices.js.map +1 -1
  269. package/dist/src/utils/status/fleet.d.ts +4 -4
  270. package/dist/src/utils/status/fleet.d.ts.map +1 -1
  271. package/dist/src/utils/status/fleet.js +15 -2
  272. package/dist/src/utils/status/fleet.js.map +1 -1
  273. package/dist/src/utils/tooltip.d.ts +7 -0
  274. package/dist/src/utils/tooltip.d.ts.map +1 -0
  275. package/dist/src/utils/tooltip.js +6 -0
  276. package/dist/src/utils/tooltip.js.map +1 -0
  277. package/package.json +1 -1
  278. package/src/components/DetailsPage/DetailsPageActions.tsx +34 -6
  279. package/src/components/DetailsPage/Tables/ApplicationsTable.tsx +1 -1
  280. package/src/components/Device/DeviceDetails/DeviceApplications.tsx +3 -3
  281. package/src/components/Device/DeviceDetails/DeviceDetailsPage.tsx +53 -34
  282. package/src/components/Device/DeviceDetails/DeviceDetailsTab.tsx +71 -54
  283. package/src/components/Device/DeviceDetails/DeviceDetailsTabContent/StatusContent.tsx +75 -0
  284. package/src/components/Device/DeviceDetails/DeviceDetailsTabContent/SystemResourcesContent.tsx +47 -0
  285. package/src/components/Device/DeviceDetails/TerminalTab.tsx +1 -4
  286. package/src/components/Device/DevicesPage/DecommissionedDeviceTableRow.tsx +89 -0
  287. package/src/components/Device/DevicesPage/DecommissionedDevicesTable.tsx +156 -0
  288. package/src/components/Device/DevicesPage/DeviceNameOnlyToolbarFilter.tsx +30 -0
  289. package/src/components/Device/DevicesPage/DevicesEmptyStates.tsx +46 -0
  290. package/src/components/Device/DevicesPage/DevicesPage.tsx +45 -215
  291. package/src/components/Device/DevicesPage/{DeviceTableRow.tsx → EnrolledDeviceTableRow.tsx} +16 -20
  292. package/src/components/Device/DevicesPage/EnrolledDevicesTable.tsx +208 -0
  293. package/src/components/Device/DevicesPage/useDevices.ts +21 -1
  294. package/src/components/Device/EditDeviceWizard/EditDeviceWizard.tsx +6 -3
  295. package/src/components/Device/EditDeviceWizard/EditDeviceWizardNav.tsx +1 -1
  296. package/src/components/Device/EditDeviceWizard/steps/ApplicationTemplates.tsx +2 -0
  297. package/src/components/Device/EditDeviceWizard/steps/ConfigInlineTemplateForm.tsx +1 -0
  298. package/src/components/Device/EditDeviceWizard/steps/ConfigurationTemplates.tsx +1 -0
  299. package/src/components/Device/EditDeviceWizard/steps/ReviewDeviceStep.tsx +27 -19
  300. package/src/components/Device/EditDeviceWizard/steps/ReviewUpdatePolicy.tsx +55 -0
  301. package/src/components/Device/EditDeviceWizard/steps/SystemdUnitsForm.tsx +9 -7
  302. package/src/components/EnrollmentRequest/EnrollmentRequestDetails/EnrollmentRequestDetails.tsx +10 -36
  303. package/src/components/EnrollmentRequest/EnrollmentRequestList.tsx +2 -2
  304. package/src/components/EnrollmentRequest/EnrollmentRequestTableRow.tsx +2 -2
  305. package/src/components/EnrollmentRequest/useEnrollmentRequests.ts +3 -2
  306. package/src/components/Fleet/CreateFleet/CreateFleetWizard.tsx +46 -5
  307. package/src/components/Fleet/CreateFleet/CreateFleetWizardFooter.tsx +4 -0
  308. package/src/components/Fleet/CreateFleet/fleetSpecUtils.ts +62 -0
  309. package/src/components/Fleet/CreateFleet/steps/ReviewStep.tsx +65 -30
  310. package/src/components/Fleet/CreateFleet/steps/UpdateConfirmChangesModal.tsx +87 -0
  311. package/src/components/Fleet/CreateFleet/steps/UpdatePolicyStep.tsx +155 -0
  312. package/src/components/Fleet/CreateFleet/steps/UpdateStepDisruptionBudget.tsx +87 -0
  313. package/src/components/Fleet/CreateFleet/steps/UpdateStepRolloutPolicy.tsx +190 -0
  314. package/src/components/Fleet/CreateFleet/types.ts +25 -0
  315. package/src/components/Fleet/CreateFleet/utils.ts +20 -1
  316. package/src/components/Fleet/FleetDetails/FleetDetailsContent.tsx +10 -7
  317. package/src/components/Fleet/FleetDetails/{FleetDevices.tsx → FleetDevicesCharts.tsx} +4 -4
  318. package/src/components/Fleet/FleetDetails/FleetDevicesCount.tsx +53 -0
  319. package/src/components/Fleet/FleetResourceSyncs.tsx +2 -2
  320. package/src/components/Fleet/FleetRow.tsx +12 -4
  321. package/src/components/Fleet/FleetsPage.tsx +2 -2
  322. package/src/components/Fleet/useFleets.ts +7 -7
  323. package/src/components/ListPage/ListPage.tsx +12 -4
  324. package/src/components/ListPage/ListPageActions.tsx +50 -16
  325. package/src/components/ListPage/types.ts +8 -8
  326. package/src/components/OverviewPage/Cards/Status/DeviceStatusChart.tsx +0 -1
  327. package/src/components/OverviewPage/OverviewPage.tsx +12 -4
  328. package/src/components/Repository/RepositoryDetails/RepositoryResourceSyncsCard.tsx +1 -1
  329. package/src/components/Repository/useRepositories.ts +2 -2
  330. package/src/components/ResourceSync/RepositoryResourceSyncList.tsx +2 -2
  331. package/src/components/Status/DeviceLifecycleStatus.tsx +33 -0
  332. package/src/components/Status/StatusDisplay.tsx +4 -4
  333. package/src/components/Table/Table.tsx +2 -1
  334. package/src/components/Table/TablePagination.tsx +9 -7
  335. package/src/components/common/EditableLabelControl.tsx +7 -6
  336. package/src/components/common/TechPreviewBadge.tsx +43 -0
  337. package/src/components/form/LabelsField.tsx +4 -1
  338. package/src/components/form/NumberField.tsx +78 -0
  339. package/src/components/form/TextListField.tsx +82 -0
  340. package/src/components/form/validations.ts +103 -10
  341. package/src/components/modals/DecommissionModal/DecommissionModal.tsx +95 -0
  342. package/src/components/modals/EditLabelsModal/EditLabelsForm.tsx +9 -8
  343. package/src/components/modals/massModals/MassDecommissionDeviceModal/MassDecommissionDeviceModal.tsx +130 -0
  344. package/src/constants.ts +1 -1
  345. package/src/hooks/useAppContext.tsx +1 -1
  346. package/src/hooks/useFetchPeriodically.ts +11 -11
  347. package/src/hooks/{useTablePagination.tsx → useTablePagination.ts} +13 -7
  348. package/src/hooks/useWebSocket.ts +4 -4
  349. package/src/links.ts +2 -0
  350. package/src/types/rbac.ts +2 -0
  351. package/src/utils/api.ts +13 -6
  352. package/src/utils/apiCalls.ts +15 -0
  353. package/src/utils/devices.ts +21 -3
  354. package/src/utils/patch.ts +182 -8
  355. package/src/utils/status/common.ts +8 -8
  356. package/src/utils/status/devices.ts +39 -8
  357. package/src/utils/status/fleet.ts +21 -6
  358. package/src/utils/tooltip.ts +2 -0
  359. package/dist/src/components/DetailsPage/Tables/IntegrityDetails.d.ts +0 -8
  360. package/dist/src/components/DetailsPage/Tables/IntegrityDetails.d.ts.map +0 -1
  361. package/dist/src/components/DetailsPage/Tables/IntegrityDetails.js +0 -23
  362. package/dist/src/components/DetailsPage/Tables/IntegrityDetails.js.map +0 -1
  363. package/dist/src/components/Device/DevicesPage/DeviceTableRow.d.ts +0 -16
  364. package/dist/src/components/Device/DevicesPage/DeviceTableRow.d.ts.map +0 -1
  365. package/dist/src/components/Device/DevicesPage/DeviceTableRow.js.map +0 -1
  366. package/dist/src/components/Fleet/FleetDetails/FleetDevices.d.ts +0 -9
  367. package/dist/src/components/Fleet/FleetDetails/FleetDevices.d.ts.map +0 -1
  368. package/dist/src/components/Fleet/FleetDetails/FleetDevices.js.map +0 -1
  369. package/dist/src/components/Fleet/FleetDetails/FleetDevicesLink.d.ts +0 -7
  370. package/dist/src/components/Fleet/FleetDetails/FleetDevicesLink.d.ts.map +0 -1
  371. package/dist/src/components/Fleet/FleetDetails/FleetDevicesLink.js +0 -13
  372. package/dist/src/components/Fleet/FleetDetails/FleetDevicesLink.js.map +0 -1
  373. package/dist/src/components/Status/IntegrityStatus.d.ts +0 -7
  374. package/dist/src/components/Status/IntegrityStatus.d.ts.map +0 -1
  375. package/dist/src/components/Status/IntegrityStatus.js +0 -17
  376. package/dist/src/components/Status/IntegrityStatus.js.map +0 -1
  377. package/dist/src/utils/status/integrity.d.ts +0 -5
  378. package/dist/src/utils/status/integrity.d.ts.map +0 -1
  379. package/dist/src/utils/status/integrity.js +0 -28
  380. package/dist/src/utils/status/integrity.js.map +0 -1
  381. package/src/components/DetailsPage/Tables/IntegrityDetails.tsx +0 -44
  382. package/src/components/Fleet/FleetDetails/FleetDevicesLink.tsx +0 -16
  383. package/src/components/Status/IntegrityStatus.tsx +0 -19
  384. package/src/utils/status/integrity.ts +0 -26
@@ -31,7 +31,7 @@ const LabelsField: React.FC<LabelsFieldProps> = ({
31
31
  const errors = await setLabels(newLabels, true);
32
32
  const hasErrors = Object.keys(errors || {}).length > 0;
33
33
 
34
- onChangeCallback && onChangeCallback(newLabels, hasErrors);
34
+ onChangeCallback?.(newLabels, hasErrors);
35
35
  };
36
36
 
37
37
  const onDelete = async (_ev: React.MouseEvent<Element, MouseEvent>, index: number) => {
@@ -44,6 +44,9 @@ const LabelsField: React.FC<LabelsFieldProps> = ({
44
44
  };
45
45
 
46
46
  const onAdd = async (text: string) => {
47
+ if (!text) {
48
+ return;
49
+ }
47
50
  const split = text.split('=');
48
51
  let newLabel: FlightCtlLabel;
49
52
  if (split.length === 2) {
@@ -0,0 +1,78 @@
1
+ import * as React from 'react';
2
+ import { useField } from 'formik';
3
+ import { FormGroup, NumberInput, NumberInputProps as PFNumberInputProps } from '@patternfly/react-core';
4
+ import ErrorHelperText, { DefaultHelperText } from './FieldHelperText';
5
+
6
+ export interface NumberFieldProps extends Omit<PFNumberInputProps, 'onChange'> {
7
+ name: string;
8
+ isRequired?: boolean;
9
+ helperText?: React.ReactNode;
10
+ }
11
+
12
+ const NumberField = React.forwardRef(
13
+ ({ helperText, min = 0, max, isRequired, ...props }: NumberFieldProps, ref: React.Ref<HTMLInputElement>) => {
14
+ const [field, meta, { setValue, setTouched }] = useField<number | ''>({
15
+ name: props.name,
16
+ });
17
+
18
+ const doChange = (value: number) => {
19
+ let newValue = value < (min || 0) ? min : value;
20
+ newValue = max && newValue > max ? max : newValue;
21
+ if (field.value !== newValue) {
22
+ setValue(newValue);
23
+ }
24
+ };
25
+
26
+ const onPlus: PFNumberInputProps['onPlus'] = () => {
27
+ doChange(field.value ? field.value + 1 : min);
28
+ };
29
+
30
+ const onMinus: PFNumberInputProps['onMinus'] = () => {
31
+ doChange(field.value ? field.value - 1 : min);
32
+ };
33
+
34
+ const handleChange: PFNumberInputProps['onChange'] = (event: React.FormEvent<HTMLInputElement>) => {
35
+ const valStr = (event.target as HTMLInputElement).value;
36
+ // Skip updating the value onBlur. Otherwise, when the field is cleared PF sets a numeric value onBlur.
37
+ if (event.type === 'change') {
38
+ if (!isRequired && valStr === '') {
39
+ setValue('');
40
+ } else {
41
+ const targetValue = valStr as unknown as number;
42
+ doChange(Number.isNaN(targetValue) ? min : Number(targetValue));
43
+ setTouched(true);
44
+ }
45
+ }
46
+ };
47
+
48
+ const fieldId = `numberfield-${props.name}`;
49
+ const hasError = meta.touched && !!meta.error;
50
+
51
+ return (
52
+ <FormGroup id={`form-control__${fieldId}`} fieldId={fieldId}>
53
+ <NumberInput
54
+ className="fc-number-input"
55
+ {...field}
56
+ {...props}
57
+ // Prevent the NumberInput setting the value to 0 when it's not defined
58
+ value={field.value === undefined && !isRequired ? '' : field.value}
59
+ min={min}
60
+ max={max}
61
+ ref={ref}
62
+ inputName={fieldId}
63
+ onMinus={onMinus}
64
+ onChange={handleChange}
65
+ onPlus={onPlus}
66
+ validated={hasError ? 'error' : 'default'}
67
+ />
68
+
69
+ <DefaultHelperText helperText={helperText} />
70
+ <ErrorHelperText meta={meta} />
71
+ </FormGroup>
72
+ );
73
+ },
74
+ );
75
+
76
+ NumberField.displayName = 'NumberField';
77
+
78
+ export default NumberField;
@@ -0,0 +1,82 @@
1
+ import * as React from 'react';
2
+ import { useField } from 'formik';
3
+ import { Label, LabelGroup } from '@patternfly/react-core';
4
+
5
+ import EditableLabelControl from '../common/EditableLabelControl';
6
+ import ErrorHelperText, { DefaultHelperText } from './FieldHelperText';
7
+
8
+ type TextListFieldProps = {
9
+ name: string;
10
+ isLoading?: boolean;
11
+ addButtonText?: string;
12
+ helperText?: React.ReactNode;
13
+ onChangeCallback?: (newList: string[], hasErrors: boolean) => void;
14
+ canEdit?: boolean;
15
+ };
16
+
17
+ const maxWidth = '16ch';
18
+
19
+ const TextListField = ({ name, onChangeCallback, addButtonText, helperText }: TextListFieldProps) => {
20
+ const [{ value: valueList }, meta, { setValue: setValueList, setTouched }] = useField<string[]>(name);
21
+ const updateValueList = async (newValueList: string[]) => {
22
+ const errors = await setValueList(newValueList, true);
23
+ const hasErrors = Object.keys(errors || {}).length > 0;
24
+
25
+ setTouched(true);
26
+ onChangeCallback?.(newValueList, hasErrors);
27
+ };
28
+
29
+ const onDelete = async (_ev: React.MouseEvent<Element, MouseEvent>, index: number) => {
30
+ const newValueList = [...valueList];
31
+ newValueList.splice(index, 1);
32
+ await updateValueList(newValueList);
33
+ };
34
+
35
+ const onAdd = async (text: string) => {
36
+ if (text) {
37
+ await updateValueList([...valueList, text]);
38
+ } else {
39
+ setTouched(true);
40
+ }
41
+ };
42
+
43
+ const onEdit = async (index: number, newValue: string) => {
44
+ const newLabels = [...valueList];
45
+ newLabels.splice(index, 1, newValue);
46
+
47
+ await updateValueList(newLabels);
48
+ };
49
+
50
+ return (
51
+ <>
52
+ <LabelGroup
53
+ numLabels={5}
54
+ isEditable
55
+ addLabelControl={
56
+ <EditableLabelControl defaultLabel="" addButtonText={addButtonText} onAddLabel={onAdd} isEditable />
57
+ }
58
+ >
59
+ {valueList.map((text, index) => {
60
+ return (
61
+ <Label
62
+ key={`${text}_${index}`}
63
+ textMaxWidth={maxWidth}
64
+ onClose={(e) => onDelete(e, index)}
65
+ onEditCancel={(_, prevText) => onEdit(index, prevText)}
66
+ onEditComplete={(_, newText) => onEdit(index, newText)}
67
+ /* Add a basic tooltip as the PF tooltip doesn't work for editable labels */
68
+ title={text}
69
+ isEditable
70
+ >
71
+ {text}
72
+ </Label>
73
+ );
74
+ })}
75
+ </LabelGroup>
76
+ <DefaultHelperText helperText={helperText} />
77
+ <ErrorHelperText meta={meta} />
78
+ </>
79
+ );
80
+ };
81
+
82
+ export default TextListField;
@@ -17,8 +17,7 @@ import {
17
17
  import { labelToString } from '../../utils/labels';
18
18
  import { ApplicationFormSpec } from '../Device/EditDeviceWizard/types';
19
19
  import { SystemdUnitFormValue } from '../Device/SystemdUnitsModal/TrackSystemdUnitsForm';
20
-
21
- type UnvalidatedLabel = Partial<FlightCtlLabel>;
20
+ import { BatchForm, BatchLimitType, DisruptionBudgetForm, RolloutPolicyForm } from '../Fleet/CreateFleet/types';
22
21
 
23
22
  const SYSTEMD_PATTERNS_REGEXP = /^[a-z][a-z0-9-_.]*$/;
24
23
  const SYSTEMD_UNITS_MAX_PATTERNS = 256;
@@ -40,6 +39,8 @@ const BASIC_FLEET_OS_IMAGE_REGEXP = /^[a-zA-Z0-9.\-\/:@_+{}\s]*$/;
40
39
  const absolutePathRegex = /^\/.*$/;
41
40
  export const MAX_TARGET_REVISION_LENGTH = 244;
42
41
 
42
+ const isInteger = (val: number | undefined) => val === undefined || Number.isInteger(val);
43
+
43
44
  export const getLabelValueValidations = (t: TFunction) => [
44
45
  { key: 'labelValueStartAndEnd', message: t('Starts and ends with a letter or a number.') },
45
46
  {
@@ -92,12 +93,12 @@ export const getKubernetesDnsSubdomainErrors = (value: string) => {
92
93
  return errorKeys;
93
94
  };
94
95
 
95
- export const hasUniqueLabelKeys = (labels: UnvalidatedLabel[]) => {
96
+ export const hasUniqueLabelKeys = (labels: FlightCtlLabel[]) => {
96
97
  const uniqueKeys = new Set(labels.map((label) => label.key));
97
98
  return uniqueKeys.size === labels.length;
98
99
  };
99
100
 
100
- export const getInvalidKubernetesLabels = (labels: UnvalidatedLabel[]) => {
101
+ export const getInvalidKubernetesLabels = (labels: FlightCtlLabel[]) => {
101
102
  return labels.filter((unvalidatedLabel) => {
102
103
  const key = unvalidatedLabel.key || '';
103
104
  const value = unvalidatedLabel.value || '';
@@ -201,14 +202,13 @@ export const validOsImage = (t: TFunction, { isFleet }: { isFleet: boolean }) =>
201
202
  export const validLabelsSchema = (t: TFunction) =>
202
203
  Yup.array()
203
204
  .of(
204
- Yup.object<UnvalidatedLabel>().shape({
205
- // We'll define the mandatory key restriction for all labels, not individually
206
- key: Yup.string(),
205
+ Yup.object<FlightCtlLabel>().shape({
206
+ key: Yup.string().required(),
207
207
  value: Yup.string(),
208
208
  }),
209
209
  )
210
210
  .required()
211
- .test('missing keys', (labels: UnvalidatedLabel[], testContext) => {
211
+ .test('missing keys', (labels: FlightCtlLabel[], testContext) => {
212
212
  const missingKeyLabels = labels.filter((label) => !label.key).map((label) => label.value);
213
213
  return missingKeyLabels.length > 0
214
214
  ? testContext.createError({
@@ -219,18 +219,32 @@ export const validLabelsSchema = (t: TFunction) =>
219
219
  : true;
220
220
  })
221
221
  .test('unique keys', t('Label keys must be unique'), hasUniqueLabelKeys)
222
- .test('invalid-labels', (labels: UnvalidatedLabel[], testContext) => {
222
+ .test('invalid-labels', (labels: FlightCtlLabel[], testContext) => {
223
223
  const invalidLabels = getInvalidKubernetesLabels(labels);
224
224
 
225
225
  return invalidLabels.length > 0
226
226
  ? testContext.createError({
227
227
  message: t('The following labels are not valid Kubernetes labels: {{invalidLabels}}', {
228
- invalidLabels: `${invalidLabels.map((label) => labelToString(label as FlightCtlLabel)).join(', ')}`,
228
+ invalidLabels: `${invalidLabels.map(labelToString).join(', ')}`,
229
229
  }),
230
230
  })
231
231
  : true;
232
232
  });
233
233
 
234
+ export const validGroupLabelKeysSchema = (t: TFunction) =>
235
+ Yup.array()
236
+ .of(
237
+ Yup.string()
238
+ .required()
239
+ .test('only-label-keys', t("Full labels are not allowed, use only the 'key' part."), (value?: string) => {
240
+ return !value?.includes('=');
241
+ }),
242
+ )
243
+ .test('unique keys', t('Label keys must be unique'), (labelKeys) => {
244
+ const uniqueKeys = new Set(labelKeys);
245
+ return uniqueKeys.size === labelKeys?.length;
246
+ });
247
+
234
248
  export const validApplicationsSchema = (t: TFunction) => {
235
249
  return Yup.array()
236
250
  .of(
@@ -287,6 +301,85 @@ export const validApplicationsSchema = (t: TFunction) => {
287
301
  });
288
302
  };
289
303
 
304
+ export const validFleetRolloutPolicySchema = (t: TFunction) => {
305
+ return Yup.object()
306
+ .shape({
307
+ isAdvanced: Yup.boolean().required(),
308
+ updateTimeout: Yup.number()
309
+ .required('Update timeout is required')
310
+ .test('not-decimal', t('Cannot be decimal'), isInteger),
311
+ batches: Yup.array()
312
+ .of(
313
+ Yup.lazy((values: BatchForm) =>
314
+ Yup.object<BatchForm>().shape({
315
+ selector: validLabelsSchema(t),
316
+ limitType: Yup.string()
317
+ .oneOf([BatchLimitType.BatchLimitAbsoluteNumber, BatchLimitType.BatchLimitPercent])
318
+ .required(),
319
+ limit: Yup.number()
320
+ .test('correct-percentage', t('Percentage must be between 1 and 100.'), (num) => {
321
+ if (num === undefined) {
322
+ return true;
323
+ }
324
+ if (values.limitType === BatchLimitType.BatchLimitPercent && num > 100) {
325
+ return false;
326
+ }
327
+ return true;
328
+ })
329
+ .test('not-decimal', t('Cannot be decimal'), isInteger)
330
+ // When an absolute number, we can only restrict the minimum value
331
+ .min(1, t('Value must be greater or equal than 1')),
332
+ successThreshold: Yup.number()
333
+ .required('Success threshold is required')
334
+ .min(1, t('Success threshold must be between 1 and 100'))
335
+ .max(100, t('Success threshold must be between 1 and 100'))
336
+ .test('not-decimal', t('Cannot be decimal'), isInteger),
337
+ }),
338
+ ),
339
+ )
340
+ .required(),
341
+ })
342
+ .test('valid-rollout', (rolloutPolicy: RolloutPolicyForm | undefined, testContext) => {
343
+ if (!rolloutPolicy || rolloutPolicy.batches.length === 0) {
344
+ return true;
345
+ }
346
+
347
+ const errors = rolloutPolicy.batches.reduce((errors, batch, batchIndex) => {
348
+ const hasError = batch.limit === undefined && Object.keys(batch.selector || {}).length === 0;
349
+ if (hasError) {
350
+ errors.push(
351
+ new Yup.ValidationError(
352
+ t('At least one of the label selector or numeric selector must be specified.'),
353
+ '',
354
+ `rolloutPolicy.batches[${batchIndex}]`,
355
+ ),
356
+ );
357
+ }
358
+ return errors;
359
+ }, [] as Yup.ValidationError[]);
360
+
361
+ return testContext.createError({
362
+ message: () => errors,
363
+ });
364
+ });
365
+ };
366
+
367
+ export const validFleetDisruptionBudgetSchema = (t: TFunction) => {
368
+ return Yup.object()
369
+ .shape({
370
+ isAdvanced: Yup.boolean().required(),
371
+ minAvailable: Yup.number().test('not-decimal', t('Number of devices cannot be decimal'), isInteger),
372
+ maxUnavailable: Yup.number().test('not-decimal', t('Number of devices cannot be decimal'), isInteger),
373
+ groupBy: validGroupLabelKeysSchema(t),
374
+ })
375
+ .test(
376
+ 'has-min-or-max',
377
+ t('At least one of minimum available or maximum unavailable devices is required.'),
378
+ (value: DisruptionBudgetForm) =>
379
+ !(value.isAdvanced && value.minAvailable === undefined && value.maxUnavailable === undefined),
380
+ );
381
+ };
382
+
290
383
  export const validConfigTemplatesSchema = (t: TFunction) =>
291
384
  Yup.array()
292
385
  .test('unique-names', t('Source names must be unique'), (templates: SpecConfigTemplate[] | undefined) => {
@@ -0,0 +1,95 @@
1
+ import * as React from 'react';
2
+ import { Formik } from 'formik';
3
+ import { Alert, Button, Modal, Stack, StackItem } from '@patternfly/react-core';
4
+
5
+ import { DeviceDecommissionTargetType } from '@flightctl/types';
6
+
7
+ import { useTranslation } from '../../../hooks/useTranslation';
8
+ import { getErrorMessage } from '../../../utils/error';
9
+
10
+ type DecommissionModalProps = {
11
+ onDecommission: (target: DeviceDecommissionTargetType) => Promise<unknown>;
12
+ onClose: VoidFunction;
13
+ };
14
+
15
+ type DecommissionFormValues = {
16
+ // Currently not implemented - no checkbox to select this option is visible in the UI
17
+ doFactoryReset: boolean;
18
+ };
19
+
20
+ const DecommissionModal = ({ onDecommission, onClose }: DecommissionModalProps) => {
21
+ const { t } = useTranslation();
22
+ const [isDecommissioning, setIsDecommissioning] = React.useState(false);
23
+ const [error, setError] = React.useState<string>();
24
+
25
+ React.useEffect(() => {
26
+ // Clean-up after the modal closes for any reason
27
+ return () => {
28
+ setIsDecommissioning(false);
29
+ };
30
+ }, []);
31
+
32
+ return (
33
+ <Modal title={t('Decommission device?')} isOpen onClose={onClose} variant="small" titleIconVariant="warning">
34
+ <Formik<DecommissionFormValues>
35
+ initialValues={{
36
+ doFactoryReset: false,
37
+ }}
38
+ onSubmit={({ doFactoryReset }) => {
39
+ const doSubmit = async () => {
40
+ setError(undefined);
41
+ try {
42
+ setIsDecommissioning(true);
43
+ await onDecommission(
44
+ doFactoryReset
45
+ ? DeviceDecommissionTargetType.DeviceDecommissionTargetTypeFactoryReset
46
+ : DeviceDecommissionTargetType.DeviceDecommissionTargetTypeUnenroll,
47
+ );
48
+ onClose();
49
+ } catch (err) {
50
+ setError(getErrorMessage(err));
51
+ setIsDecommissioning(false);
52
+ }
53
+ };
54
+ void doSubmit();
55
+ }}
56
+ >
57
+ {({ submitForm }) => {
58
+ return (
59
+ <Stack hasGutter>
60
+ <StackItem>{t('Are you sure you want to proceed with decommissioning this device?')}</StackItem>
61
+ <StackItem>
62
+ {t(
63
+ 'Decommissioned devices will not be able to communicate with the edge management system anymore, and they will be removed from any fleet they were associated to. Once decommissioned, the device cannot be managed further.',
64
+ )}
65
+ </StackItem>
66
+ {error && (
67
+ <StackItem>
68
+ <Alert isInline variant="danger" title={t('An error occurred')}>
69
+ {error}
70
+ </Alert>
71
+ </StackItem>
72
+ )}
73
+ <StackItem>
74
+ <Button
75
+ key="confirm"
76
+ variant="danger"
77
+ isDisabled={isDecommissioning}
78
+ isLoading={isDecommissioning}
79
+ onClick={submitForm}
80
+ >
81
+ {t('Decommission device')}
82
+ </Button>
83
+ <Button key="cancel" variant="link" onClick={onClose} isDisabled={isDecommissioning}>
84
+ {t('Cancel')}
85
+ </Button>
86
+ </StackItem>
87
+ </Stack>
88
+ );
89
+ }}
90
+ </Formik>
91
+ </Modal>
92
+ );
93
+ };
94
+
95
+ export default DecommissionModal;
@@ -15,6 +15,7 @@ import { fromAPILabel } from '../../../utils/labels';
15
15
  import { validLabelsSchema } from '../../form/validations';
16
16
  import { getErrorMessage } from '../../../utils/error';
17
17
  import { getLabelPatches } from '../../../utils/patch';
18
+ import LabelsView from '../../common/LabelsView';
18
19
 
19
20
  type EditLabelsFormValues = {
20
21
  labels: FlightCtlLabel[];
@@ -23,7 +24,6 @@ type EditLabelsFormValues = {
23
24
  type EditLabelsFormContentProps = {
24
25
  isSubmitting: FormikProps<EditLabelsFormValues>['isSubmitting'];
25
26
  submitForm: (values: EditLabelsFormValues) => Promise<string>;
26
- canEdit: boolean;
27
27
  };
28
28
 
29
29
  const getValidationSchema = (t: TFunction) => {
@@ -34,7 +34,7 @@ const getValidationSchema = (t: TFunction) => {
34
34
 
35
35
  const delayResponse = (ms: number) => new Promise((resolve) => setTimeout(resolve, ms));
36
36
 
37
- const EditLabelsFormContent = ({ isSubmitting, submitForm, canEdit }: EditLabelsFormContentProps) => {
37
+ const EditLabelsFormContent = ({ isSubmitting, submitForm }: EditLabelsFormContentProps) => {
38
38
  const { t } = useTranslation();
39
39
  const [submitError, setSubmitError] = React.useState<string>();
40
40
 
@@ -56,7 +56,6 @@ const EditLabelsFormContent = ({ isSubmitting, submitForm, canEdit }: EditLabels
56
56
  addButtonText={isSubmitting ? t('Saving...') : undefined}
57
57
  isLoading={isSubmitting}
58
58
  onChangeCallback={debouncedSubmit}
59
- canEdit={canEdit}
60
59
  />
61
60
  {submitError && <Alert isInline title={submitError} variant="danger" />}
62
61
  </FlightCtlForm>
@@ -66,10 +65,14 @@ const EditLabelsFormContent = ({ isSubmitting, submitForm, canEdit }: EditLabels
66
65
  type EditLabelsFormProps = {
67
66
  device: Device;
68
67
  onDeviceUpdate: () => void;
69
- canEdit: boolean;
70
68
  };
71
69
 
72
- const EditLabelsForm = ({ device, onDeviceUpdate, canEdit }: EditLabelsFormProps) => {
70
+ export const ViewLabels = ({ device }: { device: Device }) => {
71
+ const currentLabels = device.metadata.labels || {};
72
+ return <LabelsView prefix="read-only-labels" labels={currentLabels} />;
73
+ };
74
+
75
+ const EditLabelsForm = ({ device, onDeviceUpdate }: EditLabelsFormProps) => {
73
76
  const { t } = useTranslation();
74
77
  const { patch } = useFetch();
75
78
 
@@ -96,9 +99,7 @@ const EditLabelsForm = ({ device, onDeviceUpdate, canEdit }: EditLabelsFormProps
96
99
  }}
97
100
  validationSchema={getValidationSchema(t)}
98
101
  >
99
- {({ isSubmitting, submitForm }) => (
100
- <EditLabelsFormContent canEdit={canEdit} isSubmitting={isSubmitting} submitForm={submitForm} />
101
- )}
102
+ {({ isSubmitting, submitForm }) => <EditLabelsFormContent isSubmitting={isSubmitting} submitForm={submitForm} />}
102
103
  </Formik>
103
104
  );
104
105
  };
@@ -0,0 +1,130 @@
1
+ import * as React from 'react';
2
+ import { Alert, Button, Modal, Progress, ProgressMeasureLocation, Stack, StackItem } from '@patternfly/react-core';
3
+ import { Table, Tbody, Td, Th, Thead, Tr } from '@patternfly/react-table';
4
+
5
+ import { Device, DeviceDecommission, DeviceDecommissionTargetType } from '@flightctl/types';
6
+
7
+ import { getErrorMessage } from '../../../../utils/error';
8
+ import { useFetch } from '../../../../hooks/useFetch';
9
+ import { useTranslation } from '../../../../hooks/useTranslation';
10
+ import { isPromiseRejected } from '../../../../types/typeUtils';
11
+ import ResourceLink from '../../../common/ResourceLink';
12
+
13
+ type MassDecommissionDeviceModalProps = {
14
+ devices: Array<Device>;
15
+ onClose: VoidFunction;
16
+ onSuccess: VoidFunction;
17
+ };
18
+
19
+ const MassDecommissionDeviceModal = ({ onClose, devices, onSuccess }: MassDecommissionDeviceModalProps) => {
20
+ const { t } = useTranslation();
21
+ const [progress, setProgress] = React.useState(0);
22
+ const [totalProgress, setTotalProgress] = React.useState(0);
23
+ const [isSubmitting, setIsSubmitting] = React.useState(false);
24
+ const [errors, setErrors] = React.useState<string[]>();
25
+ const { put } = useFetch();
26
+
27
+ const decommissionDevices = async () => {
28
+ setProgress(0);
29
+ setIsSubmitting(true);
30
+ const promises = devices.map(async (dev) => {
31
+ await put<DeviceDecommission>(`devices/${dev.metadata.name}/decommission`, {
32
+ target: DeviceDecommissionTargetType.DeviceDecommissionTargetTypeUnenroll,
33
+ });
34
+ setProgress((p) => p + 1);
35
+ });
36
+ setTotalProgress(promises.length);
37
+ const results = await Promise.allSettled(promises);
38
+ setIsSubmitting(false);
39
+
40
+ const rejectedResults = results.filter(isPromiseRejected);
41
+
42
+ if (rejectedResults.length) {
43
+ setErrors(rejectedResults.map((r) => getErrorMessage(r.reason)));
44
+ } else {
45
+ onSuccess();
46
+ }
47
+ };
48
+
49
+ return (
50
+ <Modal
51
+ title={t('Decommission devices ?')}
52
+ isOpen
53
+ onClose={onClose}
54
+ showClose={!isSubmitting}
55
+ titleIconVariant="warning"
56
+ variant="medium"
57
+ actions={[
58
+ <Button
59
+ key="decommission"
60
+ variant="danger"
61
+ onClick={decommissionDevices}
62
+ isLoading={isSubmitting}
63
+ isDisabled={isSubmitting}
64
+ >
65
+ {t('Decommission')}
66
+ </Button>,
67
+ <Button key="cancel" variant="link" onClick={onClose} isDisabled={isSubmitting}>
68
+ {t('Cancel')}
69
+ </Button>,
70
+ ]}
71
+ >
72
+ <Stack hasGutter>
73
+ <StackItem>{t('Are you sure you want to proceed with decommissioning these devices ?')}</StackItem>
74
+ <StackItem>
75
+ {t(
76
+ 'Decommissioned devices will not be able to communicate with the edge management system anymore, and they will be removed from any fleet they were associated to. Once decommissioned, the devices cannot be managed further.',
77
+ )}
78
+ </StackItem>
79
+ <StackItem>
80
+ <Table>
81
+ <Thead>
82
+ <Tr>
83
+ <Th>{t('Name')}</Th>
84
+ <Th>{t('Alias')}</Th>
85
+ </Tr>
86
+ </Thead>
87
+ <Tbody>
88
+ {devices.map((device) => {
89
+ return (
90
+ <Tr key={device.metadata.name}>
91
+ <Td dataLabel={t('Name')}>
92
+ <ResourceLink id={device.metadata.name as string} />
93
+ </Td>
94
+ <Td dataLabel={t('Alias')}>{device.metadata.labels?.alias || '-'}</Td>
95
+ </Tr>
96
+ );
97
+ })}
98
+ </Tbody>
99
+ </Table>
100
+ </StackItem>
101
+ {isSubmitting && (
102
+ <StackItem>
103
+ <Progress
104
+ value={progress}
105
+ min={0}
106
+ max={totalProgress}
107
+ title={t('Decommissioning...')}
108
+ measureLocation={ProgressMeasureLocation.top}
109
+ label={t('{{progress}} of {{totalProgress}}', { progress, totalProgress })}
110
+ valueText={t('{{progress}} of {{totalProgress}}', { progress, totalProgress })}
111
+ />
112
+ </StackItem>
113
+ )}
114
+ {errors?.length && (
115
+ <StackItem>
116
+ <Alert isInline variant="danger" title={t('An error occurred')}>
117
+ <Stack hasGutter>
118
+ {errors.map((e, index) => (
119
+ <StackItem key={index}>{e}</StackItem>
120
+ ))}
121
+ </Stack>
122
+ </Alert>
123
+ </StackItem>
124
+ )}
125
+ </Stack>
126
+ </Modal>
127
+ );
128
+ };
129
+
130
+ export default MassDecommissionDeviceModal;
package/src/constants.ts CHANGED
@@ -1,4 +1,4 @@
1
- const APP_TITLE = 'Device management service';
1
+ const APP_TITLE = 'Edge Manager';
2
2
  const API_VERSION = 'v1alpha1';
3
3
  const PAGE_SIZE = 15;
4
4
 
@@ -59,7 +59,7 @@ export type AppContextProps = {
59
59
  Prompt?: PromptFC;
60
60
  };
61
61
  fetch: {
62
- getWsEndpoint: () => { wsEndpoint: string; protocols: string[] };
62
+ getWsEndpoint: (deviceId: string) => { wsEndpoint: string; protocols: string[] };
63
63
  get: <R>(kind: string, abortSignal?: AbortSignal) => Promise<R>;
64
64
  post: <R>(kind: string, data: R, abortSignal?: AbortSignal) => Promise<R>;
65
65
  put: <R>(kind: string, data: R, abortSignal?: AbortSignal) => Promise<R>;