@rancher/shell 0.1.2 → 0.1.3

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 (258) hide show
  1. package/assets/translations/en-us.yaml +27 -769
  2. package/assets/translations/zh-hans.yaml +8 -769
  3. package/components/ActionMenu.vue +3 -3
  4. package/components/CodeMirror.vue +6 -8
  5. package/components/CommunityLinks.vue +1 -1
  6. package/components/ContainerResourceLimit.vue +14 -0
  7. package/components/ExplorerMembers.vue +123 -0
  8. package/components/ExplorerProjectsNamespaces.vue +405 -0
  9. package/components/GrafanaDashboard.vue +17 -2
  10. package/components/LocaleSelector.vue +81 -0
  11. package/components/PromptModal.vue +2 -3
  12. package/components/ResourceList/index.vue +1 -1
  13. package/components/ResourceTable.vue +3 -6
  14. package/components/SingleClusterInfo.vue +1 -1
  15. package/components/SortableTable/index.vue +23 -20
  16. package/components/SortableTable/selection.js +1 -0
  17. package/components/auth/AzureWarning.vue +5 -1
  18. package/components/auth/Principal.vue +1 -1
  19. package/components/auth/RoleDetailEdit.vue +18 -11
  20. package/components/fleet/FleetRepos.vue +0 -2
  21. package/components/form/NameNsDescription.vue +4 -6
  22. package/components/form/NodeScheduling.vue +1 -1
  23. package/components/form/WorkloadPorts.vue +1 -1
  24. package/components/formatter/WorkloadHealthScale.vue +1 -1
  25. package/components/nav/Header.vue +9 -9
  26. package/components/nav/NamespaceFilter.vue +7 -4
  27. package/components/nav/TopLevelMenu.vue +6 -43
  28. package/components/nav/WindowManager/ContainerLogs.vue +1 -1
  29. package/config/product/harvester-manager.js +64 -2
  30. package/config/product/manager.js +9 -0
  31. package/config/settings.js +17 -71
  32. package/config/table-headers.js +0 -1
  33. package/config/types.js +5 -25
  34. package/core/plugin-routes.ts +34 -22
  35. package/core/plugin.ts +15 -3
  36. package/core/plugins-loader.js +2 -0
  37. package/core/plugins.js +79 -36
  38. package/core/types.ts +7 -1
  39. package/detail/provisioning.cattle.io.cluster.vue +13 -0
  40. package/detail/workload/index.vue +11 -5
  41. package/{components/dialog → dialog}/AddClusterMemberDialog.vue +0 -0
  42. package/{components/dialog → dialog}/AddCustomBadgeDialog.vue +0 -0
  43. package/{components/dialog → dialog}/AddProjectMemberDialog.vue +0 -0
  44. package/{components/dialog → dialog}/AddonConfigConfirmationDialog.vue +0 -0
  45. package/{components/dialog → dialog}/DrainNode.vue +0 -0
  46. package/{components/dialog → dialog}/ForceMachineRemoveDialog.vue +0 -0
  47. package/{components/dialog → dialog}/GenericPrompt.vue +0 -0
  48. package/{components/dialog → dialog}/RollbackWorkloadDialog.vue +0 -0
  49. package/{components/dialog → dialog}/RotateCertificatesDialog.vue +0 -0
  50. package/{components/dialog → dialog}/RotateEncryptionKeyDialog.vue +0 -0
  51. package/{components/dialog → dialog}/SaveAsRKETemplateDialog.vue +0 -0
  52. package/{components/dialog → dialog}/ScaleMachineDownDialog.vue +0 -0
  53. package/edit/auth/azuread.vue +20 -1
  54. package/edit/management.cattle.io.project.vue +2 -2
  55. package/edit/namespace.vue +17 -10
  56. package/edit/persistentvolumeclaim.vue +1 -0
  57. package/edit/provisioning.cattle.io.cluster/CustomCommand.vue +1 -1
  58. package/edit/provisioning.cattle.io.cluster/MachinePool.vue +33 -5
  59. package/edit/service.vue +1 -1
  60. package/edit/workload/index.vue +363 -15
  61. package/edit/workload/mixins/workload.js +62 -7
  62. package/edit/workload/storage/persistentVolumeClaim/persistentvolumeclaim.vue +1 -0
  63. package/layouts/default.vue +52 -27
  64. package/layouts/error.vue +5 -1
  65. package/layouts/home.vue +6 -2
  66. package/list/harvesterhci.io.management.cluster.vue +74 -33
  67. package/list/namespace.vue +3 -5
  68. package/machine-config/amazonec2.vue +2 -0
  69. package/machine-config/harvester.vue +96 -49
  70. package/middleware/authenticated.js +56 -52
  71. package/mixins/form-validation.js +1 -1
  72. package/mixins/resource-fetch.js +3 -1
  73. package/models/fleet.cattle.io.bundle.js +26 -19
  74. package/models/harvesterhci.io.management.cluster.js +194 -5
  75. package/models/management.cattle.io.cluster.js +1 -1
  76. package/models/management.cattle.io.clusterroletemplatebinding.js +9 -0
  77. package/models/management.cattle.io.project.js +23 -2
  78. package/models/namespace.js +19 -3
  79. package/models/pod.js +19 -2
  80. package/models/provisioning.cattle.io.cluster.js +4 -0
  81. package/models/workload.js +4 -243
  82. package/models/workload.service.js +314 -0
  83. package/nuxt.config.js +11 -9
  84. package/package.json +3 -3
  85. package/pages/auth/login.vue +11 -2
  86. package/pages/auth/setup.vue +1 -1
  87. package/pages/c/_cluster/_product/members/index.vue +3 -93
  88. package/pages/c/_cluster/_product/projectsnamespaces.vue +6 -403
  89. package/pages/c/_cluster/settings/performance.vue +19 -16
  90. package/pages/fail-whale.vue +1 -10
  91. package/pages/index.vue +18 -4
  92. package/pages/plugins.vue +2 -2
  93. package/pages/prefs.vue +8 -6
  94. package/pkg/auto-import.js +44 -7
  95. package/pkg/dynamic-plugin-loader.js +28 -0
  96. package/pkg/import.js +2 -2
  97. package/pkg/model-loader-require.lib.js +3 -0
  98. package/pkg/vue.config.js +9 -6
  99. package/plugins/dashboard-store/model-loader-require.js +12 -0
  100. package/plugins/dashboard-store/model-loader.js +4 -1
  101. package/plugins/dashboard-store/resource-class.js +10 -3
  102. package/plugins/steve/actions.js +1 -1
  103. package/plugins/steve/index.js +6 -4
  104. package/plugins/steve/subscribe.js +34 -23
  105. package/rancher-components/Form/Checkbox/Checkbox.test.ts +77 -0
  106. package/rancher-components/Form/Checkbox/Checkbox.vue +12 -2
  107. package/scripts/build-pkg.sh +48 -2
  108. package/scripts/drone-build-pkg.sh +31 -0
  109. package/scripts/publish-shell.sh +10 -11
  110. package/scripts/serve-pkgs +17 -10
  111. package/store/catalog.js +3 -1
  112. package/store/i18n.js +16 -11
  113. package/store/index.js +4 -181
  114. package/store/prefs.js +30 -2
  115. package/store/type-map.js +16 -29
  116. package/utils/cluster.js +1 -1
  117. package/utils/custom-validators.js +1 -12
  118. package/utils/dynamic-importer.js +1 -1
  119. package/utils/validators/setting.js +0 -35
  120. package/components/FilterLabel.vue +0 -254
  121. package/components/HarvesterUpgradeProgressBarList.vue +0 -109
  122. package/components/VMConsoleBar.vue +0 -87
  123. package/components/dialog/harvester/AddHotplugModal.vue +0 -159
  124. package/components/dialog/harvester/BackupModal.vue +0 -117
  125. package/components/dialog/harvester/CloneTemplate.vue +0 -125
  126. package/components/dialog/harvester/EjectCDROMDialog.vue +0 -157
  127. package/components/dialog/harvester/ExportImageDialog.vue +0 -152
  128. package/components/dialog/harvester/MaintenanceDialog.vue +0 -94
  129. package/components/dialog/harvester/MigrationDialog.vue +0 -154
  130. package/components/dialog/harvester/RestoreDialog.vue +0 -153
  131. package/components/dialog/harvester/SupportBundle.vue +0 -217
  132. package/components/dialog/harvester/UnplugVolume.vue +0 -108
  133. package/components/form/SerialConsole/index.vue +0 -267
  134. package/components/formatter/AttachVMWithName.vue +0 -46
  135. package/components/formatter/CloudInitType.vue +0 -27
  136. package/components/formatter/HarvesterBackupTargetValidation.vue +0 -43
  137. package/components/formatter/HarvesterCPUUsed.vue +0 -122
  138. package/components/formatter/HarvesterDiskState.vue +0 -66
  139. package/components/formatter/HarvesterHostName.vue +0 -66
  140. package/components/formatter/HarvesterIpAddress.vue +0 -90
  141. package/components/formatter/HarvesterMemoryUsed.vue +0 -140
  142. package/components/formatter/HarvesterMigrationState.vue +0 -85
  143. package/components/formatter/HarvesterNodeName.vue +0 -49
  144. package/components/formatter/HarvesterStorageUsed.vue +0 -194
  145. package/components/formatter/HarvesterVmState.vue +0 -123
  146. package/components/nav/HarvesterUpgrade.vue +0 -232
  147. package/components/novnc/NovncConsole.vue +0 -93
  148. package/components/novnc/NovncConsoleItem.vue +0 -89
  149. package/components/novnc/NovncConsoleWrapper.vue +0 -243
  150. package/config/harvester-map.js +0 -44
  151. package/config/harvester-table-headers.js +0 -27
  152. package/config/product/harvester.js +0 -305
  153. package/detail/harvesterhci.io.host/HarvesterHostBasic.vue +0 -364
  154. package/detail/harvesterhci.io.host/HarvesterHostDisk.vue +0 -200
  155. package/detail/harvesterhci.io.host/HarvesterHostNetwork.vue +0 -89
  156. package/detail/harvesterhci.io.host/VirtualMachineInstance.vue +0 -134
  157. package/detail/harvesterhci.io.host/index.vue +0 -243
  158. package/detail/harvesterhci.io.virtualmachinebackup/index.vue +0 -221
  159. package/detail/harvesterhci.io.virtualmachineimage.vue +0 -118
  160. package/detail/kubevirt.io.virtualmachine/VirtualMachineTabs/VirtualMachineBasics.vue +0 -279
  161. package/detail/kubevirt.io.virtualmachine/VirtualMachineTabs/VirtualMachineEvents.vue +0 -75
  162. package/detail/kubevirt.io.virtualmachine/VirtualMachineTabs/VirtualMachineKeypairs.vue +0 -114
  163. package/detail/kubevirt.io.virtualmachine/VirtualMachineTabs/VirtualMachineMigration.vue +0 -79
  164. package/detail/kubevirt.io.virtualmachine/index.vue +0 -213
  165. package/edit/harvesterhci.io.cloudtemplate.vue +0 -123
  166. package/edit/harvesterhci.io.host/HarvesterDisk.vue +0 -262
  167. package/edit/harvesterhci.io.host/index.vue +0 -533
  168. package/edit/harvesterhci.io.keypair.vue +0 -112
  169. package/edit/harvesterhci.io.managedchart/index.vue +0 -25
  170. package/edit/harvesterhci.io.managedchart/rancher-monitoring.vue +0 -172
  171. package/edit/harvesterhci.io.networkattachmentdefinition.vue +0 -210
  172. package/edit/harvesterhci.io.setting/additional-ca.vue +0 -36
  173. package/edit/harvesterhci.io.setting/backup-target.vue +0 -182
  174. package/edit/harvesterhci.io.setting/http-proxy.vue +0 -79
  175. package/edit/harvesterhci.io.setting/index.vue +0 -201
  176. package/edit/harvesterhci.io.setting/overcommit-config.vue +0 -94
  177. package/edit/harvesterhci.io.setting/ssl-certificates.vue +0 -117
  178. package/edit/harvesterhci.io.setting/ssl-parameters.vue +0 -161
  179. package/edit/harvesterhci.io.setting/support-bundle-image.vue +0 -134
  180. package/edit/harvesterhci.io.setting/support-bundle-namespaces.vue +0 -73
  181. package/edit/harvesterhci.io.setting/vip-pools.vue +0 -244
  182. package/edit/harvesterhci.io.setting/vm-force-reset-policy.vue +0 -81
  183. package/edit/harvesterhci.io.virtualmachinebackup.vue +0 -256
  184. package/edit/harvesterhci.io.virtualmachineimage.vue +0 -364
  185. package/edit/harvesterhci.io.virtualmachinetemplateversion.vue +0 -340
  186. package/edit/harvesterhci.io.volume.vue +0 -195
  187. package/edit/kubevirt.io.virtualmachine/VirtualMachineAccessCredentials/AccessCredentialsUsers.vue +0 -190
  188. package/edit/kubevirt.io.virtualmachine/VirtualMachineAccessCredentials/index.vue +0 -212
  189. package/edit/kubevirt.io.virtualmachine/VirtualMachineAccessCredentials/type/basicAuth.vue +0 -94
  190. package/edit/kubevirt.io.virtualmachine/VirtualMachineAccessCredentials/type/sshkey.vue +0 -85
  191. package/edit/kubevirt.io.virtualmachine/VirtualMachineCloudConfig/DataTemplate.vue +0 -153
  192. package/edit/kubevirt.io.virtualmachine/VirtualMachineCloudConfig/index.vue +0 -279
  193. package/edit/kubevirt.io.virtualmachine/VirtualMachineCpuMemory.vue +0 -113
  194. package/edit/kubevirt.io.virtualmachine/VirtualMachineNetwork/__tests__/HarvesterEditNetwork.test.ts +0 -41
  195. package/edit/kubevirt.io.virtualmachine/VirtualMachineNetwork/base.vue +0 -281
  196. package/edit/kubevirt.io.virtualmachine/VirtualMachineNetwork/index.vue +0 -142
  197. package/edit/kubevirt.io.virtualmachine/VirtualMachineReserved.vue +0 -54
  198. package/edit/kubevirt.io.virtualmachine/VirtualMachineSSHKey.vue +0 -256
  199. package/edit/kubevirt.io.virtualmachine/VirtualMachineVolume/index.vue +0 -391
  200. package/edit/kubevirt.io.virtualmachine/VirtualMachineVolume/type/__tests__/HarvesterEditContainer.test.ts +0 -40
  201. package/edit/kubevirt.io.virtualmachine/VirtualMachineVolume/type/__tests__/HarvesterEditExisting.test.ts +0 -102
  202. package/edit/kubevirt.io.virtualmachine/VirtualMachineVolume/type/__tests__/HarvesterEditVMImage.test.ts +0 -117
  203. package/edit/kubevirt.io.virtualmachine/VirtualMachineVolume/type/__tests__/HarvesterEditVolume.test.ts +0 -74
  204. package/edit/kubevirt.io.virtualmachine/VirtualMachineVolume/type/container.vue +0 -132
  205. package/edit/kubevirt.io.virtualmachine/VirtualMachineVolume/type/existing.vue +0 -303
  206. package/edit/kubevirt.io.virtualmachine/VirtualMachineVolume/type/vmImage.vue +0 -285
  207. package/edit/kubevirt.io.virtualmachine/VirtualMachineVolume/type/volume.vue +0 -188
  208. package/edit/kubevirt.io.virtualmachine/index.vue +0 -642
  209. package/edit/network.harvesterhci.io.clusternetwork/index.vue +0 -19
  210. package/edit/network.harvesterhci.io.clusternetwork/vlan.vue +0 -134
  211. package/edit/workload/types/Deployment.vue +0 -377
  212. package/edit/workload/types/Generic.vue +0 -295
  213. package/list/harvesterhci.io.cloudtemplate.vue +0 -78
  214. package/list/harvesterhci.io.dashboard/HarvesterUpgrade.vue +0 -211
  215. package/list/harvesterhci.io.dashboard/UpgradeInfo.vue +0 -40
  216. package/list/harvesterhci.io.dashboard/index.vue +0 -752
  217. package/list/harvesterhci.io.host/index.vue +0 -186
  218. package/list/harvesterhci.io.networkattachmentdefinition.vue +0 -167
  219. package/list/harvesterhci.io.setting.vue +0 -241
  220. package/list/harvesterhci.io.virtualmachinebackup.vue +0 -172
  221. package/list/harvesterhci.io.virtualmachineimage.vue +0 -80
  222. package/list/harvesterhci.io.virtualmachinetemplateversion.vue +0 -173
  223. package/list/harvesterhci.io.volume.vue +0 -122
  224. package/list/kubevirt.io.virtualmachine.vue +0 -193
  225. package/mixins/harvester-vm/impl.js +0 -267
  226. package/mixins/harvester-vm/index.js +0 -1357
  227. package/models/harvester/configmap.js +0 -32
  228. package/models/harvester/harvesterhci.io.blockdevice.js +0 -55
  229. package/models/harvester/harvesterhci.io.keypair.js +0 -12
  230. package/models/harvester/harvesterhci.io.setting.js +0 -127
  231. package/models/harvester/harvesterhci.io.supportbundle.js +0 -35
  232. package/models/harvester/harvesterhci.io.upgrade.js +0 -226
  233. package/models/harvester/harvesterhci.io.virtualmachinebackup.js +0 -116
  234. package/models/harvester/harvesterhci.io.virtualmachineimage.js +0 -255
  235. package/models/harvester/harvesterhci.io.virtualmachinerestore.js +0 -43
  236. package/models/harvester/harvesterhci.io.virtualmachinetemplate.js +0 -69
  237. package/models/harvester/harvesterhci.io.virtualmachinetemplateversion.js +0 -227
  238. package/models/harvester/k8s.cni.cncf.io.networkattachmentdefinition.js +0 -32
  239. package/models/harvester/kubevirt.io.virtualmachine.js +0 -850
  240. package/models/harvester/kubevirt.io.virtualmachineinstance.js +0 -142
  241. package/models/harvester/management.cattle.io.managedchart.js +0 -191
  242. package/models/harvester/management.cattle.io.setting.js +0 -40
  243. package/models/harvester/network.harvesterhci.io.clusternetwork.js +0 -100
  244. package/models/harvester/network.harvesterhci.io.nodenetwork.js +0 -34
  245. package/models/harvester/node.js +0 -255
  246. package/models/harvester/persistentvolumeclaim.js +0 -166
  247. package/models/harvester/pod.js +0 -185
  248. package/pages/c/_cluster/harvester/airgapupgrade/index.vue +0 -309
  249. package/pages/c/_cluster/harvester/console/_uid/serial.vue +0 -51
  250. package/pages/c/_cluster/harvester/console/_uid/vnc.vue +0 -52
  251. package/pages/c/_cluster/harvester/index.vue +0 -24
  252. package/pages/c/_cluster/harvester/support/index.vue +0 -154
  253. package/pkg/model-loader.lib.js +0 -3
  254. package/promptRemove/kubevirt.io.virtualmachine.vue +0 -164
  255. package/store/harvester-common.js +0 -126
  256. package/utils/validators/vm-datavolumes.js +0 -38
  257. package/utils/validators/vm-image.js +0 -32
  258. package/utils/validators/vm.js +0 -221
@@ -1,16 +1,12 @@
1
1
  <script>
2
- import WorkloadGeneric from './types/Generic';
3
- import WorkloadDeployment from './types/Deployment';
4
-
2
+ import CreateEditView from '@shell/mixins/create-edit-view';
3
+ import FormValidation from '@shell/mixins/form-validation';
5
4
  import WorkLoadMixin from '@shell/edit/workload/mixins/workload';
6
5
 
7
6
  export default {
8
- name: 'CruWorkload',
9
- components: {
10
- WorkloadGeneric,
11
- WorkloadDeployment
12
- },
13
- props: {
7
+ name: 'WorkloadDeployments',
8
+ mixins: [CreateEditView, FormValidation, WorkLoadMixin], // The order here is important since WorkLoadMixin contains some FormValidation configuration
9
+ props: {
14
10
  value: {
15
11
  type: Object,
16
12
  required: true,
@@ -21,14 +17,366 @@ export default {
21
17
  default: 'create',
22
18
  },
23
19
  },
24
- mixins: [WorkLoadMixin],
20
+ data() {
21
+ return { selectedName: null };
22
+ },
23
+ methods: {
24
+ changed(tab) {
25
+ this.selectedName = tab.selectedName;
26
+ const container = this.containerOptions.find( c => c.name === tab.selectedName);
27
+
28
+ if ( container ) {
29
+ this.selectContainer(container);
30
+ }
31
+ }
32
+ }
25
33
  };
26
34
  </script>
27
35
 
28
36
  <template>
29
- <div>
30
- <Loading v-if="$fetchState.pending" />
31
- <WorkloadDeployment v-else-if="isDeployment" :mode="mode" :value="value" />
32
- <WorkloadGeneric v-else :mode="mode" :value="value" />
33
- </div>
37
+ <Loading v-if="$fetchState.pending" />
38
+ <form v-else class="filled-height">
39
+ <CruResource
40
+ :validation-passed="fvFormIsValid"
41
+ :selected-subtype="type"
42
+ :resource="value"
43
+ :mode="mode"
44
+ :errors="fvUnreportedValidationErrors"
45
+ :done-route="doneRoute"
46
+ :subtypes="workloadSubTypes"
47
+ :apply-hooks="applyHooks"
48
+ :value="value"
49
+ @finish="save"
50
+ @select-type="selectType"
51
+ @error="e=>errors = e"
52
+ >
53
+ <!-- <pre>{{ JSON.stringify(allContainers, null, 2) }}</pre> -->
54
+ <NameNsDescription
55
+ :value="value"
56
+ :mode="mode"
57
+ :rules="{name: fvGetAndReportPathRules('metadata.name'), namespace: fvGetAndReportPathRules('metadata.namespace'), description: []}"
58
+ @change="name=value.metadata.name"
59
+ />
60
+ <div v-if="isCronJob || isReplicable || isStatefulSet || containerOptions.length > 1" class="row mb-20">
61
+ <div v-if="isCronJob" class="col span-3">
62
+ <LabeledInput
63
+ v-model="spec.schedule"
64
+ type="cron"
65
+ required
66
+ :mode="mode"
67
+ :label="t('workload.cronSchedule')"
68
+ :rules="fvGetAndReportPathRules('spec.schedule')"
69
+ placeholder="0 * * * *"
70
+ />
71
+ </div>
72
+ <div v-if="isReplicable" class="col span-3">
73
+ <LabeledInput
74
+ v-model.number="spec.replicas"
75
+ type="number"
76
+ min="0"
77
+ required
78
+ :mode="mode"
79
+ :label="t('workload.replicas')"
80
+ />
81
+ </div>
82
+ <div v-if="isStatefulSet" class="col span-3">
83
+ <LabeledSelect
84
+ v-model="spec.serviceName"
85
+ option-label="metadata.name"
86
+ :reduce="service=>service.metadata.name"
87
+ :mode="mode"
88
+ :label="t('workload.serviceName')"
89
+ :options="headlessServices"
90
+ required
91
+ />
92
+ </div>
93
+ </div>
94
+ <Tabbed class="deployment-tabs" :show-tabs-add-remove="true" :default-tab="defaultTab" @changed="changed">
95
+ <Tab
96
+ v-for="(tab, i) in allContainers"
97
+ :key="i+tab.name"
98
+ :label="tab.name"
99
+ :name="tab.name"
100
+ :weight="tab.weight"
101
+ :error="!!tab.error"
102
+ >
103
+ <Tabbed :side-tabs="true" :weight="99">
104
+ <Tab :label="t('workload.container.titles.general')" name="general" :weight="tabWeightMap['general']" :error="tabErrors.general">
105
+ <template #tab-header-right class="tab-content-controls">
106
+ <button v-if="allContainers.length > 1 && !isView" type="button" class="btn-sm role-link" @click="removeContainer(tab)">
107
+ {{ t('workload.container.removeContainer') }}
108
+ </button>
109
+ </template>
110
+ <div>
111
+ <div :style="{'align-items':'center'}" class="row mb-20">
112
+ <div class="col span-6">
113
+ <LabeledInput v-model="container.name" :mode="mode" :label="t('workload.container.containerName')" />
114
+ </div>
115
+ <div class="col span-6">
116
+ <RadioGroup
117
+ :mode="mode"
118
+ :value="isInitContainer"
119
+ name="initContainer"
120
+ :options="[true, false]"
121
+ :labels="[t('workload.container.init'), t('workload.container.standard')]"
122
+ @input="updateInitContainer"
123
+ />
124
+ </div>
125
+ </div>
126
+ <h3>{{ t('workload.container.titles.image') }}</h3>
127
+ <div class="row mb-20">
128
+ <div class="col span-6">
129
+ <LabeledInput
130
+ v-model.trim="container.image"
131
+ :mode="mode"
132
+ :label="t('workload.container.image')"
133
+ :placeholder="t('generic.placeholder', {text: 'nginx:latest'}, true)"
134
+ :rules="fvGetAndReportPathRules('image')"
135
+ />
136
+ </div>
137
+ <div class="col span-6">
138
+ <LabeledSelect
139
+ v-model="container.imagePullPolicy"
140
+ :label="t('workload.container.imagePullPolicy')"
141
+ :options="pullPolicyOptions"
142
+ :mode="mode"
143
+ />
144
+ </div>
145
+ </div>
146
+ <div class="row">
147
+ <div class="col span-6">
148
+ <LabeledSelect
149
+ v-model="imagePullSecrets"
150
+ :label="t('workload.container.imagePullSecrets')"
151
+ :multiple="true"
152
+ :taggable="true"
153
+ :options="imagePullNamespacedSecrets"
154
+ :mode="mode"
155
+ option-label="metadata.name"
156
+ :reduce="service=>service.metadata.name"
157
+ :create-option="createOption"
158
+ />
159
+ </div>
160
+ </div>
161
+ </div>
162
+ <div class="spacer" />
163
+ <div>
164
+ <h3>{{ t('workload.container.titles.ports') }}</h3>
165
+ <div class="row">
166
+ <WorkloadPorts v-model="allContainers[i].ports" :name="value.metadata.name" :services="servicesOwned" :mode="mode" />
167
+ </div>
168
+ </div>
169
+ <div class="spacer" />
170
+ <div>
171
+ <h3>{{ t('workload.container.titles.command') }}</h3>
172
+ <Command v-model="allContainers[i]" :secrets="namespacedSecrets" :config-maps="namespacedConfigMaps" :mode="mode" />
173
+ </div>
174
+ <ServiceNameSelect
175
+ :value="podTemplateSpec.serviceAccountName"
176
+ :mode="mode"
177
+ :select-label="t('workload.serviceAccountName.label')"
178
+ :select-placeholder="t('workload.serviceAccountName.label')"
179
+ :options="namespacedServiceNames"
180
+ option-label="metadata.name"
181
+ @input="updateServiceAccount"
182
+ />
183
+ <div class="spacer" />
184
+ <div>
185
+ <h3>{{ t('workload.container.titles.lifecycle') }}</h3>
186
+ <LifecycleHooks v-model="allContainers[i].lifecycle" :mode="mode" />
187
+ </div>
188
+ </Tab>
189
+ <Tab :label="t('workload.container.titles.resources')" name="resources" :weight="tabWeightMap['resources']">
190
+ <!-- Resources and Limitations -->
191
+ <ContainerResourceLimit v-model="flatResources" :mode="mode" :show-tip="false" />
192
+ </Tab>
193
+
194
+ <Tab v-if="!isInitContainer" :label="t('workload.container.titles.healthCheck')" name="healthCheck" :weight="tabWeightMap['healthCheck']">
195
+ <HealthCheck :value="allContainers[i]" :mode="mode" @input="Object.assign(allContainers[i], $event)" />
196
+ </Tab>
197
+ <Tab :label="t('workload.container.titles.securityContext')" name="securityContext" :weight="tabWeightMap['securityContext']">
198
+ <Security v-model="allContainers[i].securityContext" :mode="mode" />
199
+ </Tab>
200
+ </Tabbed>
201
+ </Tab>
202
+ <Tab v-if="!isPod" :label="nameDisplayFor(type)" :name="nameDisplayFor(type)" :weight="99">
203
+ <Tabbed :side-tabs="true">
204
+ <Tab name="labels" label-key="generic.labelsAndAnnotations" :weight="tabWeightMap['labels']">
205
+ <Labels v-model="value" :mode="mode" />
206
+ </Tab>
207
+ <Tab :label="t('workload.container.titles.upgrading')" name="upgrading" :weight="tabWeightMap['upgrading']">
208
+ <Job v-if="isJob || isCronJob" v-model="spec" :mode="mode" :type="type" />
209
+ <Upgrading v-else v-model="spec" :mode="mode" :type="type" :no-pod-spec="true" />
210
+ </Tab>
211
+ </Tabbed>
212
+ </Tab>
213
+ <Tab :label="t('workload.tabs.labels.pod')" :name="'pod'" :weight="98">
214
+ <Tabbed :side-tabs="true">
215
+ <Tab :label="t('workload.storage.title')" name="storage" :weight="tabWeightMap['storage']">
216
+ <Storage
217
+ v-model="podTemplateSpec"
218
+ :namespace="value.metadata.namespace"
219
+ :register-before-hook="registerBeforeHook"
220
+ :mode="mode"
221
+ :secrets="namespacedSecrets"
222
+ :config-maps="namespacedConfigMaps"
223
+ :container="container"
224
+ :save-pvc-hook-name="savePvcHookName"
225
+ @removePvcForm="clearPvcFormState"
226
+ />
227
+ </Tab>
228
+ <Tab :label="t('workload.container.titles.resources')" name="resources" :weight="tabWeightMap['resources']">
229
+ <template>
230
+ <div>
231
+ <h3 class="mb-10">
232
+ <t k="workload.scheduling.titles.tolerations" />
233
+ </h3>
234
+ <div class="row">
235
+ <Tolerations v-model="podTemplateSpec.tolerations" :mode="mode" />
236
+ </div>
237
+ </div>
238
+
239
+ <div>
240
+ <div class="spacer" />
241
+ <h3 class="mb-10">
242
+ <t k="workload.scheduling.titles.priority" />
243
+ </h3>
244
+ <div class="row">
245
+ <div class="col span-6">
246
+ <LabeledInput v-model.number="podTemplateSpec.priority" :mode="mode" :label="t('workload.scheduling.priority.priority')" />
247
+ </div>
248
+ <div class="col span-6">
249
+ <LabeledInput v-model="podTemplateSpec.priorityClassName" :mode="mode" :label="t('workload.scheduling.priority.className')" />
250
+ </div>
251
+ </div>
252
+ </div>
253
+ </template>
254
+ </Tab>
255
+ <Tab :label="t('workload.container.titles.podScheduling')" name="podScheduling" :weight="tabWeightMap['podScheduling']">
256
+ <PodAffinity :mode="mode" :value="podTemplateSpec" :nodes="allNodeObjects" />
257
+ </Tab>
258
+ <Tab :label="t('workload.container.titles.nodeScheduling')" name="nodeScheduling" :weight="tabWeightMap['nodeScheduling']">
259
+ <NodeScheduling :mode="mode" :value="podTemplateSpec" :nodes="allNodes" />
260
+ </Tab>
261
+ <Tab :label="t('workload.container.titles.upgrading')" name="upgrading" :weight="tabWeightMap['upgrading']">
262
+ <Job v-if="isJob || isCronJob" v-model="spec" :mode="mode" :type="type" />
263
+ <Upgrading v-else v-model="spec" :mode="mode" :type="type" :no-deployment-spec="true" />
264
+ </Tab>
265
+ <Tab :label="t('workload.container.titles.securityContext')" name="securityContext" :weight="tabWeightMap['securityContext']">
266
+ <div>
267
+ <h3>{{ t('workload.container.security.podFsGroup') }}</h3>
268
+ <div class="row">
269
+ <div class="col span-6">
270
+ <LabeledInput v-model.number="podFsGroup" type="number" :mode="mode" :label="t('workload.container.security.fsGroup')" />
271
+ </div>
272
+ </div>
273
+ </div>
274
+ </Tab>
275
+ <Tab :label="t('workload.container.titles.networking')" name="networking" :weight="tabWeightMap['networking']">
276
+ <Networking v-model="podTemplateSpec" :mode="mode" />
277
+ </Tab>
278
+ <Tab v-if="isStatefulSet" :label="t('workload.container.titles.volumeClaimTemplates')" name="volumeClaimTemplates" :weight="tabWeightMap['volumeClaimTemplates']">
279
+ <VolumeClaimTemplate v-model="spec" :mode="mode" />
280
+ </Tab>
281
+ <Tab name="labels" label-key="generic.labelsAndAnnotations" :weight="tabWeightMap['labels']">
282
+ <div>
283
+ <h3>{{ t('workload.container.titles.podLabels') }}</h3>
284
+ <div class="row mb-20">
285
+ <KeyValue
286
+ key="labels"
287
+ v-model="podLabels"
288
+ :add-label="t('labels.addLabel')"
289
+ :mode="mode"
290
+ :read-allowed="false"
291
+ :protip="false"
292
+ />
293
+ </div>
294
+ <div class="spacer" />
295
+ <h3>{{ t('workload.container.titles.podAnnotations') }}</h3>
296
+ <div class="row">
297
+ <KeyValue
298
+ key="annotations"
299
+ v-model="podAnnotations"
300
+ :add-label="t('labels.addAnnotation')"
301
+ :mode="mode"
302
+ :read-allowed="false"
303
+ :protip="false"
304
+ />
305
+ </div>
306
+ </div>
307
+ </Tab>
308
+ </Tabbed>
309
+ </Tab>
310
+ <template #tab-row-extras>
311
+ <li class="tablist-controls">
312
+ <button v-if="!isView" type="button" class="btn-sm role-link" @click="addContainerBtn">
313
+ <i class="icon icon-plus icon-lg" /> {{ t('workload.container.addContainer') }}
314
+ </button>
315
+ </li>
316
+ </template>
317
+ </Tabbed>
318
+ </CruResource>
319
+ </form>
34
320
  </template>
321
+
322
+ <style lang='scss'>
323
+ .container-row {
324
+ display: flex;
325
+ align-items: center;
326
+ margin-bottom: 20px;
327
+ }
328
+
329
+ .type-placeholder {
330
+ color: white;
331
+ font-size: 2.5em;
332
+ height: 100%;
333
+ width: 100%;
334
+ background-color: var(--primary);
335
+ display: flex;
336
+ justify-content: center;
337
+ align-items: center;
338
+ }
339
+
340
+ .type-description {
341
+ color: var(--input-label);
342
+ }
343
+
344
+ .next-dropdown {
345
+ display: inline-block;
346
+ }
347
+
348
+ .tab-external-controls {
349
+ display: flex;
350
+ justify-content: right;
351
+ }
352
+
353
+ .tab-content-controls {
354
+ display: flex;
355
+ justify-content: right;
356
+ }
357
+
358
+ .tablist-controls {
359
+ .role-link {
360
+ padding: 10px 15px;
361
+ min-height: unset;
362
+ line-height: unset;
363
+
364
+ &:focus {
365
+ background: none;
366
+ box-shadow: none;
367
+ }
368
+
369
+ &:hover {
370
+ border: none;
371
+ }
372
+ }
373
+
374
+ }
375
+
376
+ .deployment-tabs {
377
+ > .tabs.horizontal {
378
+ border-bottom: 1px solid var(--border);
379
+ margin-bottom: 10px;
380
+ }
381
+ }
382
+ </style>
@@ -43,6 +43,7 @@ import { removeObject } from '@shell/utils/array';
43
43
  import { BEFORE_SAVE_HOOKS } from '@shell/mixins/child-hook';
44
44
  import NameNsDescription from '@shell/components/form/NameNsDescription';
45
45
  import formRulesGenerator from '@shell/utils/validators/formRules';
46
+ import { TYPES as SECRET_TYPES } from '@shell/models/secret';
46
47
 
47
48
  const TAB_WEIGHT_MAP = {
48
49
  general: 99,
@@ -102,6 +103,15 @@ export default {
102
103
  type: String,
103
104
  default: 'create',
104
105
  },
106
+
107
+ createOption: {
108
+ default: (text) => {
109
+ if (text) {
110
+ return { metadata: { name: text } };
111
+ }
112
+ },
113
+ type: Function
114
+ },
105
115
  },
106
116
 
107
117
  async fetch() {
@@ -138,6 +148,7 @@ export default {
138
148
  },
139
149
 
140
150
  data() {
151
+ let defaultTab;
141
152
  let type = this.$route.params.resource;
142
153
  const createSidecar = !!this.$route.query.sidecar;
143
154
  const isInitContainer = !!this.$route.query.init;
@@ -148,21 +159,48 @@ export default {
148
159
 
149
160
  if (!this.value.spec) {
150
161
  this.value.spec = {};
162
+ if (this.value.type === WORKLOAD_TYPES.POD) {
163
+ const podContainers = [{
164
+ imagePullPolicy: 'Always',
165
+ name: `container-0`,
166
+ }];
167
+
168
+ defaultTab = 'container-0';
169
+
170
+ const podSpec = { template: { spec: { containers: podContainers, initContainers: [] } } };
171
+
172
+ this.$set(this.value, 'spec', podSpec);
173
+ }
174
+ }
175
+
176
+ if (this.mode === _CREATE) {
177
+ defaultTab = 'container-0';
178
+ }
179
+
180
+ if ((this.mode === _EDIT || this.mode === _VIEW ) && this.value.type === 'pod' ) {
181
+ const podSpec = { ...this.value.spec };
182
+
183
+ this.$set(this.value.spec, 'template', { spec: podSpec });
151
184
  }
152
185
 
153
186
  const spec = this.value.spec;
187
+ let podTemplateSpec = type === WORKLOAD_TYPES.CRON_JOB ? spec.jobTemplate.spec.template.spec : spec?.template?.spec;
188
+
189
+ let containers = podTemplateSpec.containers || [];
154
190
  let container;
155
- const podTemplateSpec =
156
- type === WORKLOAD_TYPES.CRON_JOB ? spec.jobTemplate.spec.template.spec : spec?.template?.spec;
157
- let containers = podTemplateSpec.containers;
191
+
192
+ if (this.mode === _VIEW && this.value.type === 'pod' ) {
193
+ podTemplateSpec = spec;
194
+ }
158
195
 
159
196
  if (
160
197
  this.mode === _CREATE ||
161
198
  this.mode === _VIEW ||
162
- (!createSidecar && !this.value.hasSidecars)
199
+ (!createSidecar && !this.value.hasSidecars) // hasSideCars = containers.length > 1 || initContainers.length;
163
200
  ) {
164
201
  container = containers[0];
165
202
  } else {
203
+ // This means that there are no containers.
166
204
  if (!podTemplateSpec.initContainers) {
167
205
  podTemplateSpec.initContainers = [];
168
206
  }
@@ -176,13 +214,18 @@ export default {
176
214
  imagePullPolicy: 'Always',
177
215
  name: `container-${ allContainers.length }`,
178
216
  });
217
+ defaultTab = 'container-0';
218
+
179
219
  containers = podTemplateSpec.initContainers;
180
220
  }
181
- if (createSidecar) {
221
+ if (createSidecar || this.value.type === 'pod') {
182
222
  container = {
183
223
  imagePullPolicy: 'Always',
184
224
  name: `container-${ allContainers.length }`,
185
225
  };
226
+
227
+ defaultTab = 'container-0';
228
+
186
229
  containers.push(container);
187
230
  } else {
188
231
  container = containers[0];
@@ -217,7 +260,9 @@ export default {
217
260
  fvFormRuleSets: [{
218
261
  path: 'image', rootObject: this.container, rules: ['required'], translationKey: 'workload.container.image'
219
262
  }],
220
- fvReportedValidationPaths: ['spec']
263
+ fvReportedValidationPaths: ['spec'],
264
+ defaultTab
265
+
221
266
  };
222
267
  },
223
268
 
@@ -251,6 +296,10 @@ export default {
251
296
  return this.type === WORKLOAD_TYPES.DEPLOYMENT;
252
297
  },
253
298
 
299
+ isPod() {
300
+ return this.value.type === WORKLOAD_TYPES.POD;
301
+ },
302
+
254
303
  isStatefulSet() {
255
304
  return this.type === WORKLOAD_TYPES.STATEFUL_SET;
256
305
  },
@@ -430,6 +479,12 @@ export default {
430
479
  }
431
480
  },
432
481
 
482
+ imagePullNamespacedSecrets() {
483
+ const namespace = this.value?.metadata?.namespace;
484
+
485
+ return this.allSecrets.filter(secret => secret.metadata.namespace === namespace && (secret._type === SECRET_TYPES.DOCKER || secret._type === SECRET_TYPES.DOCKER_JSON));
486
+ },
487
+
433
488
  namespacedConfigMaps() {
434
489
  const namespace = this.value?.metadata?.namespace;
435
490
 
@@ -882,7 +937,7 @@ export default {
882
937
  }
883
938
  },
884
939
  nvidiaIsValid(nvidiaGpuLimit) {
885
- if (!Number.isInteger(nvidiaGpuLimit)) {
940
+ if ( !Number.isInteger(parseInt(nvidiaGpuLimit)) ) {
886
941
  return false;
887
942
  }
888
943
  if (nvidiaGpuLimit === undefined) {
@@ -209,6 +209,7 @@ export default {
209
209
  :label="t('persistentVolumeClaim.capacity')"
210
210
  :increment="1024"
211
211
  :input-exponent="3"
212
+ :required="true"
212
213
  :output-modifier="true"
213
214
  />
214
215
  </div>