@rancher/shell 0.3.3 → 0.3.5

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 (249) hide show
  1. package/assets/styles/app.scss +1 -1
  2. package/assets/styles/fonts/_fontstack.scss +11 -11
  3. package/assets/styles/vendor/vue-js-modal.scss +3 -3
  4. package/assets/translations/en-us.yaml +92 -22
  5. package/assets/translations/zh-hans.yaml +84 -15
  6. package/babel.config.js +13 -0
  7. package/chart/gatekeeper.vue +77 -0
  8. package/chart/istio.vue +108 -111
  9. package/chart/logging/index.vue +13 -4
  10. package/chart/monitoring/index.vue +15 -5
  11. package/chart/monitoring/steps/uninstall-v1.vue +2 -2
  12. package/chart/rancher-backup/index.vue +10 -3
  13. package/cloud-credential/aws.vue +1 -1
  14. package/cloud-credential/digitalocean.vue +1 -1
  15. package/cloud-credential/gcp.vue +1 -1
  16. package/cloud-credential/generic.vue +2 -2
  17. package/cloud-credential/linode.vue +1 -1
  18. package/cloud-credential/pnap.vue +1 -1
  19. package/components/ActionMenu.vue +3 -4
  20. package/components/AssignTo.vue +1 -1
  21. package/components/AsyncButton.vue +1 -1
  22. package/components/BannerGraphic.vue +1 -1
  23. package/components/ButtonDropdown.vue +2 -3
  24. package/components/ChartPsp.vue +76 -0
  25. package/components/CruResource.vue +6 -2
  26. package/components/DashboardMetrics.vue +12 -10
  27. package/components/DetailText.vue +1 -1
  28. package/components/DisableAuthProviderModal.vue +1 -1
  29. package/components/EmberPage.vue +1 -1
  30. package/components/EtcdInfoBanner.vue +5 -4
  31. package/components/ExplorerMembers.vue +1 -1
  32. package/components/ExplorerProjectsNamespaces.vue +15 -2
  33. package/components/FileDiff.vue +6 -7
  34. package/components/GrafanaDashboard.vue +18 -21
  35. package/components/LazyImage.vue +10 -12
  36. package/components/LogItem.vue +1 -1
  37. package/components/Markdown.vue +1 -1
  38. package/components/PromptRemove.vue +2 -2
  39. package/components/PromptRestore.vue +1 -1
  40. package/components/ResourceDetail/Masthead.vue +16 -0
  41. package/components/ResourceDetail/index.vue +21 -4
  42. package/components/ResourceList/index.vue +1 -1
  43. package/components/ResourceTable.vue +4 -1
  44. package/components/SingleClusterInfo.vue +2 -2
  45. package/components/SortableTable/THead.vue +1 -1
  46. package/components/SortableTable/index.vue +5 -2
  47. package/components/__tests__/AsyncButton.test.ts +3 -1
  48. package/components/__tests__/ChartPsp.test.ts +75 -0
  49. package/components/__tests__/CruResource.test.ts +3 -1
  50. package/components/auth/Principal.vue +1 -1
  51. package/components/fleet/FleetBundles.vue +3 -1
  52. package/components/fleet/FleetClusters.vue +1 -2
  53. package/components/fleet/FleetIntro.vue +9 -1
  54. package/components/fleet/FleetNoWorkspaces.vue +62 -0
  55. package/components/fleet/FleetSummary.vue +7 -1
  56. package/components/form/LabeledSelect.vue +14 -11
  57. package/components/form/MatchExpressions.vue +17 -2
  58. package/components/form/NameNsDescription.vue +31 -45
  59. package/components/form/ResourceSelector.vue +1 -1
  60. package/components/form/SecretSelector.vue +5 -1
  61. package/components/form/ServiceNameSelect.vue +1 -1
  62. package/components/form/SimpleSecretSelector.vue +9 -9
  63. package/components/form/__tests__/LabeledSelect.test.ts +138 -0
  64. package/components/form/__tests__/NameNsDescription.ts +32 -0
  65. package/components/formatter/InternalExternalIP.vue +6 -0
  66. package/components/formatter/InvolvedObjectLink.vue +54 -0
  67. package/components/formatter/Link.vue +20 -4
  68. package/components/formatter/LinkName.vue +6 -1
  69. package/components/formatter/ServiceTargets.vue +1 -1
  70. package/components/nav/Group.vue +2 -2
  71. package/components/nav/NamespaceFilter.vue +15 -11
  72. package/components/nav/TopLevelMenu.vue +2 -4
  73. package/components/nav/Type.vue +1 -1
  74. package/components/nav/WorkspaceSwitcher.vue +46 -5
  75. package/config/labels-annotations.js +17 -0
  76. package/config/product/auth.js +3 -2
  77. package/config/product/explorer.js +11 -4
  78. package/config/product/fleet.js +2 -0
  79. package/config/router.js +414 -0
  80. package/config/table-headers.js +10 -2
  81. package/config/types.js +11 -8
  82. package/config/uiplugins.js +30 -0
  83. package/content/docs/en-us/whats-new.md +10 -0
  84. package/content/docs/zh-hans/whats-new.md +11 -1
  85. package/core/plugin-helpers.js +64 -61
  86. package/core/plugin-routes.ts +23 -0
  87. package/creators/app/app.package.json +2 -1
  88. package/creators/app/files/.eslintrc.js +1 -1
  89. package/creators/app/files/babel.config.js +1 -18
  90. package/creators/app/files/vue.config.js +7 -0
  91. package/creators/app/init +5 -5
  92. package/creators/pkg/files/.github/workflows/build-extension.yml +111 -0
  93. package/creators/pkg/init +35 -4
  94. package/creators/update/init +1 -1
  95. package/detail/constraints.gatekeeper.sh.constraint.vue +20 -10
  96. package/detail/fleet.cattle.io.gitrepo.vue +19 -11
  97. package/detail/harvesterhci.io.management.cluster.vue +3 -3
  98. package/detail/provisioning.cattle.io.cluster.vue +54 -12
  99. package/detail/workload/index.vue +3 -3
  100. package/dialog/AddClusterMemberDialog.vue +1 -1
  101. package/dialog/AddProjectMemberDialog.vue +2 -2
  102. package/dialog/AddonConfigConfirmationDialog.vue +27 -15
  103. package/dialog/DiagnosticTimingsDialog.vue +1 -1
  104. package/dialog/ForceMachineRemoveDialog.vue +1 -1
  105. package/dialog/GenericPrompt.vue +18 -6
  106. package/dialog/RotateEncryptionKeyDialog.vue +1 -1
  107. package/dialog/SaveAsRKETemplateDialog.vue +1 -1
  108. package/dialog/ScaleMachineDownDialog.vue +1 -1
  109. package/edit/auth/github.vue +8 -8
  110. package/edit/auth/googleoauth.vue +5 -5
  111. package/edit/auth/ldap/index.vue +1 -1
  112. package/edit/auth/oidc.vue +1 -1
  113. package/edit/auth/saml.vue +1 -1
  114. package/edit/cis.cattle.io.clusterscan.vue +1 -1
  115. package/edit/fleet.cattle.io.clustergroup.vue +6 -4
  116. package/edit/fleet.cattle.io.gitrepo.vue +16 -3
  117. package/edit/helm.cattle.io.projecthelmchart.vue +5 -1
  118. package/edit/management.cattle.io.fleetworkspace.vue +141 -6
  119. package/edit/management.cattle.io.podsecurityadmissionconfigurationtemplate.vue +4 -1
  120. package/edit/management.cattle.io.setting.vue +1 -1
  121. package/edit/monitoring.coreos.com.alertmanagerconfig/types/webhook.vue +2 -2
  122. package/edit/monitoring.coreos.com.receiver/tls.vue +18 -18
  123. package/edit/monitoring.coreos.com.receiver/types/webhook.banner.vue +4 -4
  124. package/edit/monitoring.coreos.com.receiver/types/webhook.vue +1 -1
  125. package/edit/namespace.vue +2 -2
  126. package/edit/networking.k8s.io.networkpolicy/PolicyRuleTarget.vue +126 -45
  127. package/edit/networking.k8s.io.networkpolicy/index.vue +1 -1
  128. package/edit/provisioning.cattle.io.cluster/MachinePool.vue +10 -0
  129. package/edit/provisioning.cattle.io.cluster/RegistryConfigs.vue +1 -0
  130. package/edit/provisioning.cattle.io.cluster/__tests__/rke2.test.ts +202 -2
  131. package/edit/provisioning.cattle.io.cluster/rke2.vue +248 -84
  132. package/edit/resources.cattle.io.backup.vue +1 -1
  133. package/edit/service.vue +1 -1
  134. package/edit/storage.k8s.io.storageclass/provisioners/driver.harvesterhci.io.vue +2 -2
  135. package/edit/workload/__tests__/Job.test.ts +3 -1
  136. package/edit/workload/index.vue +8 -3
  137. package/edit/workload/mixins/workload.js +16 -0
  138. package/layouts/default.vue +7 -3
  139. package/list/fleet.cattle.io.bundle.vue +6 -3
  140. package/list/fleet.cattle.io.clusterregistrationtoken.vue +3 -1
  141. package/list/fleet.cattle.io.gitrepo.vue +44 -5
  142. package/list/management.cattle.io.fleetworkspace.vue +45 -0
  143. package/list/node.vue +69 -16
  144. package/list/provisioning.cattle.io.cluster.vue +30 -1
  145. package/machine-config/azure.vue +97 -38
  146. package/middleware/authenticated.js +34 -0
  147. package/mixins/chart.js +73 -2
  148. package/mixins/resource-fetch.js +2 -2
  149. package/models/apps.statefulset.js +28 -0
  150. package/models/cluster/node.js +23 -2
  151. package/models/cluster.x-k8s.io.machine.js +4 -2
  152. package/models/clusterroletemplatebinding.js +7 -0
  153. package/models/constraints.gatekeeper.sh.constraint.js +9 -0
  154. package/models/fleet.cattle.io.cluster.js +19 -10
  155. package/models/fleet.cattle.io.gitrepo.js +7 -2
  156. package/models/management.cattle.io.cluster.js +1 -1
  157. package/models/management.cattle.io.fleetworkspace.js +12 -0
  158. package/models/management.cattle.io.gitreporestriction.js +5 -0
  159. package/models/management.cattle.io.podsecurityadmissionconfigurationtemplate.js +3 -0
  160. package/models/namespace.js +5 -5
  161. package/models/provisioning.cattle.io.cluster.js +7 -5
  162. package/nuxt/App.js +210 -0
  163. package/nuxt/axios.js +186 -0
  164. package/nuxt/client.js +817 -0
  165. package/nuxt/components/nuxt-build-indicator.vue +143 -0
  166. package/nuxt/components/nuxt-child.js +122 -0
  167. package/nuxt/components/nuxt-error.vue +98 -0
  168. package/nuxt/components/nuxt-link.client.js +98 -0
  169. package/nuxt/components/nuxt-link.server.js +16 -0
  170. package/nuxt/components/nuxt-loading.vue +154 -0
  171. package/nuxt/components/nuxt.js +101 -0
  172. package/nuxt/cookie-universal-nuxt.js +9 -0
  173. package/nuxt/empty.js +1 -0
  174. package/nuxt/index.js +365 -0
  175. package/nuxt/jsonp.js +82 -0
  176. package/nuxt/loading.html +39 -0
  177. package/nuxt/middleware.js +12 -0
  178. package/nuxt/mixins/fetch.client.js +90 -0
  179. package/nuxt/mixins/fetch.server.js +69 -0
  180. package/nuxt/portal-vue.js +4 -0
  181. package/nuxt/server.js +312 -0
  182. package/nuxt/store.js +178 -0
  183. package/nuxt/utils.js +630 -0
  184. package/nuxt/views/app.template.html +9 -0
  185. package/nuxt/views/error.html +23 -0
  186. package/package.json +5 -9
  187. package/pages/auth/setup.vue +2 -2
  188. package/pages/c/_cluster/apps/charts/__tests__/install.helper.test.ts +33 -0
  189. package/pages/c/_cluster/apps/charts/chart.vue +4 -4
  190. package/pages/c/_cluster/apps/charts/install.helpers.js +26 -0
  191. package/pages/c/_cluster/apps/charts/install.vue +40 -66
  192. package/pages/c/_cluster/explorer/EventsTable.vue +5 -19
  193. package/pages/c/_cluster/explorer/index.vue +29 -25
  194. package/pages/c/_cluster/explorer/tools/index.vue +8 -8
  195. package/pages/c/_cluster/fleet/index.vue +95 -34
  196. package/pages/c/_cluster/gatekeeper/index.vue +1 -1
  197. package/pages/c/_cluster/istio/index.vue +5 -5
  198. package/pages/c/_cluster/manager/cloudCredential/index.vue +1 -1
  199. package/pages/c/_cluster/monitoring/index.vue +7 -0
  200. package/pages/c/_cluster/uiplugins/InstallDialog.vue +8 -8
  201. package/pages/c/_cluster/uiplugins/PluginInfoPanel.vue +20 -7
  202. package/pages/c/_cluster/uiplugins/index.vue +49 -17
  203. package/pages/home.vue +9 -4
  204. package/pages/index.vue +10 -1
  205. package/plugins/clean-html-directive.js +31 -0
  206. package/plugins/dashboard-store/actions.js +32 -9
  207. package/plugins/dashboard-store/mutations.js +5 -2
  208. package/plugins/dashboard-store/resource-class.js +8 -1
  209. package/plugins/steve/mutations.js +3 -2
  210. package/plugins/steve/steve-description-class.js +5 -1
  211. package/plugins/steve/subscribe.js +63 -54
  212. package/plugins/steve-create-worker.js +14 -0
  213. package/promptRemove/management.cattle.io.globalrole.vue +2 -2
  214. package/promptRemove/management.cattle.io.project.vue +2 -2
  215. package/promptRemove/management.cattle.io.roletemplate.vue +2 -2
  216. package/promptRemove/pod.vue +1 -1
  217. package/public/index.html +65 -0
  218. package/rancher-components/components/Banner/Banner.test.ts +9 -1
  219. package/rancher-components/components/Banner/Banner.vue +1 -1
  220. package/rancher-components/components/Form/Checkbox/Checkbox.vue +2 -0
  221. package/rancher-components/components/Form/Radio/RadioButton.vue +1 -1
  222. package/scripts/build-pkg.sh +1 -0
  223. package/scripts/clean +6 -0
  224. package/scripts/extension/bundle +58 -0
  225. package/scripts/extension/helmpatch +89 -0
  226. package/scripts/extension/publish +314 -0
  227. package/scripts/test-plugins-build.sh +4 -0
  228. package/store/__tests__/index.test.ts +110 -0
  229. package/store/index.js +145 -58
  230. package/store/type-map.js +26 -19
  231. package/tsconfig.default.json +36 -0
  232. package/tsconfig.json +24 -0
  233. package/types/shell/index.d.ts +420 -343
  234. package/utils/__tests__/string.test.ts +12 -0
  235. package/utils/auth.js +65 -0
  236. package/utils/monitoring.js +2 -1
  237. package/utils/position.js +5 -8
  238. package/utils/router.scrollBehavior.js +80 -0
  239. package/utils/select.js +1 -3
  240. package/utils/socket.js +1 -0
  241. package/utils/string.js +13 -0
  242. package/utils/time.js +9 -0
  243. package/vue.config.js +679 -0
  244. package/yarn-error.log +196 -0
  245. package/chart/rancher-alerting-drivers.vue +0 -53
  246. package/chart/rancher-gatekeeper.vue +0 -37
  247. package/creators/app/files/nuxt.config.js +0 -6
  248. package/models/management.cattle.io.podsecurityadmissionconfigurationtemplate.ts +0 -4
  249. package/nuxt.config.js +0 -798
@@ -4,12 +4,18 @@ import CruResource from '@shell/components/CruResource';
4
4
  import Labels from '@shell/components/form/Labels';
5
5
  import Loading from '@shell/components/Loading';
6
6
  import NameNsDescription from '@shell/components/form/NameNsDescription';
7
- import { FLEET, MANAGEMENT } from '@shell/config/types';
7
+ import { FLEET, MANAGEMENT, SCHEMA } from '@shell/config/types';
8
8
  // import RoleBindings from '@shell/components/RoleBindings';
9
9
  import Tabbed from '@shell/components/Tabbed';
10
10
  import Tab from '@shell/components/Tabbed/Tab';
11
11
  import { SCOPE_NAMESPACE, SCOPE_CLUSTER } from '@shell/components/RoleBindings.vue';
12
12
  import { NAME as FLEET_NAME } from '@shell/config/product/fleet';
13
+ // import KeyValue from '@shell/components/form/KeyValue.vue';
14
+ import { mapState } from 'vuex';
15
+ import { LAST_NAMESPACE, WORKSPACE } from '@shell/store/prefs';
16
+ import { exceptionToErrorsArray } from '@shell/utils/error';
17
+ import Banner from '@components/Banner/Banner.vue';
18
+ import ArrayList from '@shell/components/form/ArrayList.vue';
13
19
 
14
20
  export default {
15
21
  name: 'FleetCruWorkspace',
@@ -19,26 +25,123 @@ export default {
19
25
  Labels,
20
26
  Loading,
21
27
  NameNsDescription,
22
- // RoleBindings,
23
28
  Tabbed,
24
29
  Tab,
30
+ Banner,
31
+ ArrayList
25
32
  },
26
33
 
27
34
  mixins: [CreateEditView],
28
35
 
29
36
  async fetch() {
30
37
  this.rancherClusters = await this.$store.dispatch('management/findAll', { type: MANAGEMENT.CLUSTER });
31
- this.fleetClusters = await this.$store.dispatch('management/findAll', { type: FLEET.CLUSTER });
38
+
39
+ if (this.$store.getters['management/schemaFor']( FLEET.CLUSTER )) {
40
+ this.fleetClusters = await this.$store.dispatch('management/findAll', { type: FLEET.CLUSTER });
41
+ }
42
+
43
+ if (this.hasRepoRestrictionSchema) {
44
+ const restrictions = await this.$store.dispatch('management/findAll', { type: FLEET.GIT_REPO_RESTRICTION });
45
+
46
+ const workSpaceRestriction = restrictions.find((item) => {
47
+ return item.metadata.namespace === this.value.metadata.name && item.metadata.name.startsWith(`restriction-${ this.value.metadata.name }`);
48
+ });
49
+
50
+ if (workSpaceRestriction) {
51
+ this.workSpaceRestriction = workSpaceRestriction;
52
+ }
53
+ }
54
+
55
+ this.restrictionsOptions = await this.$store.getters[`type-map/optionsFor`](FLEET.GIT_REPO_RESTRICTION);
56
+ this.restrictionsSchema = await this.$store.getters[`management/schemaFor`](FLEET.GIT_REPO_RESTRICTION);
32
57
  },
33
58
 
34
59
  data() {
60
+ this.$set(this.value, 'spec', this.value.spec || {});
61
+
35
62
  return {
36
- fleetClusters: null,
37
- rancherClusters: null,
63
+ fleetClusters: null,
64
+ rancherClusters: null,
65
+ workSpaceRestriction: null,
66
+ restrictions: [],
67
+ targetNamespaces: [],
68
+ restrictionsSchema: { spec: {} },
69
+ namespace: this.$store.getters['prefs/get'](LAST_NAMESPACE),
70
+ hasRepoRestrictionSchema: !!this.$store.getters['management/schemaFor']( FLEET.GIT_REPO_RESTRICTION )
38
71
  };
39
72
  },
40
73
 
74
+ methods: {
75
+ async saveAll(buttonCb) {
76
+ // Anyone who can edit workspace
77
+
78
+ try {
79
+ await this.value.save();
80
+
81
+ // IF there is a restriction update it
82
+ if (this.workSpaceRestriction) {
83
+ await this.workSpaceRestriction.save();
84
+ }
85
+
86
+ // If there is no restriction and targetnamespace is set then create it.
87
+ if (!this.workSpaceRestriction && this.targetNamespaces.length) {
88
+ // For users with more limited permissions the gitreporestriction schema may not be visible until they create a workspace
89
+ if (!this.hasRepoRestrictionSchema) {
90
+ await this.$store.dispatch('management/find', { type: SCHEMA, id: FLEET.GIT_REPO_RESTRICTION }, { force: true });
91
+ }
92
+ const model = await this.$store.dispatch(`management/create`, {
93
+ type: FLEET.GIT_REPO_RESTRICTION,
94
+ allowedTargetNamespaces: this.targetNamespaces,
95
+ metadata: {
96
+ // restriction- prefix is added to the workspace name
97
+ // to identify automatically created GitRepoRestrictions
98
+ // when adding targetNamespaces at the point of workspace creation
99
+ name: `restriction-${ this.value.metadata.name }-${ Date.now() }`,
100
+ namespace: this.value.metadata.name // what the user types
101
+ }
102
+ });
103
+
104
+ await model.save();
105
+ }
106
+
107
+ await this.value.waitForWorkspaceSchema(20000, (schema) => {
108
+ // For standard user if there are no workspaces, user can't list workspaces
109
+ // Therefore wait for it.
110
+ return schema.collectionMethods?.includes('GET');
111
+ });
112
+
113
+ await this.$store.dispatch( 'management/findAll', { type: FLEET.WORKSPACE });
114
+
115
+ this.$store.commit('updateWorkspace', { value: this.value.metadata.name, getters: this.$store.getters } );
116
+ this.$store.dispatch('prefs/set', { key: WORKSPACE, value: this.value.metadata.name });
117
+
118
+ buttonCb(true);
119
+ this.done();
120
+ } catch (err) {
121
+ console.error(err) ; // eslint-disable-line no-console
122
+ buttonCb(false);
123
+ this.errors = exceptionToErrorsArray(err);
124
+ }
125
+ },
126
+ },
127
+
41
128
  computed: {
129
+ ...mapState(['allWorkspaces', 'workspace']),
130
+
131
+ allowedTargetNamespaces: {
132
+ get() {
133
+ return this.workSpaceRestriction?.allowedTargetNamespaces || [];
134
+ },
135
+
136
+ set(value) {
137
+ if (this.workSpaceRestriction) {
138
+ this.workSpaceRestriction.allowedTargetNamespaces = value;
139
+ }
140
+
141
+ this.targetNamespaces = value;
142
+ }
143
+ },
144
+
42
145
  SCOPE_NAMESPACE() {
43
146
  return SCOPE_NAMESPACE;
44
147
  },
@@ -65,7 +168,7 @@ export default {
65
168
  :validation-passed="true"
66
169
  :errors="errors"
67
170
  @error="e=>errors = e"
68
- @finish="save"
171
+ @finish="saveAll"
69
172
  @cancel="done"
70
173
  >
71
174
  <NameNsDescription
@@ -100,6 +203,38 @@ export default {
100
203
  :mode="mode"
101
204
  />
102
205
  </Tab>
206
+ <Tab
207
+ name="allowedtargetnamespaces"
208
+ label-key="fleet.workspaces.tabs.restrictions"
209
+ >
210
+ <Banner
211
+ color="info"
212
+ >
213
+ <div>
214
+ <t
215
+ k="fleet.restrictions.banner"
216
+ :count="allowedTargetNamespaces.length"
217
+ :raw="true"
218
+ />
219
+ <a
220
+ v-if="!!allowedTargetNamespaces.length"
221
+ @click="workSpaceRestriction.goToDetail()"
222
+ >
223
+ {{ t('generic.here') }}
224
+ </a>
225
+ </div>
226
+ </Banner>
227
+
228
+ <ArrayList
229
+ key="labels"
230
+ v-model="allowedTargetNamespaces"
231
+ :add-label="t('fleet.restrictions.addLabel')"
232
+ :mode="mode"
233
+ :title="t('fleet.restrictions.addTitle')"
234
+ :read-allowed="false"
235
+ :value-can-be-empty="true"
236
+ />
237
+ </Tab>
103
238
  </Tabbed>
104
239
  </CruResource>
105
240
  </template>
@@ -86,15 +86,18 @@ export default (Vue as VueConstructor<Vue & InstanceType<typeof CreateEditView>>
86
86
  :resource="value"
87
87
  :errors="errors"
88
88
  :cancel-event="true"
89
+ :done-route="doneRoute"
89
90
  @error="setErrors"
90
91
  @finish="save"
91
- @cancel="done()"
92
+ @cancel="done"
92
93
  >
93
94
  <NameNsDescription
94
95
  :value="value"
95
96
  :namespaced="false"
96
97
  :mode="mode"
98
+ description-key="description"
97
99
  />
100
+
98
101
  <PodSecurityAdmission
99
102
  :labels="defaults"
100
103
  :labels-always-active="true"
@@ -122,8 +122,8 @@ export default {
122
122
 
123
123
  <h5
124
124
  v-if="editHelp"
125
+ v-clean-html="editHelp"
125
126
  class="edit-help"
126
- v-html="editHelp"
127
127
  />
128
128
 
129
129
  <div class="edit-change mt-20">
@@ -143,8 +143,8 @@ export default {
143
143
  <div>
144
144
  <Banner
145
145
  v-if="mode !== view"
146
+ v-clean-html="t('monitoringReceiver.webhook.banner', {}, raw=true)"
146
147
  color="info"
147
- v-html="t('monitoringReceiver.webhook.banner', {}, raw=true)"
148
148
  />
149
149
  <div class="row mb-20">
150
150
  <LabeledSelect
@@ -166,8 +166,8 @@ export default {
166
166
  </div>
167
167
  <Banner
168
168
  v-if="showNamespaceBanner"
169
+ v-clean-html="t('monitoringReceiver.webhook.modifyNamespace', {}, raw=true)"
169
170
  color="info"
170
- v-html="t('monitoringReceiver.webhook.modifyNamespace', {}, raw=true)"
171
171
  />
172
172
  <div class="row mb-20">
173
173
  <div class="col span-12">
@@ -35,37 +35,37 @@ export default {
35
35
  <div class="row">
36
36
  <div class="col span-12">
37
37
  <h3>{{ t('monitoring.receiver.tls.label') }}</h3>
38
- <Banner
39
- color="info"
40
- v-html="t('monitoring.receiver.tls.secretsBanner', {}, true)"
38
+ <Banner
39
+ v-clean-html="t('monitoring.receiver.tls.secretsBanner', {}, true)"
40
+ color="info"
41
41
  />
42
42
  </div>
43
43
  </div>
44
44
  <div class="row mb-20">
45
45
  <div class="col span-6">
46
- <LabeledInput
47
- v-model="value.tls_config.ca_file"
48
- :mode="mode"
49
- :label="t('monitoring.receiver.tls.caFilePath.label')"
50
- :placeholder="t('monitoring.receiver.tls.caFilePath.placeholder')"
46
+ <LabeledInput
47
+ v-model="value.tls_config.ca_file"
48
+ :mode="mode"
49
+ :label="t('monitoring.receiver.tls.caFilePath.label')"
50
+ :placeholder="t('monitoring.receiver.tls.caFilePath.placeholder')"
51
51
  />
52
52
  </div>
53
53
  </div>
54
54
  <div class="row mb-20">
55
55
  <div class="col span-6">
56
- <LabeledInput
57
- v-model="value.tls_config.cert_file"
58
- :mode="mode"
59
- :label="t('monitoring.receiver.tls.certFilePath.label')"
60
- :placeholder="t('monitoring.receiver.tls.certFilePath.placeholder')"
56
+ <LabeledInput
57
+ v-model="value.tls_config.cert_file"
58
+ :mode="mode"
59
+ :label="t('monitoring.receiver.tls.certFilePath.label')"
60
+ :placeholder="t('monitoring.receiver.tls.certFilePath.placeholder')"
61
61
  />
62
62
  </div>
63
63
  <div class="col span-6">
64
- <LabeledInput
65
- v-model="value.tls_config.key_file"
66
- :mode="mode"
67
- :label="t('monitoring.receiver.tls.keyFilePath.label')"
68
- :placeholder="t('monitoring.receiver.tls.keyFilePath.placeholder')"
64
+ <LabeledInput
65
+ v-model="value.tls_config.key_file"
66
+ :mode="mode"
67
+ :label="t('monitoring.receiver.tls.keyFilePath.label')"
68
+ :placeholder="t('monitoring.receiver.tls.keyFilePath.placeholder')"
69
69
  />
70
70
  </div>
71
71
  </div>
@@ -20,9 +20,9 @@ export default {
20
20
  };
21
21
  </script>
22
22
  <template>
23
- <Banner
24
- v-if="model.length === 0 && !isView"
25
- color="info"
26
- v-html="t('monitoringReceiver.webhook.banner', {}, raw=true)"
23
+ <Banner
24
+ v-if="model.length === 0 && !isView"
25
+ v-clean-html="t('monitoringReceiver.webhook.banner', {}, raw=true)"
26
+ color="info"
27
27
  />
28
28
  </template>
@@ -50,8 +50,8 @@ export default {
50
50
  </div>
51
51
  <Banner
52
52
  v-if="showNamespaceBanner"
53
+ v-clean-html="t('monitoringReceiver.webhook.modifyNamespace', {}, raw=true)"
53
54
  color="info"
54
- v-html="t('monitoringReceiver.webhook.modifyNamespace', {}, raw=true)"
55
55
  />
56
56
  <div class="row mb-20">
57
57
  <div class="col span-12">
@@ -108,8 +108,8 @@ export default {
108
108
  },
109
109
 
110
110
  watch: {
111
- project(newProject) {
112
- const limits = this.getDefaultContainerResourceLimits(newProject);
111
+ project() {
112
+ const limits = this.getDefaultContainerResourceLimits(this.projectName);
113
113
 
114
114
  this.$set(this, 'containerResourceLimits', limits);
115
115
  },
@@ -11,9 +11,12 @@ import { Banner } from '@components/Banner';
11
11
  import throttle from 'lodash/throttle';
12
12
  import { isValidCIDR } from '@shell/utils/validators/cidr';
13
13
 
14
- const TARGET_OPTION_IP_BLOCK = 'ipBlock';
15
- const TARGET_OPTION_NAMESPACE_SELECTOR = 'namespaceSelector';
16
- const TARGET_OPTION_POD_SELECTOR = 'podSelector';
14
+ const TARGET_OPTIONS = {
15
+ IP_BLOCK: 'ipBlock',
16
+ NAMESPACE_SELECTOR: 'namespaceSelector',
17
+ POD_SELECTOR: 'podSelector',
18
+ NAMESPACE_AND_POD_SELECTOR: 'namespaceAndPodSelector',
19
+ };
17
20
 
18
21
  export default {
19
22
  components: {
@@ -52,53 +55,48 @@ export default {
52
55
  },
53
56
  },
54
57
  data() {
55
- if (!this.value[TARGET_OPTION_IP_BLOCK] && !this.value[TARGET_OPTION_POD_SELECTOR] && !this.value[TARGET_OPTION_NAMESPACE_SELECTOR]) {
58
+ if (!this.value[TARGET_OPTIONS.IP_BLOCK] &&
59
+ !this.value[TARGET_OPTIONS.POD_SELECTOR] &&
60
+ !this.value[TARGET_OPTIONS.NAMESPACE_SELECTOR] &&
61
+ !this.value[TARGET_OPTIONS.NAMESPACE_AND_POD_SELECTOR]
62
+ ) {
56
63
  this.$nextTick(() => {
57
- this.$set(this.value, TARGET_OPTION_IP_BLOCK, {});
64
+ this.$set(this.value, TARGET_OPTIONS.IP_BLOCK, {});
58
65
  });
59
66
  }
60
67
 
61
- const matchingPods = this.getMatchingPods();
62
- const matchingNamespaces = this.getMatchingNamespaces();
63
-
64
68
  return {
65
- portOptions: ['TCP', 'UDP'],
66
- matchingPods,
67
- matchingNamespaces,
68
- invalidCidr: null,
69
- invalidCidrs: [],
70
- TARGET_OPTION_IP_BLOCK,
71
- TARGET_OPTION_NAMESPACE_SELECTOR,
72
- TARGET_OPTION_POD_SELECTOR,
69
+ portOptions: ['TCP', 'UDP'],
70
+ matchingPods: {},
71
+ matchingNamespaces: {},
72
+ invalidCidr: null,
73
+ invalidCidrs: [],
73
74
  POD,
74
- targetOptions: [
75
- TARGET_OPTION_IP_BLOCK,
76
- TARGET_OPTION_NAMESPACE_SELECTOR,
77
- TARGET_OPTION_POD_SELECTOR
78
- ],
75
+ TARGET_OPTIONS,
76
+ targetOptions: Object.values(TARGET_OPTIONS),
79
77
  };
80
78
  },
81
79
  computed: {
82
80
  podSelectorExpressions: {
83
81
  get() {
84
82
  return convert(
85
- this.value[TARGET_OPTION_POD_SELECTOR]?.matchLabels || {},
86
- this.value[TARGET_OPTION_POD_SELECTOR]?.matchExpressions || []
83
+ this.value[TARGET_OPTIONS.POD_SELECTOR]?.matchLabels || {},
84
+ this.value[TARGET_OPTIONS.POD_SELECTOR]?.matchExpressions || []
87
85
  );
88
86
  },
89
87
  set(podSelectorExpressions) {
90
- this.$set(this.value, TARGET_OPTION_POD_SELECTOR, simplify(podSelectorExpressions));
88
+ this.$set(this.value, TARGET_OPTIONS.POD_SELECTOR, simplify(podSelectorExpressions));
91
89
  }
92
90
  },
93
91
  namespaceSelectorExpressions: {
94
92
  get() {
95
93
  return convert(
96
- this.value[TARGET_OPTION_NAMESPACE_SELECTOR]?.matchLabels || {},
97
- this.value[TARGET_OPTION_NAMESPACE_SELECTOR]?.matchExpressions || []
94
+ this.value[TARGET_OPTIONS.NAMESPACE_SELECTOR]?.matchLabels || {},
95
+ this.value[TARGET_OPTIONS.NAMESPACE_SELECTOR]?.matchExpressions || []
98
96
  );
99
97
  },
100
98
  set(namespaceSelectorExpressions) {
101
- this.$set(this.value, TARGET_OPTION_NAMESPACE_SELECTOR, simplify(namespaceSelectorExpressions));
99
+ this.$set(this.value, TARGET_OPTIONS.NAMESPACE_SELECTOR, simplify(namespaceSelectorExpressions));
102
100
  }
103
101
  },
104
102
  selectTargetOptions() {
@@ -116,6 +114,9 @@ export default {
116
114
  targetType: {
117
115
  get() {
118
116
  for (const option of this.targetOptions) {
117
+ if (this.value[TARGET_OPTIONS.NAMESPACE_AND_POD_SELECTOR] || (this.value[TARGET_OPTIONS.NAMESPACE_SELECTOR] && this.value[TARGET_OPTIONS.POD_SELECTOR])) {
118
+ return TARGET_OPTIONS.NAMESPACE_AND_POD_SELECTOR;
119
+ }
119
120
  if (this.value[option]) {
120
121
  return option;
121
122
  }
@@ -124,13 +125,30 @@ export default {
124
125
  return null;
125
126
  },
126
127
  set(targetType) {
127
- this.$delete(this.value, TARGET_OPTION_IP_BLOCK);
128
- this.$delete(this.value, TARGET_OPTION_NAMESPACE_SELECTOR);
129
- this.$delete(this.value, TARGET_OPTION_POD_SELECTOR);
128
+ this.$delete(this.value, TARGET_OPTIONS.IP_BLOCK);
129
+ this.$delete(this.value, TARGET_OPTIONS.NAMESPACE_SELECTOR);
130
+ this.$delete(this.value, TARGET_OPTIONS.POD_SELECTOR);
131
+ this.$delete(this.value, TARGET_OPTIONS.NAMESPACE_AND_POD_SELECTOR);
130
132
  this.$nextTick(() => {
131
133
  this.$set(this.value, targetType, {});
132
134
  });
133
135
  }
136
+ },
137
+ updateMatches() {
138
+ return {
139
+ handler: throttle(function() {
140
+ this.matchingNamespaces = this.getMatchingNamespaces();
141
+ this.matchingPods = this.getMatchingPods();
142
+ }, 250, { leading: true }),
143
+ immediate: true
144
+ };
145
+ },
146
+ matchingNamespacesAndPods() {
147
+ return {
148
+ policyNamespace: this.namespace,
149
+ ...Object.keys(this.matchingNamespaces).reduce((acc, k) => ({ ...acc, [`${ k }Namespaces`]: this.matchingNamespaces[k] }), {}),
150
+ ...Object.keys(this.matchingPods).reduce((acc, k) => ({ ...acc, [`${ k }Pods`]: this.matchingPods[k] }), {}),
151
+ };
134
152
  }
135
153
  },
136
154
  watch: {
@@ -144,24 +162,21 @@ export default {
144
162
  },
145
163
  methods: {
146
164
  validateCIDR() {
147
- const exceptCidrs = this.value[TARGET_OPTION_IP_BLOCK]?.except || [];
165
+ const exceptCidrs = this.value[TARGET_OPTIONS.IP_BLOCK]?.except || [];
148
166
 
149
167
  this.invalidCidrs = exceptCidrs
150
168
  .filter(cidr => !isValidCIDR(cidr))
151
169
  .map(invalidCidr => invalidCidr || '<blank>');
152
170
 
153
- if (this.value[TARGET_OPTION_IP_BLOCK]?.cidr && !isValidCIDR(this.value[TARGET_OPTION_IP_BLOCK].cidr)) {
154
- this.invalidCidr = this.value[TARGET_OPTION_IP_BLOCK].cidr;
171
+ if (this.value[TARGET_OPTIONS.IP_BLOCK]?.cidr && !isValidCIDR(this.value[TARGET_OPTIONS.IP_BLOCK].cidr)) {
172
+ this.invalidCidr = this.value[TARGET_OPTIONS.IP_BLOCK].cidr;
155
173
  } else {
156
174
  this.invalidCidr = null;
157
175
  }
158
176
  },
159
- updateMatches: throttle(function() {
160
- this.matchingPods = this.getMatchingPods();
161
- this.matchingNamespaces = this.getMatchingNamespaces();
162
- }, 250, { leading: true }),
163
177
  getMatchingPods() {
164
- const allInNamespace = this.allPods.filter(pod => pod.metadata.namespace === this.namespace);
178
+ const namespaces = this.targetType === TARGET_OPTIONS.NAMESPACE_AND_POD_SELECTOR ? this.matchingNamespaces.matches : [{ id: this.namespace }];
179
+ const allInNamespace = this.allPods.filter(pod => namespaces.some(ns => ns.id === pod.metadata.namespace));
165
180
  const match = matching(allInNamespace, this.podSelectorExpressions);
166
181
  const matched = match.length || 0;
167
182
  const sample = match[0]?.nameDisplay;
@@ -199,17 +214,18 @@ export default {
199
214
  <LabeledSelect
200
215
  v-model="targetType"
201
216
  :mode="mode"
217
+ :tooltip="targetType === TARGET_OPTIONS.NAMESPACE_AND_POD_SELECTOR ? t('networkpolicy.selectors.matchingNamespacesAndPods.tooltip') : null"
202
218
  :options="selectTargetOptions"
203
219
  :multiple="false"
204
220
  :label="t('networkpolicy.rules.type')"
205
221
  />
206
222
  </div>
207
223
  </div>
208
- <div v-if="targetType === TARGET_OPTION_IP_BLOCK">
224
+ <div v-if="targetType === TARGET_OPTIONS.IP_BLOCK">
209
225
  <div class="row">
210
226
  <div class="col span-6">
211
227
  <LabeledInput
212
- v-model="value[TARGET_OPTION_IP_BLOCK].cidr"
228
+ v-model="value[TARGET_OPTIONS.IP_BLOCK].cidr"
213
229
  :mode="mode"
214
230
  :placeholder="t('networkpolicy.rules.ipBlock.cidr.placeholder')"
215
231
  :label="t('networkpolicy.rules.ipBlock.cidr.label')"
@@ -229,7 +245,7 @@ export default {
229
245
  <div class="row mt-20">
230
246
  <div class="col span-12">
231
247
  <ArrayList
232
- v-model="value[TARGET_OPTION_IP_BLOCK].except"
248
+ v-model="value[TARGET_OPTIONS.IP_BLOCK].except"
233
249
  :add-label="t('networkpolicy.rules.ipBlock.addExcept')"
234
250
  :mode="mode"
235
251
  :show-header="true"
@@ -249,11 +265,11 @@ export default {
249
265
  </div>
250
266
  </div>
251
267
  </div>
252
- <div v-if="targetType === TARGET_OPTION_POD_SELECTOR">
268
+ <div v-if="targetType === TARGET_OPTIONS.POD_SELECTOR">
253
269
  <div class="row">
254
270
  <div class="col span-12">
255
271
  <Banner color="success">
256
- <span v-html="t('networkpolicy.selectors.matchingPods.matchesSome', matchingPods)" />
272
+ <span v-clean-html="t('networkpolicy.selectors.matchingPods.matchesSome', matchingPods)" />
257
273
  </Banner>
258
274
  </div>
259
275
  </div>
@@ -269,11 +285,11 @@ export default {
269
285
  </div>
270
286
  </div>
271
287
  </div>
272
- <div v-if="targetType === TARGET_OPTION_NAMESPACE_SELECTOR">
288
+ <div v-if="targetType === TARGET_OPTIONS.NAMESPACE_SELECTOR">
273
289
  <div class="row">
274
290
  <div class="col span-12">
275
291
  <Banner color="success">
276
- <span v-html="t('networkpolicy.selectors.matchingNamespaces.matchesSome', matchingNamespaces)" />
292
+ <span v-clean-html="t('networkpolicy.selectors.matchingNamespaces.matchesSome', matchingNamespaces)" />
277
293
  </Banner>
278
294
  </div>
279
295
  </div>
@@ -289,5 +305,70 @@ export default {
289
305
  </div>
290
306
  </div>
291
307
  </div>
308
+ <div v-if="targetType === TARGET_OPTIONS.NAMESPACE_AND_POD_SELECTOR">
309
+ <div class="row">
310
+ <div class="col span-12">
311
+ <Banner color="success">
312
+ <span
313
+ v-if="!namespaceSelectorExpressions.length"
314
+ v-clean-html="t('networkpolicy.selectors.matchingPods.matchesSome', matchingPods)"
315
+ />
316
+ <span
317
+ v-else
318
+ v-clean-html="t('networkpolicy.selectors.matchingNamespacesAndPods.matchesSome', matchingNamespacesAndPods)"
319
+ />
320
+ </Banner>
321
+ </div>
322
+ </div>
323
+ <div class="row mb-0">
324
+ <div class="col span-1 namespace-pod-rule">
325
+ <span class="label">
326
+ {{ t('networkpolicy.rules.namespace') }}
327
+ </span>
328
+ </div>
329
+ <div class="col span-11">
330
+ <MatchExpressions
331
+ v-model="namespaceSelectorExpressions"
332
+ :mode="mode"
333
+ :show-add-button="false"
334
+ :show-remove-button="false"
335
+ :show-remove="false"
336
+ :initial-empty-row="true"
337
+ :type="POD"
338
+ />
339
+ </div>
340
+ </div>
341
+ <div class="row mb-0">
342
+ <div class="col span-1 namespace-pod-rule">
343
+ <span class="label">
344
+ {{ t('networkpolicy.rules.pod') }}
345
+ </span>
346
+ </div>
347
+ <div class="col span-11">
348
+ <MatchExpressions
349
+ v-model="podSelectorExpressions"
350
+ :mode="mode"
351
+ :show-add-button="false"
352
+ :show-remove-button="false"
353
+ :show-remove="false"
354
+ :initial-empty-row="true"
355
+ :type="POD"
356
+ />
357
+ </div>
358
+ </div>
359
+ </div>
292
360
  </div>
293
361
  </template>
362
+
363
+ <style lang='scss' scoped>
364
+ .namespace-pod-rule {
365
+ width: 100px;
366
+ margin: 0;
367
+ text-align: center;
368
+
369
+ .label {
370
+ display: block;
371
+ margin-top: 32px;
372
+ }
373
+ }
374
+ </style>
@@ -258,7 +258,7 @@ export default {
258
258
  <div class="row">
259
259
  <div class="col span-12">
260
260
  <Banner color="success">
261
- <span v-html="t('networkpolicy.selectors.matchingPods.matchesSome', matchingPods)" />
261
+ <span v-clean-html="t('networkpolicy.selectors.matchingPods.matchesSome', matchingPods)" />
262
262
  </Banner>
263
263
  </div>
264
264
  </div>
@@ -158,6 +158,14 @@ export default {
158
158
  // (only used on Elemental because it comes from "machineinventoryselectortemplate" machine-config)
159
159
  updateMachineCount(val) {
160
160
  this.value.pool.quantity = val || 1;
161
+ },
162
+
163
+ expandAdvanced() {
164
+ const advancedComponent = this.$refs.advanced;
165
+
166
+ if (advancedComponent && !advancedComponent.show) {
167
+ advancedComponent.toggle();
168
+ }
161
169
  }
162
170
  }
163
171
  };
@@ -223,6 +231,7 @@ export default {
223
231
  :machine-pools="machinePools"
224
232
  @error="e=>errors = e"
225
233
  @updateMachineCount="updateMachineCount"
234
+ @expandAdvanced="expandAdvanced"
226
235
  />
227
236
  <Banner
228
237
  v-else-if="value.configMissing"
@@ -236,6 +245,7 @@ export default {
236
245
  />
237
246
 
238
247
  <AdvancedSection
248
+ ref="advanced"
239
249
  :mode="mode"
240
250
  class="advanced"
241
251
  >