@flightctl/ui-components 1.1.0-rc1 → 1.1.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 (180) hide show
  1. package/dist/src/components/Repository/CreateRepository/CreateRepositoryForm.css +5 -1
  2. package/dist/types/imagebuilder/index.d.ts +1 -0
  3. package/dist/types/imagebuilder/index.d.ts.map +1 -1
  4. package/dist/types/imagebuilder/models/Status.d.ts +30 -0
  5. package/dist/types/imagebuilder/models/Status.d.ts.map +1 -0
  6. package/dist/types/imagebuilder/models/Status.js +3 -0
  7. package/dist/types/imagebuilder/models/Status.js.map +1 -0
  8. package/dist/types/index.d.ts +7 -0
  9. package/dist/types/index.d.ts.map +1 -1
  10. package/dist/types/index.js.map +1 -1
  11. package/dist/types/models/ApplicationProviderBase.d.ts +12 -0
  12. package/dist/types/models/ApplicationProviderBase.d.ts.map +1 -0
  13. package/dist/types/models/ApplicationProviderBase.js +3 -0
  14. package/dist/types/models/ApplicationProviderBase.js.map +1 -0
  15. package/dist/types/models/ApplicationProviderSpec.d.ts +5 -15
  16. package/dist/types/models/ApplicationProviderSpec.d.ts.map +1 -1
  17. package/dist/types/models/ApplicationUser.d.ts +7 -0
  18. package/dist/types/models/ApplicationUser.d.ts.map +1 -0
  19. package/dist/types/models/ApplicationUser.js +3 -0
  20. package/dist/types/models/ApplicationUser.js.map +1 -0
  21. package/dist/types/models/ComposeApplication.d.ts +7 -0
  22. package/dist/types/models/ComposeApplication.d.ts.map +1 -0
  23. package/dist/types/models/ComposeApplication.js +3 -0
  24. package/dist/types/models/ComposeApplication.js.map +1 -0
  25. package/dist/types/models/ContainerApplication.d.ts +18 -0
  26. package/dist/types/models/ContainerApplication.d.ts.map +1 -0
  27. package/dist/types/models/ContainerApplication.js +3 -0
  28. package/dist/types/models/ContainerApplication.js.map +1 -0
  29. package/dist/types/models/ContainerApplicationProperties.d.ts +13 -0
  30. package/dist/types/models/ContainerApplicationProperties.d.ts.map +1 -0
  31. package/dist/types/models/ContainerApplicationProperties.js +3 -0
  32. package/dist/types/models/ContainerApplicationProperties.js.map +1 -0
  33. package/dist/types/models/HelmApplication.d.ts +20 -0
  34. package/dist/types/models/HelmApplication.d.ts.map +1 -0
  35. package/dist/types/models/HelmApplication.js +3 -0
  36. package/dist/types/models/HelmApplication.js.map +1 -0
  37. package/dist/types/models/ImageApplicationProviderSpec.d.ts +2 -22
  38. package/dist/types/models/ImageApplicationProviderSpec.d.ts.map +1 -1
  39. package/dist/types/models/InlineApplicationProviderSpec.d.ts +2 -3
  40. package/dist/types/models/InlineApplicationProviderSpec.d.ts.map +1 -1
  41. package/dist/types/models/QuadletApplication.d.ts +8 -0
  42. package/dist/types/models/QuadletApplication.d.ts.map +1 -0
  43. package/dist/types/models/QuadletApplication.js +3 -0
  44. package/dist/types/models/QuadletApplication.js.map +1 -0
  45. package/dist/ui-components/src/components/AuthProvider/CreateAuthProvider/utils.js +1 -1
  46. package/dist/ui-components/src/components/AuthProvider/CreateAuthProvider/utils.js.map +1 -1
  47. package/dist/ui-components/src/components/DetailsPage/Tables/ApplicationsTable.js +1 -1
  48. package/dist/ui-components/src/components/DetailsPage/Tables/ApplicationsTable.js.map +1 -1
  49. package/dist/ui-components/src/components/Device/DeviceDetails/DeviceDetailsPage.d.ts.map +1 -1
  50. package/dist/ui-components/src/components/Device/DeviceDetails/DeviceDetailsPage.js +5 -4
  51. package/dist/ui-components/src/components/Device/DeviceDetails/DeviceDetailsPage.js.map +1 -1
  52. package/dist/ui-components/src/components/Device/EditDeviceWizard/deviceSpecUtils.d.ts +3 -3
  53. package/dist/ui-components/src/components/Device/EditDeviceWizard/deviceSpecUtils.d.ts.map +1 -1
  54. package/dist/ui-components/src/components/Device/EditDeviceWizard/deviceSpecUtils.js +308 -363
  55. package/dist/ui-components/src/components/Device/EditDeviceWizard/deviceSpecUtils.js.map +1 -1
  56. package/dist/ui-components/src/components/Device/EditDeviceWizard/steps/ApplicationContainerForm.d.ts +1 -3
  57. package/dist/ui-components/src/components/Device/EditDeviceWizard/steps/ApplicationContainerForm.d.ts.map +1 -1
  58. package/dist/ui-components/src/components/Device/EditDeviceWizard/steps/ApplicationContainerForm.js +18 -19
  59. package/dist/ui-components/src/components/Device/EditDeviceWizard/steps/ApplicationContainerForm.js.map +1 -1
  60. package/dist/ui-components/src/components/Device/EditDeviceWizard/steps/ApplicationHelmForm.d.ts +1 -3
  61. package/dist/ui-components/src/components/Device/EditDeviceWizard/steps/ApplicationHelmForm.d.ts.map +1 -1
  62. package/dist/ui-components/src/components/Device/EditDeviceWizard/steps/ApplicationHelmForm.js +4 -3
  63. package/dist/ui-components/src/components/Device/EditDeviceWizard/steps/ApplicationHelmForm.js.map +1 -1
  64. package/dist/ui-components/src/components/Device/EditDeviceWizard/steps/ApplicationImageForm.d.ts +1 -3
  65. package/dist/ui-components/src/components/Device/EditDeviceWizard/steps/ApplicationImageForm.d.ts.map +1 -1
  66. package/dist/ui-components/src/components/Device/EditDeviceWizard/steps/ApplicationImageForm.js +2 -2
  67. package/dist/ui-components/src/components/Device/EditDeviceWizard/steps/ApplicationImageForm.js.map +1 -1
  68. package/dist/ui-components/src/components/Device/EditDeviceWizard/steps/ApplicationInlineForm.d.ts +3 -3
  69. package/dist/ui-components/src/components/Device/EditDeviceWizard/steps/ApplicationInlineForm.d.ts.map +1 -1
  70. package/dist/ui-components/src/components/Device/EditDeviceWizard/steps/ApplicationInlineForm.js +20 -23
  71. package/dist/ui-components/src/components/Device/EditDeviceWizard/steps/ApplicationInlineForm.js.map +1 -1
  72. package/dist/ui-components/src/components/Device/EditDeviceWizard/steps/ApplicationIntegritySettings.js +3 -3
  73. package/dist/ui-components/src/components/Device/EditDeviceWizard/steps/ApplicationIntegritySettings.js.map +1 -1
  74. package/dist/ui-components/src/components/Device/EditDeviceWizard/steps/ApplicationTemplates.d.ts.map +1 -1
  75. package/dist/ui-components/src/components/Device/EditDeviceWizard/steps/ApplicationTemplates.js +25 -45
  76. package/dist/ui-components/src/components/Device/EditDeviceWizard/steps/ApplicationTemplates.js.map +1 -1
  77. package/dist/ui-components/src/components/Device/EditDeviceWizard/steps/ApplicationVariablesForm.d.ts +8 -0
  78. package/dist/ui-components/src/components/Device/EditDeviceWizard/steps/ApplicationVariablesForm.d.ts.map +1 -0
  79. package/dist/ui-components/src/components/Device/EditDeviceWizard/steps/ApplicationVariablesForm.js +37 -0
  80. package/dist/ui-components/src/components/Device/EditDeviceWizard/steps/ApplicationVariablesForm.js.map +1 -0
  81. package/dist/ui-components/src/components/Device/EditDeviceWizard/steps/ApplicationVolumeForm.d.ts +1 -3
  82. package/dist/ui-components/src/components/Device/EditDeviceWizard/steps/ApplicationVolumeForm.d.ts.map +1 -1
  83. package/dist/ui-components/src/components/Device/EditDeviceWizard/steps/ApplicationVolumeForm.js +5 -8
  84. package/dist/ui-components/src/components/Device/EditDeviceWizard/steps/ApplicationVolumeForm.js.map +1 -1
  85. package/dist/ui-components/src/components/Device/EditDeviceWizard/utils.d.ts +18 -18
  86. package/dist/ui-components/src/components/Fleet/CreateFleet/utils.js +2 -2
  87. package/dist/ui-components/src/components/Fleet/CreateFleet/utils.js.map +1 -1
  88. package/dist/ui-components/src/components/Fleet/ImportFleetWizard/steps/RepositoryStep.d.ts.map +1 -1
  89. package/dist/ui-components/src/components/Fleet/ImportFleetWizard/steps/RepositoryStep.js +3 -1
  90. package/dist/ui-components/src/components/Fleet/ImportFleetWizard/steps/RepositoryStep.js.map +1 -1
  91. package/dist/ui-components/src/components/ImageBuilds/CancelImageBuildModal/CancelImageBuildModal.d.ts +7 -0
  92. package/dist/ui-components/src/components/ImageBuilds/CancelImageBuildModal/CancelImageBuildModal.d.ts.map +1 -0
  93. package/dist/ui-components/src/components/ImageBuilds/CancelImageBuildModal/CancelImageBuildModal.js +40 -0
  94. package/dist/ui-components/src/components/ImageBuilds/CancelImageBuildModal/CancelImageBuildModal.js.map +1 -0
  95. package/dist/ui-components/src/components/ImageBuilds/ConfirmImageExportModal/ConfirmImageExportModal.d.ts +8 -0
  96. package/dist/ui-components/src/components/ImageBuilds/ConfirmImageExportModal/ConfirmImageExportModal.d.ts.map +1 -0
  97. package/dist/ui-components/src/components/ImageBuilds/ConfirmImageExportModal/ConfirmImageExportModal.js +30 -0
  98. package/dist/ui-components/src/components/ImageBuilds/ConfirmImageExportModal/ConfirmImageExportModal.js.map +1 -0
  99. package/dist/ui-components/src/components/ImageBuilds/CreateImageBuildWizard/utils.js +2 -2
  100. package/dist/ui-components/src/components/ImageBuilds/CreateImageBuildWizard/utils.js.map +1 -1
  101. package/dist/ui-components/src/components/ImageBuilds/ImageBuildDetails/ImageBuildDetailsPage.d.ts.map +1 -1
  102. package/dist/ui-components/src/components/ImageBuilds/ImageBuildDetails/ImageBuildDetailsPage.js +22 -11
  103. package/dist/ui-components/src/components/ImageBuilds/ImageBuildDetails/ImageBuildDetailsPage.js.map +1 -1
  104. package/dist/ui-components/src/components/ImageBuilds/ImageBuildDetails/ImageBuildExportsGallery.d.ts.map +1 -1
  105. package/dist/ui-components/src/components/ImageBuilds/ImageBuildDetails/ImageBuildExportsGallery.js +103 -36
  106. package/dist/ui-components/src/components/ImageBuilds/ImageBuildDetails/ImageBuildExportsGallery.js.map +1 -1
  107. package/dist/ui-components/src/components/ImageBuilds/ImageBuildRow.d.ts +5 -2
  108. package/dist/ui-components/src/components/ImageBuilds/ImageBuildRow.d.ts.map +1 -1
  109. package/dist/ui-components/src/components/ImageBuilds/ImageBuildRow.js +22 -12
  110. package/dist/ui-components/src/components/ImageBuilds/ImageBuildRow.js.map +1 -1
  111. package/dist/ui-components/src/components/ImageBuilds/ImageBuildsPage.d.ts.map +1 -1
  112. package/dist/ui-components/src/components/ImageBuilds/ImageBuildsPage.js +17 -8
  113. package/dist/ui-components/src/components/ImageBuilds/ImageBuildsPage.js.map +1 -1
  114. package/dist/ui-components/src/components/ImageBuilds/ImageExportCards.d.ts +10 -9
  115. package/dist/ui-components/src/components/ImageBuilds/ImageExportCards.d.ts.map +1 -1
  116. package/dist/ui-components/src/components/ImageBuilds/ImageExportCards.js +109 -25
  117. package/dist/ui-components/src/components/ImageBuilds/ImageExportCards.js.map +1 -1
  118. package/dist/ui-components/src/components/Repository/CreateRepository/CreateRepositoryForm.d.ts.map +1 -1
  119. package/dist/ui-components/src/components/Repository/CreateRepository/CreateRepositoryForm.js +1 -1
  120. package/dist/ui-components/src/components/Repository/CreateRepository/CreateRepositoryForm.js.map +1 -1
  121. package/dist/ui-components/src/components/Repository/CreateRepository/utils.js +3 -3
  122. package/dist/ui-components/src/components/Repository/CreateRepository/utils.js.map +1 -1
  123. package/dist/ui-components/src/components/form/validations.d.ts +20 -18
  124. package/dist/ui-components/src/components/form/validations.d.ts.map +1 -1
  125. package/dist/ui-components/src/components/form/validations.js +40 -11
  126. package/dist/ui-components/src/components/form/validations.js.map +1 -1
  127. package/dist/ui-components/src/constants.d.ts +7 -6
  128. package/dist/ui-components/src/constants.d.ts.map +1 -1
  129. package/dist/ui-components/src/constants.js +19 -11
  130. package/dist/ui-components/src/constants.js.map +1 -1
  131. package/dist/ui-components/src/types/deviceSpec.d.ts +44 -76
  132. package/dist/ui-components/src/types/deviceSpec.d.ts.map +1 -1
  133. package/dist/ui-components/src/types/deviceSpec.js +13 -26
  134. package/dist/ui-components/src/types/deviceSpec.js.map +1 -1
  135. package/dist/ui-components/src/types/extraTypes.d.ts +1 -7
  136. package/dist/ui-components/src/types/extraTypes.d.ts.map +1 -1
  137. package/dist/ui-components/src/types/extraTypes.js.map +1 -1
  138. package/dist/ui-components/src/types/rbac.d.ts +7 -1
  139. package/dist/ui-components/src/types/rbac.d.ts.map +1 -1
  140. package/dist/ui-components/src/types/rbac.js +6 -0
  141. package/dist/ui-components/src/types/rbac.js.map +1 -1
  142. package/dist/ui-components/src/utils/imageBuilds.d.ts +1 -0
  143. package/dist/ui-components/src/utils/imageBuilds.d.ts.map +1 -1
  144. package/dist/ui-components/src/utils/imageBuilds.js +7 -1
  145. package/dist/ui-components/src/utils/imageBuilds.js.map +1 -1
  146. package/dist/ui-components/src/utils/search.js +1 -1
  147. package/dist/ui-components/src/utils/search.js.map +1 -1
  148. package/package.json +1 -1
  149. package/src/components/AuthProvider/CreateAuthProvider/utils.ts +2 -2
  150. package/src/components/DetailsPage/Tables/ApplicationsTable.tsx +2 -2
  151. package/src/components/Device/DeviceDetails/DeviceDetailsPage.tsx +10 -4
  152. package/src/components/Device/EditDeviceWizard/deviceSpecUtils.ts +359 -425
  153. package/src/components/Device/EditDeviceWizard/steps/ApplicationContainerForm.tsx +19 -29
  154. package/src/components/Device/EditDeviceWizard/steps/ApplicationHelmForm.tsx +4 -12
  155. package/src/components/Device/EditDeviceWizard/steps/ApplicationImageForm.tsx +2 -16
  156. package/src/components/Device/EditDeviceWizard/steps/ApplicationInlineForm.tsx +8 -7
  157. package/src/components/Device/EditDeviceWizard/steps/ApplicationIntegritySettings.tsx +5 -5
  158. package/src/components/Device/EditDeviceWizard/steps/ApplicationTemplates.tsx +29 -101
  159. package/src/components/Device/EditDeviceWizard/steps/ApplicationVariablesForm.tsx +87 -0
  160. package/src/components/Device/EditDeviceWizard/steps/ApplicationVolumeForm.tsx +5 -10
  161. package/src/components/Fleet/CreateFleet/utils.ts +4 -4
  162. package/src/components/Fleet/ImportFleetWizard/steps/RepositoryStep.tsx +11 -8
  163. package/src/components/ImageBuilds/CancelImageBuildModal/CancelImageBuildModal.tsx +81 -0
  164. package/src/components/ImageBuilds/ConfirmImageExportModal/ConfirmImageExportModal.tsx +48 -0
  165. package/src/components/ImageBuilds/CreateImageBuildWizard/utils.ts +3 -3
  166. package/src/components/ImageBuilds/ImageBuildDetails/ImageBuildDetailsPage.tsx +35 -16
  167. package/src/components/ImageBuilds/ImageBuildDetails/ImageBuildExportsGallery.tsx +120 -42
  168. package/src/components/ImageBuilds/ImageBuildRow.tsx +41 -20
  169. package/src/components/ImageBuilds/ImageBuildsPage.tsx +34 -15
  170. package/src/components/ImageBuilds/ImageExportCards.tsx +176 -77
  171. package/src/components/Repository/CreateRepository/CreateRepositoryForm.css +5 -1
  172. package/src/components/Repository/CreateRepository/CreateRepositoryForm.tsx +1 -0
  173. package/src/components/Repository/CreateRepository/utils.ts +4 -4
  174. package/src/components/form/validations.ts +112 -82
  175. package/src/constants.ts +19 -6
  176. package/src/types/deviceSpec.ts +68 -108
  177. package/src/types/extraTypes.ts +2 -12
  178. package/src/types/rbac.ts +6 -0
  179. package/src/utils/imageBuilds.ts +8 -0
  180. package/src/utils/search.ts +2 -2
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.hasMicroshiftRegistrationConfig = exports.MicroshiftRegistrationHook = exports.ACMImportConfig = exports.ACMCrdConfig = exports.formatFileMode = exports.getConfigTemplatesValues = exports.getSystemdUnitsValues = exports.getApplicationValues = exports.createInitialAppForm = exports.getApiConfig = exports.getApplicationPatches = exports.toAPIApplication = exports.getDeviceSpecConfigPatches = exports.getConfigType = exports.ACM_REPO_NAME = void 0;
3
+ exports.hasMicroshiftRegistrationConfig = exports.MicroshiftRegistrationHook = exports.ACMImportConfig = exports.ACMCrdConfig = exports.formatFileMode = exports.getConfigTemplatesValues = exports.getSystemdUnitsValues = exports.getApplicationValues = exports.createInitialAppForm = exports.getApiConfig = exports.getApplicationPatches = exports.toApiApplication = exports.getDeviceSpecConfigPatches = exports.getConfigType = exports.ACM_REPO_NAME = void 0;
4
4
  const tslib_1 = require("tslib");
5
5
  const js_yaml_1 = tslib_1.__importDefault(require("js-yaml"));
6
6
  const types_1 = require("@flightctl/types");
@@ -150,308 +150,314 @@ const getDeviceSpecConfigPatches = (currentConfigs, newConfigs, configPath) => {
150
150
  return allPatches;
151
151
  };
152
152
  exports.getDeviceSpecConfigPatches = getDeviceSpecConfigPatches;
153
- const toAPIApplication = (app) => {
154
- var _a, _b, _c;
155
- if ((0, deviceSpec_1.isHelmImageAppForm)(app)) {
156
- const data = {
157
- name: app.name,
158
- image: app.image,
159
- appType: app.appType,
160
- };
161
- if (app.namespace) {
162
- data.namespace = app.namespace;
163
- }
164
- if (app.valuesYaml) {
165
- try {
166
- const values = js_yaml_1.default.load(app.valuesYaml);
167
- if (values && Object.keys(values).length > 0) {
168
- data.values = values;
169
- }
170
- }
171
- catch (error) {
172
- throw new Error('Values content is not valid YAML.');
173
- }
174
- }
175
- const fileNames = app.valuesFiles.filter((file) => file && file.trim() !== '');
176
- if (fileNames.length > 0) {
177
- data.valuesFiles = fileNames;
178
- }
179
- return data;
180
- }
181
- const envVars = app.variables.reduce((acc, variable) => {
182
- acc[variable.name] = variable.value;
183
- return acc;
184
- }, {});
185
- const volumes = (_a = app.volumes) === null || _a === void 0 ? void 0 : _a.map((v) => {
186
- const volume = {
187
- name: v.name || '',
188
- };
189
- if (v.imageRef) {
190
- volume.image = {
191
- reference: v.imageRef,
192
- pullPolicy: v.imagePullPolicy || types_1.ImagePullPolicy.PullIfNotPresent,
193
- };
194
- }
195
- if (v.mountPath) {
196
- volume.mount = {
197
- path: v.mountPath,
198
- };
199
- }
200
- return volume;
153
+ const haveInlineFilesChanged = (current, updated) => {
154
+ if (current.length !== updated.length)
155
+ return true;
156
+ return current.some((file, index) => {
157
+ const other = updated[index];
158
+ const aBase64 = file.contentEncoding === types_1.EncodingType.EncodingBase64;
159
+ const bBase64 = other.contentEncoding === types_1.EncodingType.EncodingBase64;
160
+ return (aBase64 !== bBase64 || (file.path || '') !== (other.path || '') || (file.content || '') !== (other.content || ''));
201
161
  });
202
- if ((0, deviceSpec_1.isSingleContainerAppForm)(app)) {
203
- const data = {
204
- image: app.image,
205
- appType: app.appType,
206
- envVars,
207
- volumes,
208
- };
209
- if (app.name) {
210
- data.name = app.name;
211
- }
212
- if (app.ports) {
213
- data.ports = app.ports.map((p) => `${p.hostPort}:${p.containerPort}`);
214
- }
215
- // Removed fields must not appear in the resources object
216
- const appLimits = {};
217
- if ((_b = app.limits) === null || _b === void 0 ? void 0 : _b.cpu) {
218
- appLimits.cpu = app.limits.cpu;
219
- }
220
- if ((_c = app.limits) === null || _c === void 0 ? void 0 : _c.memory) {
221
- appLimits.memory = app.limits.memory;
222
- }
223
- if (Object.keys(appLimits).length > 0) {
224
- data.resources = {
225
- limits: appLimits,
226
- };
227
- }
228
- data.runAs = app.runAs || deviceSpec_1.RUN_AS_DEFAULT_USER;
229
- return data;
230
- }
231
- if ((0, deviceSpec_1.isQuadletImageAppForm)(app) || (0, deviceSpec_1.isComposeImageAppForm)(app)) {
232
- const data = {
233
- image: app.image,
234
- appType: app.appType,
235
- envVars,
236
- volumes,
237
- };
238
- if (app.name) {
239
- data.name = app.name;
240
- }
241
- if ((0, deviceSpec_1.isQuadletImageAppForm)(app) && app.runAs) {
242
- data.runAs = app.runAs;
243
- }
244
- return data;
245
- }
246
- // Inline applications (Quadlet or Compose)
247
- const inlineData = {
248
- name: app.name,
249
- appType: app.appType,
250
- inline: toAPIFiles(app.files),
251
- envVars,
252
- volumes,
253
- };
254
- if ((0, deviceSpec_1.isQuadletInlineAppForm)(app) && app.runAs) {
255
- inlineData.runAs = app.runAs;
256
- }
257
- return inlineData;
258
162
  };
259
- exports.toAPIApplication = toAPIApplication;
260
- const hasInlineApplicationChanged = (currentApp, updatedApp) => {
261
- if (currentApp.inline.length !== updatedApp.files.length) {
163
+ const haveEnvVarsChanged = (current, updated) => {
164
+ const aKeys = Object.keys(current);
165
+ const bKeys = Object.keys(updated);
166
+ if (aKeys.length !== bKeys.length)
262
167
  return true;
263
- }
264
- const filesChanged = currentApp.inline.some((file, index) => {
265
- const updatedFile = updatedApp.files[index];
266
- const isCurrentBase64 = file.contentEncoding === types_1.EncodingType.EncodingBase64;
267
- return ((updatedFile.base64 || false) !== isCurrentBase64 ||
268
- updatedFile.path !== file.path ||
269
- updatedFile.content !== file.content);
270
- });
271
- if (filesChanged) {
168
+ return aKeys.some((key) => current[key] !== updated[key]);
169
+ };
170
+ const haveVolumesChanged = (current, updated) => {
171
+ if (current.length !== updated.length)
272
172
  return true;
273
- }
274
- // Check runAs for Quadlet inline apps
275
- if ((0, deviceSpec_1.isQuadletInlineAppForm)(updatedApp)) {
276
- const currentAppWithRunAs = currentApp;
277
- if ((currentAppWithRunAs.runAs || deviceSpec_1.RUN_AS_DEFAULT_USER) !== (updatedApp.runAs || deviceSpec_1.RUN_AS_DEFAULT_USER)) {
173
+ return current.some((currentVol, index) => {
174
+ var _a, _b, _c, _d, _e, _f;
175
+ const updatedVol = updated[index];
176
+ if (currentVol.name !== updatedVol.name)
177
+ return true;
178
+ if ((currentVol.reclaimPolicy || types_1.ApplicationVolumeReclaimPolicy.RETAIN) !==
179
+ (updatedVol.reclaimPolicy || types_1.ApplicationVolumeReclaimPolicy.RETAIN))
180
+ return true;
181
+ const currentFull = currentVol;
182
+ const updatedFull = updatedVol;
183
+ const currentImageRef = ((_a = currentFull.image) === null || _a === void 0 ? void 0 : _a.reference) || '';
184
+ const updatedImageRef = ((_b = updatedFull.image) === null || _b === void 0 ? void 0 : _b.reference) || '';
185
+ if (currentImageRef !== updatedImageRef)
278
186
  return true;
279
- }
280
- }
281
- return !areVolumesEqual(currentApp.volumes || [], updatedApp.volumes || []);
282
- };
283
- const areVolumesEqual = (currentVolumes, updatedFormVolumes) => {
284
- if (currentVolumes.length !== updatedFormVolumes.length) {
285
- return false;
286
- }
287
- return currentVolumes.every((currentVol, index) => {
288
- var _a, _b, _c;
289
- const updatedFormVol = updatedFormVolumes[index];
290
- const currentFullVol = currentVol;
291
- if (currentFullVol.name !== updatedFormVol.name) {
292
- return false;
293
- }
294
- const currentImageRef = ((_a = currentFullVol.image) === null || _a === void 0 ? void 0 : _a.reference) || '';
295
- const updatedImageRef = (updatedFormVol === null || updatedFormVol === void 0 ? void 0 : updatedFormVol.imageRef) || '';
296
- if (currentImageRef !== updatedImageRef) {
297
- return false;
298
- }
299
187
  if (currentImageRef || updatedImageRef) {
300
- const currentPullPolicy = ((_b = currentFullVol.image) === null || _b === void 0 ? void 0 : _b.pullPolicy) || types_1.ImagePullPolicy.PullIfNotPresent;
301
- const updatedPullPolicy = (updatedFormVol === null || updatedFormVol === void 0 ? void 0 : updatedFormVol.imagePullPolicy) || types_1.ImagePullPolicy.PullIfNotPresent;
302
- if (currentPullPolicy !== updatedPullPolicy) {
303
- return false;
304
- }
305
- }
306
- const currentMountPath = ((_c = currentFullVol.mount) === null || _c === void 0 ? void 0 : _c.path) || '';
307
- const updatedMountPath = (updatedFormVol === null || updatedFormVol === void 0 ? void 0 : updatedFormVol.mountPath) || '';
308
- if (currentMountPath !== updatedMountPath) {
309
- return false;
188
+ if ((((_c = currentFull.image) === null || _c === void 0 ? void 0 : _c.pullPolicy) || types_1.ImagePullPolicy.PullIfNotPresent) !==
189
+ (((_d = updatedFull.image) === null || _d === void 0 ? void 0 : _d.pullPolicy) || types_1.ImagePullPolicy.PullIfNotPresent))
190
+ return true;
310
191
  }
311
- return true;
192
+ return (((_e = currentFull.mount) === null || _e === void 0 ? void 0 : _e.path) || '') !== (((_f = updatedFull.mount) === null || _f === void 0 ? void 0 : _f.path) || '');
312
193
  });
313
194
  };
314
- const arePortsEqual = (currentPorts, updatedPorts) => {
315
- if (currentPorts.length !== updatedPorts.length) {
316
- return false;
317
- }
318
- // Reordered ports will be considered as changed
319
- return currentPorts.every((currentPort, index) => {
320
- const updatedPort = updatedPorts[index];
321
- return currentPort === `${updatedPort.hostPort}:${updatedPort.containerPort}`;
322
- });
195
+ const hasStringChanged = (current, updated, defaultValue = '') => (current || defaultValue) !== (updated || defaultValue);
196
+ const havePortsChanged = (current, updated) => {
197
+ if (current.length !== updated.length)
198
+ return true;
199
+ return current.some((port, index) => port !== updated[index]);
323
200
  };
324
- const areResourceLimitsEqual = (currentLimits, updatedLimits) => {
325
- const currentCpu = (currentLimits === null || currentLimits === void 0 ? void 0 : currentLimits.cpu) || '';
326
- const updatedCpu = (updatedLimits === null || updatedLimits === void 0 ? void 0 : updatedLimits.cpu) || '';
327
- const currentMemory = (currentLimits === null || currentLimits === void 0 ? void 0 : currentLimits.memory) || '';
328
- const updatedMemory = (updatedLimits === null || updatedLimits === void 0 ? void 0 : updatedLimits.memory) || '';
329
- return currentCpu === updatedCpu && currentMemory === updatedMemory;
201
+ const haveResourceLimitsChanged = (current, updated) => {
202
+ return ((current === null || current === void 0 ? void 0 : current.cpu) || '') !== ((updated === null || updated === void 0 ? void 0 : updated.cpu) || '') || ((current === null || current === void 0 ? void 0 : current.memory) || '') !== ((updated === null || updated === void 0 ? void 0 : updated.memory) || '');
330
203
  };
331
- const areEnvVariablesEqual = (currentVars, updatedFormVars) => {
332
- const envVars = currentVars || {};
333
- if (Object.keys(envVars).length !== updatedFormVars.length) {
334
- return false;
335
- }
336
- return updatedFormVars.every((variable) => {
337
- // Envvars may have "falsy" values (eg. number 0) when they are defined
338
- return variable.name in envVars && envVars[variable.name] === variable.value;
339
- });
204
+ const haveValuesFilesChanged = (current, updated) => {
205
+ const a = current.filter((f) => f.trim() !== '');
206
+ const b = updated.filter((f) => f.trim() !== '');
207
+ if (a.length !== b.length)
208
+ return true;
209
+ return a.some((file, i) => file !== b[i]);
340
210
  };
341
- const hasSingleContainerAppChanged = (currentApp, updatedApp) => {
342
- var _a;
343
- if (!(0, deviceSpec_1.isSingleContainerAppForm)(updatedApp)) {
211
+ const haveHelmValuesChanged = (current, updated) => JSON.stringify(current) !== JSON.stringify(updated);
212
+ const hasRunAsChanged = (current, updated) => {
213
+ if (!current) {
214
+ // For empty "runAs", we mark the app as changed.
215
+ // This means that we'll set the field explicitly to the default user (currently "root").
344
216
  return true;
345
217
  }
346
- const imageApp = currentApp;
347
- if (imageApp.name !== updatedApp.name || imageApp.image !== updatedApp.image) {
218
+ return current !== updated;
219
+ };
220
+ // Single container apps always have an image, and it doesn't have an inline variant
221
+ const hasContainerAppChanged = (current, updated) => {
222
+ var _a, _b;
223
+ return hasStringChanged(current.name, updated.name) ||
224
+ hasStringChanged(current.image, updated.image) ||
225
+ havePortsChanged(current.ports || [], updated.ports || []) ||
226
+ haveResourceLimitsChanged((_a = current.resources) === null || _a === void 0 ? void 0 : _a.limits, (_b = updated.resources) === null || _b === void 0 ? void 0 : _b.limits) ||
227
+ haveEnvVarsChanged(current.envVars || {}, updated.envVars || {}) ||
228
+ hasRunAsChanged(current.runAs, updated.runAs) ||
229
+ haveVolumesChanged(current.volumes || [], updated.volumes || []);
230
+ };
231
+ // Helm apps always have an image (chart), and it doesn't have an inline variant
232
+ const hasHelmAppChanged = (current, updated) => hasStringChanged(current.name, updated.name) ||
233
+ hasStringChanged(current.image, updated.image) ||
234
+ hasStringChanged(current.namespace, updated.namespace) ||
235
+ haveValuesFilesChanged(current.valuesFiles || [], updated.valuesFiles || []) ||
236
+ haveHelmValuesChanged(current.values || {}, updated.values || {});
237
+ const hasComposeAppChanged = (current, updated, specType) => {
238
+ const baseChanged = hasStringChanged(current.name, updated.name) ||
239
+ haveEnvVarsChanged(current.envVars || {}, updated.envVars || {}) ||
240
+ haveVolumesChanged(current.volumes || [], updated.volumes || []);
241
+ if (baseChanged) {
348
242
  return true;
349
243
  }
350
- if (!arePortsEqual(imageApp.ports || [], updatedApp.ports || [])) {
351
- return true;
244
+ if (specType === deviceSpec_1.AppSpecType.OCI_IMAGE) {
245
+ return hasStringChanged(current.image, updated.image);
352
246
  }
353
- if (!areResourceLimitsEqual((_a = imageApp.resources) === null || _a === void 0 ? void 0 : _a.limits, updatedApp.limits)) {
247
+ return haveInlineFilesChanged(current.inline, updated.inline);
248
+ };
249
+ // Quadlet apps are currently the same as Compose apps, plus an optional "runAs" field.
250
+ const hasQuadletAppChanged = (current, updated, specType) => {
251
+ const baseChanged = hasComposeAppChanged(current, updated, specType);
252
+ if (baseChanged) {
354
253
  return true;
355
254
  }
356
- if (!areEnvVariablesEqual(imageApp.envVars, updatedApp.variables)) {
255
+ return hasRunAsChanged(current.runAs, updated.runAs);
256
+ };
257
+ const hasApplicationChanged = (current, updated) => {
258
+ if (current.appType !== updated.appType) {
357
259
  return true;
358
260
  }
359
- if ((imageApp.runAs || deviceSpec_1.RUN_AS_DEFAULT_USER) !== (updatedApp.runAs || deviceSpec_1.RUN_AS_DEFAULT_USER)) {
261
+ const currentSpectType = (0, deviceSpec_1.isImageVariantApp)(current) ? deviceSpec_1.AppSpecType.OCI_IMAGE : deviceSpec_1.AppSpecType.INLINE;
262
+ const updatedSpectType = (0, deviceSpec_1.isImageVariantApp)(updated) ? deviceSpec_1.AppSpecType.OCI_IMAGE : deviceSpec_1.AppSpecType.INLINE;
263
+ if (currentSpectType !== updatedSpectType) {
360
264
  return true;
361
265
  }
362
- return !areVolumesEqual(imageApp.volumes || [], updatedApp.volumes || []);
363
- };
364
- const hasApplicationChanged = (currentApp, updatedApp) => {
365
- const isCurrentImageApp = (0, deviceSpec_1.isImageAppProvider)(currentApp);
366
- const currentAppSpecType = isCurrentImageApp ? deviceSpec_1.AppSpecType.OCI_IMAGE : deviceSpec_1.AppSpecType.INLINE;
367
- // Check if application name changed, or it's a different type of application (either specType or appType)
368
- if (currentAppSpecType !== updatedApp.specType ||
369
- currentApp.appType !== updatedApp.appType ||
370
- currentApp.name !== updatedApp.name) {
371
- return true;
266
+ switch (current.appType) {
267
+ case types_1.AppType.AppTypeContainer:
268
+ return hasContainerAppChanged(current, updated);
269
+ case types_1.AppType.AppTypeHelm:
270
+ return hasHelmAppChanged(current, updated);
271
+ case types_1.AppType.AppTypeQuadlet:
272
+ return hasQuadletAppChanged(current, updated, currentSpectType);
273
+ case types_1.AppType.AppTypeCompose:
274
+ return hasComposeAppChanged(current, updated, currentSpectType);
372
275
  }
373
- // The app is a single container application
374
- if ((0, deviceSpec_1.isSingleContainerAppForm)(updatedApp)) {
375
- return hasSingleContainerAppChanged(currentApp, updatedApp);
276
+ };
277
+ const variablesToEnvVars = (variables) => {
278
+ if (variables.length === 0) {
279
+ return undefined;
376
280
  }
377
- // The app is a Helm application
378
- if ((0, deviceSpec_1.isHelmImageAppForm)(updatedApp)) {
379
- const imageApp = currentApp;
380
- if (imageApp.image !== updatedApp.image || imageApp.namespace !== updatedApp.namespace) {
381
- return true;
281
+ return variables.reduce((acc, v) => {
282
+ if (v.name) {
283
+ acc[v.name] = v.value || '';
382
284
  }
383
- // Compare valuesFiles arrays
384
- const currentValuesFiles = (imageApp.valuesFiles || []).filter((file) => file !== '');
385
- const updatedValuesFiles = updatedApp.valuesFiles.filter((file) => file !== '');
386
- if (currentValuesFiles.length !== updatedValuesFiles.length) {
387
- return true;
285
+ return acc;
286
+ }, {});
287
+ };
288
+ /**
289
+ * Converts form volumes to API volumes, ignoring fields that are not allowed for the given app type.
290
+ * Quadlet/Compose apps --> can only be image volumes (mount is not allowed)
291
+ * Container apps --> can either be mount or image mount volumes
292
+ */
293
+ const formVolumesToApi = (volumes, appType) => {
294
+ return volumes.map((v) => {
295
+ const vol = {
296
+ name: v.name || '',
297
+ };
298
+ if (v.imageRef) {
299
+ vol.image = {
300
+ reference: v.imageRef,
301
+ pullPolicy: v.imagePullPolicy || types_1.ImagePullPolicy.PullIfNotPresent,
302
+ };
388
303
  }
389
- if (!currentValuesFiles.every((file, index) => file === updatedValuesFiles[index])) {
390
- return true;
304
+ if (v.mountPath && appType === types_1.AppType.AppTypeContainer) {
305
+ vol.mount = { path: v.mountPath };
391
306
  }
392
- const updatedValues = js_yaml_1.default.load(updatedApp.valuesYaml || ' ');
393
- if (JSON.stringify(imageApp.values || {}) !== JSON.stringify(updatedValues)) {
394
- return true;
307
+ return vol;
308
+ });
309
+ };
310
+ const formFilesToApi = (files) => files.map((f) => ({
311
+ path: f.path,
312
+ content: f.content || '',
313
+ contentEncoding: f.base64 ? types_1.EncodingType.EncodingBase64 : types_1.EncodingType.EncodingPlain,
314
+ }));
315
+ const toFormFiles = (files) => files.map((file) => ({
316
+ path: file.path || '',
317
+ content: file.content || '',
318
+ base64: file.contentEncoding === types_1.EncodingType.EncodingBase64,
319
+ }));
320
+ const toApiHelmApp = (app) => {
321
+ const helmApp = {
322
+ name: app.name,
323
+ image: app.image,
324
+ appType: app.appType,
325
+ };
326
+ if (app.namespace) {
327
+ helmApp.namespace = app.namespace;
328
+ }
329
+ if (app.valuesYaml) {
330
+ try {
331
+ const values = js_yaml_1.default.load(app.valuesYaml);
332
+ if (values && Object.keys(values).length > 0)
333
+ helmApp.values = values;
334
+ }
335
+ catch (_a) {
336
+ // leave values unset on invalid YAML
395
337
  }
396
- return false;
397
338
  }
398
- if (!areEnvVariablesEqual(currentApp.envVars, updatedApp.variables)) {
399
- return true;
339
+ const fileNames = (app.valuesFiles || []).filter((f) => f.trim() !== '');
340
+ if (fileNames.length > 0) {
341
+ helmApp.valuesFiles = fileNames;
400
342
  }
401
- // The app is an image application (Quadlet/Compose image apps)
402
- if (isCurrentImageApp) {
403
- const imageApp = currentApp;
404
- const updatedImageApp = updatedApp;
405
- if (imageApp.image !== updatedImageApp.image) {
406
- return true;
343
+ return helmApp;
344
+ };
345
+ const toApiContainerApp = (app) => {
346
+ const containerApp = {
347
+ image: app.image,
348
+ appType: app.appType,
349
+ runAs: app.runAs || deviceSpec_1.RUN_AS_ROOT_USER,
350
+ envVars: variablesToEnvVars(app.variables || []),
351
+ volumes: formVolumesToApi(app.volumes || [], types_1.AppType.AppTypeContainer),
352
+ };
353
+ if (app.name) {
354
+ containerApp.name = app.name;
355
+ }
356
+ if (app.ports.length > 0) {
357
+ containerApp.ports = app.ports.map((p) => `${p.hostPort}:${p.containerPort}`);
358
+ }
359
+ const cpu = app.cpuLimit;
360
+ const memory = app.memoryLimit;
361
+ if (cpu || memory) {
362
+ const limits = {};
363
+ if (cpu) {
364
+ limits.cpu = cpu;
407
365
  }
408
- // Check runAs for Quadlet image apps
409
- if ((0, deviceSpec_1.isQuadletImageAppForm)(updatedApp)) {
410
- if ((currentApp.runAs || deviceSpec_1.RUN_AS_DEFAULT_USER) !== (updatedApp.runAs || deviceSpec_1.RUN_AS_DEFAULT_USER)) {
411
- return true;
412
- }
366
+ if (memory) {
367
+ limits.memory = memory;
413
368
  }
414
- return !areVolumesEqual(imageApp.volumes || [], updatedApp.volumes || []);
369
+ containerApp.resources = { limits };
370
+ }
371
+ return containerApp;
372
+ };
373
+ const toApiComposeApp = (app) => {
374
+ const formApp = {
375
+ appType: app.appType,
376
+ envVars: variablesToEnvVars(app.variables || []),
377
+ volumes: formVolumesToApi(app.volumes || [], app.appType),
378
+ };
379
+ if (app.name) {
380
+ formApp.name = app.name;
381
+ }
382
+ if (app.specType === deviceSpec_1.AppSpecType.OCI_IMAGE) {
383
+ formApp.image = app.image;
384
+ }
385
+ else {
386
+ formApp.inline = formFilesToApi(app.files);
387
+ }
388
+ return formApp;
389
+ };
390
+ // Quadlet apps are currently the same as Compose apps, plus an optional "runAs" field.
391
+ const toApiQuadletApp = (app) => {
392
+ const baseApp = toApiComposeApp(app);
393
+ return Object.assign(Object.assign({}, baseApp), { appType: types_1.AppType.AppTypeQuadlet, runAs: app.runAs || deviceSpec_1.RUN_AS_ROOT_USER });
394
+ };
395
+ const toApiApplication = (app) => {
396
+ switch (app.appType) {
397
+ case types_1.AppType.AppTypeHelm:
398
+ return toApiHelmApp(app);
399
+ case types_1.AppType.AppTypeContainer:
400
+ return toApiContainerApp(app);
401
+ case types_1.AppType.AppTypeQuadlet:
402
+ return toApiQuadletApp(app);
403
+ case types_1.AppType.AppTypeCompose:
404
+ return toApiComposeApp(app);
405
+ default:
406
+ throw new Error('Unknown application type');
407
+ }
408
+ };
409
+ exports.toApiApplication = toApiApplication;
410
+ const toFormVariables = (envVars) => Object.entries(envVars).map(([name, value]) => ({ name, value: value || '' }));
411
+ const toFormVolumes = (volumes) => {
412
+ if (!volumes)
413
+ return [];
414
+ return volumes.map((vol) => {
415
+ var _a, _b, _c;
416
+ const fullVolume = vol;
417
+ return {
418
+ name: fullVolume.name,
419
+ imageRef: ((_a = fullVolume.image) === null || _a === void 0 ? void 0 : _a.reference) || '',
420
+ mountPath: ((_b = fullVolume.mount) === null || _b === void 0 ? void 0 : _b.path) || '',
421
+ imagePullPolicy: ((_c = fullVolume.image) === null || _c === void 0 ? void 0 : _c.pullPolicy) || types_1.ImagePullPolicy.PullIfNotPresent,
422
+ };
423
+ });
424
+ };
425
+ const toFormApps = (app) => {
426
+ switch (app.appType) {
427
+ case types_1.AppType.AppTypeContainer:
428
+ return toContainerAppForm(app);
429
+ case types_1.AppType.AppTypeHelm:
430
+ return toHelmAppForm(app);
431
+ case types_1.AppType.AppTypeQuadlet:
432
+ return toQuadletAppForm(app);
433
+ case types_1.AppType.AppTypeCompose:
434
+ return toComposeAppForm(app);
435
+ default:
436
+ throw new Error('Unknown application type');
415
437
  }
416
- // The app must be an inline application
417
- return hasInlineApplicationChanged(currentApp, updatedApp);
418
438
  };
419
439
  const getApplicationPatches = (basePath, currentApps, updatedApps) => {
420
440
  const patches = [];
421
441
  const currentLen = currentApps.length;
422
442
  const newLen = updatedApps.length;
423
443
  if (currentLen === 0 && newLen > 0) {
424
- // First apps(s) have been added
425
- patches.push({
426
- path: `${basePath}/applications`,
427
- op: 'add',
428
- value: updatedApps.map(exports.toAPIApplication),
429
- });
444
+ patches.push({ path: `${basePath}/applications`, op: 'add', value: updatedApps.map(exports.toApiApplication) });
430
445
  }
431
446
  else if (currentLen > 0 && newLen === 0) {
432
- // Last app(s) have been removed
433
- patches.push({
434
- path: `${basePath}/applications`,
435
- op: 'remove',
436
- });
447
+ patches.push({ path: `${basePath}/applications`, op: 'remove' });
437
448
  }
438
449
  else if (currentLen !== newLen) {
439
- // Array length changed, need to replace entire array
440
- patches.push({
441
- path: `${basePath}/applications`,
442
- op: 'replace',
443
- value: updatedApps.map(exports.toAPIApplication),
444
- });
450
+ patches.push({ path: `${basePath}/applications`, op: 'replace', value: updatedApps.map(exports.toApiApplication) });
445
451
  }
446
452
  else {
447
- // Apps length has not changed. We only PATCH the applications that have actually changed
448
453
  currentApps.forEach((currentApp, index) => {
449
454
  const updatedApp = updatedApps[index];
450
- if (hasApplicationChanged(currentApp, updatedApp)) {
455
+ const updatedApi = (0, exports.toApiApplication)(updatedApp);
456
+ if (hasApplicationChanged(currentApp, updatedApi)) {
451
457
  patches.push({
452
458
  path: `${basePath}/applications/${index}`,
453
459
  op: 'replace',
454
- value: (0, exports.toAPIApplication)(updatedApp),
460
+ value: updatedApi,
455
461
  });
456
462
  }
457
463
  });
@@ -511,40 +517,15 @@ const getApiConfig = (ct) => {
511
517
  };
512
518
  };
513
519
  exports.getApiConfig = getApiConfig;
514
- const getAppFormVariables = (envVars) => Object.entries(envVars || {}).map(([varName, varValue]) => ({ name: varName, value: varValue }));
515
- const toFormFiles = (files) => {
516
- return files.map((file) => ({
517
- path: file.path || '',
518
- content: file.content || '',
519
- base64: file.contentEncoding === types_1.EncodingType.EncodingBase64,
520
- }));
521
- };
522
- const toAPIFiles = (files) => {
523
- return files.map((file) => ({
524
- path: file.path,
525
- content: file.content || '',
526
- contentEncoding: file.base64 ? types_1.EncodingType.EncodingBase64 : types_1.EncodingType.EncodingPlain,
527
- }));
528
- };
529
- const convertVolumesToForm = (volumes) => {
530
- if (!volumes)
531
- return [];
532
- return volumes.map((vol) => {
533
- var _a, _b;
534
- const fullVolume = vol;
535
- const volForm = {
536
- name: fullVolume.name,
537
- imageRef: ((_a = fullVolume.image) === null || _a === void 0 ? void 0 : _a.reference) || '',
538
- mountPath: ((_b = fullVolume.mount) === null || _b === void 0 ? void 0 : _b.path) || '',
539
- };
540
- // Only set imagePullPolicy if there's an image
541
- if (fullVolume.image) {
542
- volForm.imagePullPolicy = fullVolume.image.pullPolicy || types_1.ImagePullPolicy.PullIfNotPresent;
543
- }
544
- return volForm;
545
- });
520
+ const getRunAsUser = (app) => {
521
+ if (app) {
522
+ // Existing apps that don't have a "runAs" user are actually running as the "root" user.
523
+ return app.runAs || deviceSpec_1.RUN_AS_ROOT_USER;
524
+ }
525
+ // For new applications, we want to promote "flightctl" as the default user.
526
+ return deviceSpec_1.RUN_AS_FLIGHTCTL_USER;
546
527
  };
547
- const createContainerApp = (containerApp) => {
528
+ const toContainerAppForm = (containerApp) => {
548
529
  var _a, _b;
549
530
  const ports = ((_a = containerApp === null || containerApp === void 0 ? void 0 : containerApp.ports) === null || _a === void 0 ? void 0 : _a.map((portString) => {
550
531
  const [hostPort, containerPort] = portString.split(':');
@@ -556,114 +537,78 @@ const createContainerApp = (containerApp) => {
556
537
  specType: deviceSpec_1.AppSpecType.OCI_IMAGE,
557
538
  name: (containerApp === null || containerApp === void 0 ? void 0 : containerApp.name) || '',
558
539
  image: (containerApp === null || containerApp === void 0 ? void 0 : containerApp.image) || '',
559
- variables: getAppFormVariables(containerApp === null || containerApp === void 0 ? void 0 : containerApp.envVars),
560
- volumes: convertVolumesToForm(containerApp === null || containerApp === void 0 ? void 0 : containerApp.volumes),
540
+ variables: toFormVariables((containerApp === null || containerApp === void 0 ? void 0 : containerApp.envVars) || {}),
541
+ volumes: toFormVolumes(containerApp === null || containerApp === void 0 ? void 0 : containerApp.volumes),
561
542
  ports,
562
- limits: limits
563
- ? {
564
- cpu: limits.cpu || '',
565
- memory: limits.memory || '',
566
- }
567
- : undefined,
568
- runAs: (containerApp === null || containerApp === void 0 ? void 0 : containerApp.runAs) || deviceSpec_1.RUN_AS_DEFAULT_USER,
543
+ cpuLimit: (limits === null || limits === void 0 ? void 0 : limits.cpu) || '',
544
+ memoryLimit: (limits === null || limits === void 0 ? void 0 : limits.memory) || '',
545
+ runAs: getRunAsUser(containerApp),
569
546
  };
570
547
  };
571
- const createHelmApp = (helmApp) => {
548
+ const toHelmAppForm = (helmApp) => {
549
+ var _a;
550
+ // We want to always show at least one values file field, even when no files have been added yet.
572
551
  const values = (helmApp === null || helmApp === void 0 ? void 0 : helmApp.values) || {};
552
+ const valuesFiles = ((_a = helmApp === null || helmApp === void 0 ? void 0 : helmApp.valuesFiles) === null || _a === void 0 ? void 0 : _a.length) ? helmApp.valuesFiles : [''];
553
+ const valuesYaml = Object.keys(values || {}).length > 0 ? js_yaml_1.default.dump(values) : '';
573
554
  return {
574
555
  appType: types_1.AppType.AppTypeHelm,
575
556
  specType: deviceSpec_1.AppSpecType.OCI_IMAGE,
576
557
  name: (helmApp === null || helmApp === void 0 ? void 0 : helmApp.name) || '',
577
558
  image: (helmApp === null || helmApp === void 0 ? void 0 : helmApp.image) || '',
578
- namespace: helmApp === null || helmApp === void 0 ? void 0 : helmApp.namespace,
579
- valuesYaml: Object.keys(values).length > 0 ? js_yaml_1.default.dump(values) : '',
580
- valuesFiles: (helmApp === null || helmApp === void 0 ? void 0 : helmApp.valuesFiles) || [''],
581
- };
582
- };
583
- const createQuadletImageApp = (quadletApp) => {
584
- return {
585
- appType: types_1.AppType.AppTypeQuadlet,
586
- specType: deviceSpec_1.AppSpecType.OCI_IMAGE,
587
- name: (quadletApp === null || quadletApp === void 0 ? void 0 : quadletApp.name) || '',
588
- image: (quadletApp === null || quadletApp === void 0 ? void 0 : quadletApp.image) || '',
589
- variables: getAppFormVariables(quadletApp === null || quadletApp === void 0 ? void 0 : quadletApp.envVars),
590
- volumes: convertVolumesToForm(quadletApp === null || quadletApp === void 0 ? void 0 : quadletApp.volumes),
591
- runAs: (quadletApp === null || quadletApp === void 0 ? void 0 : quadletApp.runAs) || deviceSpec_1.RUN_AS_DEFAULT_USER,
559
+ namespace: (helmApp === null || helmApp === void 0 ? void 0 : helmApp.namespace) || '',
560
+ valuesYaml,
561
+ valuesFiles,
592
562
  };
593
563
  };
594
- const createQuadletInlineApp = (quadletApp) => {
595
- return {
596
- appType: types_1.AppType.AppTypeQuadlet,
597
- specType: deviceSpec_1.AppSpecType.INLINE,
598
- name: (quadletApp === null || quadletApp === void 0 ? void 0 : quadletApp.name) || '',
599
- files: toFormFiles((quadletApp === null || quadletApp === void 0 ? void 0 : quadletApp.inline) || []),
600
- variables: getAppFormVariables(quadletApp === null || quadletApp === void 0 ? void 0 : quadletApp.envVars),
601
- volumes: convertVolumesToForm(quadletApp === null || quadletApp === void 0 ? void 0 : quadletApp.volumes),
602
- runAs: (quadletApp === null || quadletApp === void 0 ? void 0 : quadletApp.runAs) || deviceSpec_1.RUN_AS_DEFAULT_USER,
603
- };
604
- };
605
- const createComposeImageApp = (composeApp) => {
606
- return {
564
+ const toComposeAppForm = (app) => {
565
+ const isInlineVariant = app && (0, deviceSpec_1.isInlineVariantApp)(app);
566
+ const specType = isInlineVariant ? deviceSpec_1.AppSpecType.INLINE : deviceSpec_1.AppSpecType.OCI_IMAGE;
567
+ const formApp = {
607
568
  appType: types_1.AppType.AppTypeCompose,
608
- specType: deviceSpec_1.AppSpecType.OCI_IMAGE,
609
- name: (composeApp === null || composeApp === void 0 ? void 0 : composeApp.name) || '',
610
- image: (composeApp === null || composeApp === void 0 ? void 0 : composeApp.image) || '',
611
- variables: getAppFormVariables(composeApp === null || composeApp === void 0 ? void 0 : composeApp.envVars),
612
- volumes: convertVolumesToForm(composeApp === null || composeApp === void 0 ? void 0 : composeApp.volumes),
569
+ specType,
570
+ name: (app === null || app === void 0 ? void 0 : app.name) || '',
571
+ variables: toFormVariables((app === null || app === void 0 ? void 0 : app.envVars) || {}),
572
+ volumes: toFormVolumes(app === null || app === void 0 ? void 0 : app.volumes),
613
573
  };
574
+ // We want to have both fields initialized for the formik form
575
+ if (isInlineVariant) {
576
+ formApp.files = toFormFiles((app === null || app === void 0 ? void 0 : app.inline) || []);
577
+ formApp.image = '';
578
+ }
579
+ else {
580
+ formApp.image = (app === null || app === void 0 ? void 0 : app.image) || '';
581
+ formApp.files = [];
582
+ }
583
+ return formApp;
614
584
  };
615
- const createComposeInlineApp = (composeApp) => {
616
- return {
617
- appType: types_1.AppType.AppTypeCompose,
618
- specType: deviceSpec_1.AppSpecType.INLINE,
619
- name: (composeApp === null || composeApp === void 0 ? void 0 : composeApp.name) || '',
620
- files: toFormFiles((composeApp === null || composeApp === void 0 ? void 0 : composeApp.inline) || []),
621
- variables: getAppFormVariables(composeApp === null || composeApp === void 0 ? void 0 : composeApp.envVars),
622
- volumes: convertVolumesToForm(composeApp === null || composeApp === void 0 ? void 0 : composeApp.volumes),
623
- };
585
+ const toQuadletAppForm = (app) => {
586
+ const baseApp = toComposeAppForm(app);
587
+ return Object.assign(Object.assign({}, baseApp), { appType: types_1.AppType.AppTypeQuadlet, runAs: getRunAsUser(app) });
624
588
  };
625
- const createInitialAppForm = (appType, specType, name = '') => {
589
+ const createInitialAppForm = (appType, name = '') => {
626
590
  let app;
627
591
  switch (appType) {
628
592
  case types_1.AppType.AppTypeContainer:
629
- app = createContainerApp(undefined);
593
+ app = toContainerAppForm(undefined);
630
594
  break;
631
595
  case types_1.AppType.AppTypeHelm:
632
- app = createHelmApp(undefined);
596
+ app = toHelmAppForm(undefined);
633
597
  break;
634
598
  case types_1.AppType.AppTypeQuadlet:
635
- app = specType === deviceSpec_1.AppSpecType.OCI_IMAGE ? createQuadletImageApp(undefined) : createQuadletInlineApp(undefined);
599
+ app = toQuadletAppForm(undefined);
636
600
  break;
637
601
  case types_1.AppType.AppTypeCompose:
638
- app = specType === deviceSpec_1.AppSpecType.OCI_IMAGE ? createComposeImageApp(undefined) : createComposeInlineApp(undefined);
602
+ app = toComposeAppForm(undefined);
639
603
  break;
604
+ default:
605
+ throw new Error('Unknown application type');
640
606
  }
641
607
  app.name = name;
642
608
  return app;
643
609
  };
644
610
  exports.createInitialAppForm = createInitialAppForm;
645
- const getApplicationValues = (deviceSpec) => {
646
- const apps = (deviceSpec === null || deviceSpec === void 0 ? void 0 : deviceSpec.applications) || [];
647
- return apps.map((app) => {
648
- if (!app.appType) {
649
- throw new Error('Application appType is required');
650
- }
651
- switch (app.appType) {
652
- case types_1.AppType.AppTypeContainer:
653
- return createContainerApp(app);
654
- case types_1.AppType.AppTypeHelm:
655
- return createHelmApp(app);
656
- case types_1.AppType.AppTypeQuadlet:
657
- return (0, deviceSpec_1.isImageAppProvider)(app)
658
- ? createQuadletImageApp(app)
659
- : createQuadletInlineApp(app);
660
- case types_1.AppType.AppTypeCompose:
661
- return (0, deviceSpec_1.isImageAppProvider)(app)
662
- ? createComposeImageApp(app)
663
- : createComposeInlineApp(app);
664
- }
665
- });
666
- };
611
+ const getApplicationValues = (deviceSpec) => ((deviceSpec === null || deviceSpec === void 0 ? void 0 : deviceSpec.applications) || []).map(toFormApps);
667
612
  exports.getApplicationValues = getApplicationValues;
668
613
  const getSystemdUnitsValues = (deviceSpec) => {
669
614
  var _a, _b;