@rancher/shell 3.0.4 → 3.0.5-rc.2

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 (270) hide show
  1. package/assets/images/providers/sks.svg +1 -0
  2. package/assets/styles/base/_basic.scss +6 -0
  3. package/assets/styles/base/_helpers.scss +4 -0
  4. package/assets/styles/base/_variables.scss +1 -0
  5. package/assets/styles/global/_button.scss +1 -0
  6. package/assets/translations/en-us.yaml +65 -15
  7. package/assets/translations/zh-hans.yaml +4 -3
  8. package/chart/monitoring/index.vue +3 -1
  9. package/cloud-credential/aws.vue +2 -0
  10. package/components/ActionDropdownShell.vue +71 -0
  11. package/components/AppModal.vue +18 -4
  12. package/components/AsyncButton.vue +24 -7
  13. package/components/BannerGraphic.vue +1 -0
  14. package/components/CommunityLinks.vue +4 -59
  15. package/components/CopyToClipboardText.vue +2 -1
  16. package/components/CruResource.vue +6 -1
  17. package/components/DetailText.vue +5 -0
  18. package/components/ExplorerMembers.vue +1 -1
  19. package/components/ExplorerProjectsNamespaces.vue +68 -18
  20. package/components/GlobalRoleBindings.vue +5 -1
  21. package/components/GrowlManager.vue +1 -0
  22. package/components/LandingPagePreference.vue +7 -3
  23. package/components/LocaleSelector.vue +39 -95
  24. package/components/ModalManager.vue +55 -0
  25. package/components/ModalWithCard.vue +1 -0
  26. package/components/PromptModal.vue +47 -8
  27. package/components/PromptRemove.vue +1 -0
  28. package/components/PromptRestore.vue +1 -0
  29. package/components/ResourceCancelModal.vue +1 -0
  30. package/components/ResourceDetail/Masthead.vue +38 -12
  31. package/components/ResourceDetail/__tests__/Masthead.test.ts +5 -1
  32. package/components/ResourceDetail/index.vue +47 -12
  33. package/components/ResourceTable.vue +54 -19
  34. package/components/SideNav.vue +5 -1
  35. package/components/SlideInPanelManager.vue +126 -0
  36. package/components/SortableTable/THead.vue +5 -2
  37. package/components/SortableTable/actions.js +1 -1
  38. package/components/SortableTable/index.vue +64 -51
  39. package/components/SortableTable/paging.js +16 -19
  40. package/components/SortableTable/selection.js +0 -11
  41. package/components/Wizard.vue +2 -2
  42. package/components/__tests__/AsyncButton.test.ts +2 -2
  43. package/components/__tests__/ModalManager.spec.ts +176 -0
  44. package/components/__tests__/PromptModal.test.ts +148 -0
  45. package/components/__tests__/SlideInPanelManager.spec.ts +166 -0
  46. package/components/auth/AuthBanner.vue +13 -11
  47. package/components/auth/Principal.vue +1 -0
  48. package/components/auth/__tests__/RoleDetailEdit.test.ts +3 -2
  49. package/components/auth/login/ldap.vue +1 -1
  50. package/components/fleet/FleetResources.vue +21 -6
  51. package/components/form/ArrayList.vue +76 -60
  52. package/components/form/BannerSettings.vue +17 -2
  53. package/components/form/ColorInput.vue +35 -6
  54. package/components/form/Command.vue +6 -15
  55. package/components/form/EnvVars.vue +16 -8
  56. package/components/form/HealthCheck.vue +3 -3
  57. package/components/form/HookOption.vue +11 -16
  58. package/components/form/LabeledSelect.vue +18 -22
  59. package/components/form/LifecycleHooks.vue +3 -3
  60. package/components/form/MatchExpressions.vue +14 -8
  61. package/components/form/NameNsDescription.vue +128 -104
  62. package/components/form/Networking.vue +20 -12
  63. package/components/form/NodeAffinity.vue +31 -23
  64. package/components/form/NodeScheduling.vue +13 -3
  65. package/components/form/NotificationSettings.vue +15 -1
  66. package/components/form/Password.vue +1 -0
  67. package/components/form/PodAffinity.vue +43 -43
  68. package/components/form/Probe.vue +68 -66
  69. package/components/form/ResourceQuota/Project.vue +5 -1
  70. package/components/form/ResourceSelector.vue +7 -9
  71. package/components/form/SSHKnownHosts/__tests__/KnownHostsEditDialog.test.ts +16 -24
  72. package/components/form/SSHKnownHosts/index.vue +30 -13
  73. package/components/form/Security.vue +54 -56
  74. package/components/form/Select.vue +32 -21
  75. package/components/form/ShellInput.vue +5 -1
  76. package/components/form/Tolerations.vue +5 -1
  77. package/components/form/ValueFromResource.vue +134 -121
  78. package/components/form/WorkloadPorts.vue +18 -18
  79. package/components/form/__tests__/ArrayList.test.ts +5 -2
  80. package/components/form/__tests__/ColorInput.test.ts +35 -0
  81. package/components/form/__tests__/LabeledSelect.test.ts +40 -0
  82. package/components/form/__tests__/MatchExpressions.test.ts +12 -12
  83. package/components/form/__tests__/NameNsDescription.test.ts +115 -14
  84. package/components/form/__tests__/Probe.test.ts +12 -8
  85. package/components/form/__tests__/SSHKnownHosts.test.ts +22 -2
  86. package/components/form/__tests__/Select.test.ts +37 -0
  87. package/components/formatter/InternalExternalIP.vue +2 -0
  88. package/components/formatter/SecretData.vue +20 -7
  89. package/components/nav/Group.vue +27 -5
  90. package/components/nav/Header.vue +17 -43
  91. package/components/nav/NamespaceFilter.vue +134 -86
  92. package/components/nav/TopLevelMenu.vue +4 -5
  93. package/components/nav/Type.vue +12 -1
  94. package/components/nav/WindowManager/ContainerLogs.vue +87 -61
  95. package/components/nav/WindowManager/ContainerLogsActions.vue +76 -0
  96. package/components/templates/blank.vue +4 -1
  97. package/components/templates/default.vue +8 -3
  98. package/components/templates/home.vue +10 -1
  99. package/components/templates/plain.vue +10 -4
  100. package/composables/focusTrap.ts +12 -4
  101. package/composables/useRuntimeFlag.ts +29 -0
  102. package/config/router/routes.js +20 -13
  103. package/config/store.js +4 -0
  104. package/config/uiplugins.js +5 -1
  105. package/core/types.ts +12 -6
  106. package/detail/catalog.cattle.io.app.vue +6 -1
  107. package/detail/fleet.cattle.io.bundle.vue +70 -6
  108. package/detail/fleet.cattle.io.gitrepo.vue +1 -1
  109. package/detail/namespace.vue +0 -3
  110. package/detail/node.vue +17 -13
  111. package/detail/provisioning.cattle.io.cluster.vue +72 -6
  112. package/dialog/AddCustomBadgeDialog.vue +1 -1
  113. package/{pages/c/_cluster/uiplugins/AddExtensionRepos.vue → dialog/AddExtensionReposDialog.vue} +72 -42
  114. package/{components/AssignTo.vue → dialog/AssignToDialog.vue} +71 -80
  115. package/dialog/ChangePasswordDialog.vue +106 -0
  116. package/dialog/DeactivateDriverDialog.vue +1 -0
  117. package/{pages/c/_cluster/uiplugins/DeveloperInstallDialog.vue → dialog/DeveloperLoadExtensionDialog.vue} +74 -71
  118. package/dialog/DisableAuthProviderDialog.vue +101 -0
  119. package/dialog/DrainNode.vue +1 -1
  120. package/{pages/c/_cluster/uiplugins/CatalogList/CatalogLoadDialog.vue → dialog/ExtensionCatalogInstallDialog.vue} +100 -88
  121. package/{pages/c/_cluster/uiplugins/CatalogList/CatalogUninstallDialog.vue → dialog/ExtensionCatalogUninstallDialog.vue} +69 -57
  122. package/dialog/FeatureFlagListDialog.vue +288 -0
  123. package/dialog/ForceMachineRemoveDialog.vue +5 -2
  124. package/{components/Import.vue → dialog/ImportDialog.vue} +0 -5
  125. package/{pages/c/_cluster/uiplugins/InstallDialog.vue → dialog/InstallExtensionDialog.vue} +124 -106
  126. package/{components/form/SSHKnownHosts → dialog}/KnownHostsEditDialog.vue +52 -59
  127. package/dialog/MoveNamespaceDialog.vue +157 -0
  128. package/dialog/ScalePoolDownDialog.vue +1 -1
  129. package/{components/nav/Jump.vue → dialog/SearchDialog.vue} +34 -14
  130. package/{pages/c/_cluster/uiplugins/UninstallDialog.vue → dialog/UninstallExtensionDialog.vue} +67 -58
  131. package/dialog/WechatDialog.vue +57 -0
  132. package/edit/__tests__/monitoring.coreos.com.prometheusrule.test.ts +16 -3
  133. package/edit/auth/__tests__/oidc.test.ts +152 -109
  134. package/edit/auth/azuread.vue +2 -1
  135. package/edit/auth/github.vue +1 -1
  136. package/edit/auth/googleoauth.vue +5 -1
  137. package/edit/auth/ldap/index.vue +1 -1
  138. package/edit/auth/oidc.vue +38 -5
  139. package/edit/auth/saml.vue +1 -1
  140. package/edit/cloudcredential.vue +24 -9
  141. package/edit/logging.banzaicloud.io.output/__tests__/logging.banzaicloud.io.output.test.ts +40 -9
  142. package/edit/management.cattle.io.user.vue +28 -3
  143. package/edit/namespace.vue +1 -4
  144. package/edit/networking.k8s.io.ingress/IngressClass.vue +7 -3
  145. package/edit/networking.k8s.io.ingress/__tests__/IngressClass.test.ts +58 -0
  146. package/edit/persistentvolume/__tests__/persistentvolume.test.ts +14 -2
  147. package/edit/provisioning.cattle.io.cluster/CustomCommand.vue +4 -1
  148. package/edit/provisioning.cattle.io.cluster/SelectCredential.vue +26 -9
  149. package/edit/provisioning.cattle.io.cluster/__tests__/Advanced.test.ts +8 -8
  150. package/edit/provisioning.cattle.io.cluster/__tests__/DirectoryConfig.test.ts +26 -12
  151. package/edit/provisioning.cattle.io.cluster/__tests__/rke2.test.ts +66 -0
  152. package/edit/provisioning.cattle.io.cluster/__tests__/utils/rke2-test-data.ts +58 -0
  153. package/edit/provisioning.cattle.io.cluster/rke2.vue +49 -41
  154. package/edit/provisioning.cattle.io.cluster/tabs/AgentConfiguration.vue +6 -1
  155. package/edit/provisioning.cattle.io.cluster/tabs/DirectoryConfig.vue +5 -3
  156. package/edit/provisioning.cattle.io.cluster/tabs/MachinePool.vue +33 -2
  157. package/edit/provisioning.cattle.io.cluster/tabs/etcd/index.vue +2 -2
  158. package/edit/token.vue +2 -0
  159. package/edit/workload/index.vue +1 -0
  160. package/edit/workload/mixins/workload.js +0 -2
  161. package/initialize/install-plugins.js +2 -1
  162. package/list/harvesterhci.io.management.cluster.vue +4 -1
  163. package/list/management.cattle.io.feature.vue +4 -287
  164. package/list/provisioning.cattle.io.cluster.vue +20 -12
  165. package/machine-config/azure.vue +16 -4
  166. package/mixins/vue-select-overrides.js +0 -4
  167. package/models/__tests__/namespace.test.ts +25 -1
  168. package/models/cloudcredential.js +5 -0
  169. package/models/fleet.cattle.io.cluster.js +8 -2
  170. package/models/fleet.cattle.io.gitrepo.js +8 -34
  171. package/models/kontainerdriver.js +6 -3
  172. package/models/management.cattle.io.feature.js +7 -1
  173. package/models/management.cattle.io.node.js +3 -3
  174. package/models/namespace.js +11 -6
  175. package/models/nodedriver.js +6 -3
  176. package/models/workload.js +4 -1
  177. package/package.json +3 -3
  178. package/pages/about.vue +13 -3
  179. package/pages/account/index.vue +16 -6
  180. package/pages/auth/login.vue +18 -7
  181. package/pages/auth/logout.vue +4 -1
  182. package/pages/auth/setup.vue +2 -0
  183. package/pages/auth/verify.vue +13 -8
  184. package/pages/c/_cluster/apps/charts/chart.vue +1 -1
  185. package/pages/c/_cluster/apps/charts/install.vue +26 -26
  186. package/pages/c/_cluster/auth/config/index.vue +10 -12
  187. package/pages/c/_cluster/explorer/EventsTable.vue +38 -33
  188. package/pages/c/_cluster/explorer/index.vue +17 -15
  189. package/pages/c/_cluster/istio/index.vue +2 -2
  190. package/pages/c/_cluster/longhorn/index.vue +1 -1
  191. package/pages/c/_cluster/monitoring/index.vue +1 -1
  192. package/pages/c/_cluster/monitoring/monitor/_namespace/_id.vue +4 -2
  193. package/pages/c/_cluster/monitoring/monitor/create.vue +4 -2
  194. package/pages/c/_cluster/monitoring/route-receiver/_id.vue +4 -2
  195. package/pages/c/_cluster/monitoring/route-receiver/create.vue +5 -2
  196. package/pages/c/_cluster/neuvector/index.vue +1 -1
  197. package/pages/c/_cluster/settings/banners.vue +4 -3
  198. package/pages/c/_cluster/uiplugins/CatalogList/index.vue +8 -10
  199. package/pages/c/_cluster/uiplugins/__tests__/AddExtensionRepos.test.ts +4 -7
  200. package/pages/c/_cluster/uiplugins/index.vue +98 -55
  201. package/pages/diagnostic.vue +59 -11
  202. package/pages/fail-whale.vue +14 -8
  203. package/pages/home.vue +24 -18
  204. package/pages/prefs.vue +7 -6
  205. package/pages/support/index.vue +4 -1
  206. package/plugins/internal-api/index.ts +37 -0
  207. package/plugins/internal-api/shared/base-api.ts +13 -0
  208. package/plugins/internal-api/shell/shell.api.ts +108 -0
  209. package/plugins/steve/actions.js +0 -12
  210. package/public/index.html +1 -0
  211. package/rancher-components/Card/Card.vue +1 -1
  212. package/rancher-components/Form/Checkbox/Checkbox.test.ts +59 -1
  213. package/rancher-components/Form/Checkbox/Checkbox.vue +27 -3
  214. package/rancher-components/Form/LabeledInput/LabeledInput.test.ts +47 -0
  215. package/rancher-components/Form/LabeledInput/LabeledInput.vue +20 -2
  216. package/rancher-components/Form/Radio/RadioButton.test.ts +36 -1
  217. package/rancher-components/Form/Radio/RadioButton.vue +20 -4
  218. package/rancher-components/Form/Radio/RadioGroup.test.ts +60 -0
  219. package/rancher-components/Form/Radio/RadioGroup.vue +52 -10
  220. package/rancher-components/Form/ToggleSwitch/ToggleSwitch.test.ts +17 -0
  221. package/rancher-components/Form/ToggleSwitch/ToggleSwitch.vue +5 -0
  222. package/rancher-components/LabeledTooltip/LabeledTooltip.vue +10 -1
  223. package/rancher-components/RcButton/RcButton.vue +2 -1
  224. package/rancher-components/RcButton/types.ts +1 -0
  225. package/rancher-components/RcDropdown/RcDropdown.vue +18 -6
  226. package/rancher-components/RcDropdown/RcDropdownItem.vue +3 -56
  227. package/rancher-components/RcDropdown/RcDropdownItemCheckbox.vue +68 -0
  228. package/rancher-components/RcDropdown/RcDropdownItemSelect.vue +92 -0
  229. package/rancher-components/RcDropdown/RcDropdownTrigger.vue +10 -0
  230. package/rancher-components/RcDropdown/index.ts +2 -0
  231. package/rancher-components/RcDropdown/useDropdownCollection.ts +8 -0
  232. package/rancher-components/RcDropdown/useDropdownContext.ts +9 -3
  233. package/rancher-components/RcDropdown/useDropdownItem.ts +63 -0
  234. package/scripts/extension/bundle +20 -0
  235. package/scripts/extension/helm/charts/ui-plugin-server/templates/cr.yaml +2 -1
  236. package/scripts/extension/helm/charts/ui-plugin-server/values.yaml +2 -0
  237. package/scripts/extension/helmpatch +44 -31
  238. package/scripts/extension/publish +12 -12
  239. package/scripts/typegen.sh +2 -4
  240. package/server/har-file.js +25 -3
  241. package/store/action-menu.js +26 -56
  242. package/store/features.js +2 -1
  243. package/store/index.js +5 -0
  244. package/store/modal.ts +71 -0
  245. package/store/slideInPanel.ts +47 -0
  246. package/store/type-map.js +12 -1
  247. package/store/type-map.utils.ts +4 -4
  248. package/types/global-vue.d.ts +5 -0
  249. package/types/internal-api/shell/growl.d.ts +25 -0
  250. package/types/internal-api/shell/modal.d.ts +77 -0
  251. package/types/internal-api/shell/slideIn.d.ts +15 -0
  252. package/types/resources/fleet.d.ts +0 -14
  253. package/types/shell/index.d.ts +43 -24
  254. package/types/vue-shim.d.ts +4 -1
  255. package/utils/__mocks__/tabbable.js +13 -0
  256. package/utils/__tests__/object.test.ts +38 -4
  257. package/utils/cluster.js +35 -0
  258. package/utils/fleet.ts +15 -73
  259. package/utils/object.js +48 -5
  260. package/utils/validators/formRules/__tests__/index.test.ts +10 -1
  261. package/utils/validators/formRules/index.ts +27 -3
  262. package/utils/validators/machine-pool.ts +20 -0
  263. package/components/DisableAuthProviderModal.vue +0 -114
  264. package/components/MoveModal.vue +0 -166
  265. package/components/PromptChangePassword.vue +0 -123
  266. package/components/fleet/FleetBundleResources.vue +0 -86
  267. package/components/formatter/ExtensionCache.vue +0 -74
  268. package/components/formatter/Port.vue +0 -24
  269. package/components/formatter/SecretType.vue +0 -41
  270. package/types/vue-shim.d +0 -20
@@ -6,7 +6,7 @@ import { BOTH, TYPE_MODES } from '@shell/store/type-map';
6
6
  import { COUNT } from '@shell/config/types';
7
7
 
8
8
  export default {
9
- emits: ['closeSearch'],
9
+ emits: ['close'],
10
10
 
11
11
  components: { Group },
12
12
 
@@ -41,7 +41,7 @@ export default {
41
41
  const allTypes = allTypesByMode[TYPE_MODES.ALL];
42
42
  const out = this.$store.getters['type-map/getTree'](productId, TYPE_MODES.ALL, allTypes, clusterId, BOTH, null, this.value);
43
43
 
44
- // Suplement the output with count info. Usualy the `Type` component would handle this individualy... but scales real bad so give it
44
+ // Supplement the output with count info. Usually the `Type` component would handle this individually... but scales real bad so give it
45
45
  // some help
46
46
  const counts = this.$store.getters[`${ product.inStore }/all`](COUNT)?.[0]?.counts || {};
47
47
 
@@ -77,16 +77,22 @@ export default {
77
77
  >
78
78
  {{ t('nav.resourceSearch.filteringDescription') }}
79
79
  </p>
80
- <input
81
- ref="input"
82
- v-model="value"
83
- :placeholder="t('nav.resourceSearch.placeholder')"
84
- class="search"
85
- role="textbox"
86
- :aria-label="t('nav.resourceSearch.label')"
87
- aria-describedby="describe-filter-resource-search"
88
- @keyup.esc="$emit('closeSearch')"
89
- >
80
+ <div class="dialog-title">
81
+ <div>{{ t('nav.resourceSearch.label') }}</div>
82
+ <p>{{ t('nav.resourceSearch.prompt') }}</p>
83
+ </div>
84
+ <div class="search-box">
85
+ <input
86
+ ref="input"
87
+ v-model="value"
88
+ :placeholder="t('nav.resourceSearch.placeholder')"
89
+ class="search"
90
+ role="textbox"
91
+ :aria-label="t('nav.resourceSearch.label')"
92
+ aria-describedby="describe-filter-resource-search"
93
+ @keyup.esc="$emit('close')"
94
+ >
95
+ </div>
90
96
  <div class="results">
91
97
  <div
92
98
  v-for="g in groups"
@@ -100,7 +106,7 @@ export default {
100
106
  :group="g"
101
107
  :can-collapse="false"
102
108
  :fixed-open="true"
103
- @close="$emit('closeSearch')"
109
+ @close="$emit('close')"
104
110
  >
105
111
  <template #accordion>
106
112
  <h6>{{ g.label }}</h6>
@@ -119,17 +125,31 @@ export default {
119
125
  box-shadow: none;
120
126
  }
121
127
 
128
+ .search-box {
129
+ margin: 8px;
130
+ }
131
+
122
132
  .search:focus-visible {
123
133
  outline-offset: -2px;
124
134
  }
125
135
 
136
+ .dialog-title {
137
+ padding: 8px;
138
+
139
+ > div {
140
+ font-size: 16px;
141
+ font-weight: bold;
142
+ margin: 8px 0;
143
+ }
144
+ }
145
+
126
146
  .results {
127
147
  margin-top: -1px;
128
148
  overflow-y: auto;
129
149
  padding: 10px;
130
150
  color: var(--dropdown-text);
131
151
  background-color: var(--dropdown-bg);
132
- border: 1px solid var(--dropdown-border);
152
+ border-top: 1px solid var(--dropdown-border);
133
153
  height: 75vh;
134
154
  }
135
155
  </style>
@@ -2,47 +2,70 @@
2
2
  import { mapGetters } from 'vuex';
3
3
 
4
4
  import AsyncButton from '@shell/components/AsyncButton';
5
- import AppModal from '@shell/components/AppModal.vue';
6
5
  import { CATALOG } from '@shell/config/types';
7
6
  import { UI_PLUGIN_NAMESPACE } from '@shell/config/uiplugins';
8
7
 
9
8
  export default {
10
- emits: ['closed', 'update'],
11
-
12
- components: {
13
- AsyncButton,
14
- AppModal,
9
+ emits: ['close'],
10
+
11
+ components: { AsyncButton },
12
+
13
+ props: {
14
+ /**
15
+ * Plugin object
16
+ */
17
+ plugin: {
18
+ type: Object,
19
+ default: () => {},
20
+ required: true
21
+ },
22
+ /**
23
+ * Callback to update install status on extensions main screen
24
+ */
25
+ updateStatus: {
26
+ type: Function,
27
+ default: () => {},
28
+ required: true
29
+ },
30
+ /**
31
+ * Callback when modal is closed
32
+ */
33
+ closed: {
34
+ type: Function,
35
+ default: () => {},
36
+ required: true
37
+ },
38
+ resources: {
39
+ type: Array,
40
+ default: () => []
41
+ },
42
+ registerBackgroundClosing: {
43
+ type: Function,
44
+ default: () => {}
45
+ }
15
46
  },
16
47
 
17
48
  data() {
18
- return {
19
- plugin: undefined, busy: false, showModal: false
20
- };
49
+ return { busy: false };
21
50
  },
22
51
 
23
- computed: {
24
- ...mapGetters({ allCharts: 'catalog/charts' }),
25
- returnFocusSelector() {
26
- return `[data-testid="extension-card-uninstall-btn-${ this.plugin?.name }"]`;
27
- }
28
- },
52
+ computed: { ...mapGetters({ allCharts: 'catalog/charts' }) },
29
53
 
30
54
  methods: {
31
55
  showDialog(plugin) {
32
56
  this.plugin = plugin;
33
57
  this.busy = false;
34
- this.showModal = true;
35
58
  },
36
59
  closeDialog(result) {
37
- this.showModal = false;
38
- this.$emit('closed', result);
60
+ this.closed(result);
61
+ this.$emit('close');
39
62
  },
40
63
  async uninstall() {
41
64
  this.busy = true;
42
65
 
43
66
  const plugin = this.plugin;
44
67
 
45
- this.$emit('update', plugin.name, 'uninstall');
68
+ this.updateStatus(plugin.name, 'uninstall');
46
69
 
47
70
  // Delete the CR if this is a developer plugin (there is no Helm App, so need to remove the CRD ourselves)
48
71
  if (plugin.uiplugin?.isDeveloper) {
@@ -78,47 +101,33 @@ export default {
78
101
  </script>
79
102
 
80
103
  <template>
81
- <app-modal
82
- v-if="showModal"
83
- name="uninstallPluginDialog"
84
- height="auto"
85
- :scrollable="true"
86
- :trigger-focus-trap="true"
87
- :return-focus-selector="returnFocusSelector"
88
- :return-focus-first-iterable-node-selector="'#extensions-main-page'"
89
- @close="closeDialog(false)"
90
- >
91
- <div
92
- v-if="plugin"
93
- class="plugin-install-dialog"
94
- >
95
- <h4 class="mt-10">
96
- {{ t('plugins.uninstall.title', { name: plugin.label }) }}
97
- </h4>
98
- <div class="mt-10 dialog-panel">
99
- <div class="dialog-info">
100
- <p>
101
- {{ t('plugins.uninstall.prompt') }}
102
- </p>
103
- </div>
104
- <div class="dialog-buttons">
105
- <button
106
- :disabled="busy"
107
- class="btn role-secondary"
108
- data-testid="uninstall-ext-modal-cancel-btn"
109
- @click="closeDialog(false)"
110
- >
111
- {{ t('generic.cancel') }}
112
- </button>
113
- <AsyncButton
114
- mode="uninstall"
115
- data-testid="uninstall-ext-modal-uninstall-btn"
116
- @click="uninstall()"
117
- />
118
- </div>
104
+ <div class="plugin-install-dialog">
105
+ <h4 class="mt-10">
106
+ {{ t('plugins.uninstall.title', { name: plugin?.label }) }}
107
+ </h4>
108
+ <div class="mt-10 dialog-panel">
109
+ <div class="dialog-info">
110
+ <p>
111
+ {{ t('plugins.uninstall.prompt') }}
112
+ </p>
113
+ </div>
114
+ <div class="dialog-buttons">
115
+ <button
116
+ :disabled="busy"
117
+ class="btn role-secondary"
118
+ data-testid="uninstall-ext-modal-cancel-btn"
119
+ @click="closeDialog(false)"
120
+ >
121
+ {{ t('generic.cancel') }}
122
+ </button>
123
+ <AsyncButton
124
+ mode="uninstall"
125
+ data-testid="uninstall-ext-modal-uninstall-btn"
126
+ @click="uninstall()"
127
+ />
119
128
  </div>
120
129
  </div>
121
- </app-modal>
130
+ </div>
122
131
  </template>
123
132
 
124
133
  <style lang="scss" scoped>
@@ -0,0 +1,57 @@
1
+ <script>
2
+ // i18n-ignore footer.wechat.modalText, footer.wechat.modalText2
3
+ export default {
4
+ emits: ['close'],
5
+
6
+ name: 'WechatModal',
7
+
8
+ methods: {
9
+ close() {
10
+ this.$emit('close');
11
+ }
12
+ },
13
+ };
14
+ </script>
15
+
16
+ <template>
17
+ <div class="wechat-modal">
18
+ <h1>{{ t('footer.wechat.modalText') }}</h1>
19
+ <h1>{{ t('footer.wechat.modalText2') }}</h1>
20
+ <div class="qr-img" />
21
+ <div>
22
+ <button
23
+ class="btn role-primary"
24
+ tabindex="0"
25
+ :aria-label="t('generic.close')"
26
+ role="button"
27
+ @click="close"
28
+ @keydown.enter.stop
29
+ >
30
+ {{ t('generic.close') }}
31
+ </button>
32
+ </div>
33
+ </div>
34
+ </template>
35
+
36
+ <style lang='scss' scoped>
37
+ .wechat-modal {
38
+ margin: 60px;
39
+ display: flex;
40
+ flex-direction: column;
41
+ align-items: center;
42
+ }
43
+
44
+ .btn {
45
+ margin: 20px auto 0;
46
+ }
47
+
48
+ .qr-img {
49
+ background-image: url('../assets/images/wechat-qr-code.jpg');
50
+ background-repeat: no-repeat;
51
+ background-size: cover;
52
+ background-position: center center;
53
+ height: 128px;
54
+ width: 128px;
55
+ margin: 15px auto 10px;
56
+ }
57
+ </style>
@@ -2,14 +2,23 @@ import { mount } from '@vue/test-utils';
2
2
  import FormValidation from '@shell/mixins/form-validation';
3
3
  import Monitoring from '@shell/edit/monitoring.coreos.com.prometheusrule/index.vue';
4
4
  import { _EDIT } from '@shell/config/query-params';
5
+ import { createStore } from 'vuex';
5
6
 
6
7
  describe('edit: management.cattle.io.setting should', () => {
7
8
  const MOCKED_ERRORS = ['error1', 'error2', 'error3', 'error4', 'error5'];
8
9
  const ERROR_BANNER_SELECTOR = '[data-testid="banner-close"]';
10
+ const store = createStore({
11
+ getters: {
12
+ namespaces: () => () => ({}),
13
+ currentStore: () => () => 'current_store',
14
+ 'current_store/schemaFor': () => jest.fn()
15
+ }
16
+ });
9
17
  const requiredSetup = () => ({
10
18
  // Remove all these mocks after migration to Vue 2.7/3 due mixin logic
11
19
  global: {
12
- mocks: {
20
+ provide: { store },
21
+ mocks: {
13
22
  $store: {
14
23
  dispatch: jest.fn(),
15
24
  getters: {
@@ -35,8 +44,12 @@ describe('edit: management.cattle.io.setting should', () => {
35
44
  canYaml: false,
36
45
  mode: _EDIT,
37
46
  resource: {},
38
- value: { value: 'anything' },
39
- name: ''
47
+ value: {
48
+ setAnnotation: jest.fn(),
49
+ value: 'anything',
50
+ metadata: {},
51
+ },
52
+ name: ''
40
53
  },
41
54
  ...requiredSetup()
42
55
  });
@@ -32,151 +32,194 @@ const mockModel = {
32
32
  };
33
33
 
34
34
  describe('oidc.vue', () => {
35
- let wrapper: VueWrapper<any, any>;
36
- const requiredSetup = () => ({
37
- data() {
38
- return {
39
- isEnabling: false,
40
- editConfig: false,
41
- model: { ...mockModel },
42
- serverSetting: null,
43
- errors: [],
44
- originalModel: null,
45
- principals: [],
46
- authConfigName: 'oidc',
47
- } as any; // any is necessary as in pre-existing tests we are including inherited mixins values
48
- },
49
- global: {
50
- mocks: {
51
- $fetchState: { pending: false },
52
- $store: {
53
- getters: {
54
- currentStore: () => 'current_store',
55
- 'current_store/schemaFor': jest.fn(),
56
- 'current_store/all': jest.fn(),
57
- 'i18n/t': (val: string) => val,
58
- 'i18n/exists': jest.fn(),
35
+ describe('given default valid values', () => {
36
+ let wrapper: VueWrapper<any, any>;
37
+ const requiredSetup = () => ({
38
+ data() {
39
+ return {
40
+ isEnabling: false,
41
+ editConfig: false,
42
+ model: { ...mockModel },
43
+ serverSetting: null,
44
+ errors: [],
45
+ originalModel: null,
46
+ principals: [],
47
+ authConfigName: 'oidc',
48
+ } as any; // any is necessary as in pre-existing tests we are including inherited mixins values
49
+ },
50
+ global: {
51
+ mocks: {
52
+ $fetchState: { pending: false },
53
+ $store: {
54
+ getters: {
55
+ currentStore: () => 'current_store',
56
+ 'current_store/schemaFor': jest.fn(),
57
+ 'current_store/all': jest.fn(),
58
+ 'i18n/t': (val: string) => val,
59
+ 'i18n/exists': jest.fn(),
60
+ },
61
+ dispatch: jest.fn()
59
62
  },
60
- dispatch: jest.fn()
63
+ $route: { query: { AS: '' }, params: { id: 'oicd' } },
64
+ $router: { applyQuery: jest.fn() },
61
65
  },
62
- $route: { query: { AS: '' }, params: { id: 'oicd' } },
63
- $router: { applyQuery: jest.fn() },
64
66
  },
65
- },
66
- props: {
67
- value: { applicationSecret: '' },
68
- mode: _EDIT,
69
- },
70
- });
67
+ props: {
68
+ value: { applicationSecret: '' },
69
+ mode: _EDIT,
70
+ },
71
+ });
71
72
 
72
- beforeEach(() => {
73
- wrapper = mount(oidc, { ...requiredSetup() });
74
- });
75
- afterEach(() => {
76
- wrapper.unmount();
77
- });
73
+ beforeEach(() => {
74
+ wrapper = mount(oidc, { ...requiredSetup() });
75
+ });
78
76
 
79
- it('have "Create" button enabled when provider is enabled and not editing config', async() => {
80
- wrapper.setData({ model: { enabled: true }, editConfig: false });
81
- await nextTick();
77
+ afterEach(() => {
78
+ wrapper.unmount();
79
+ });
82
80
 
83
- const saveButton = wrapper.find('[data-testid="form-save"]').element as HTMLInputElement;
81
+ describe('have "Create" button disabled', () => {
82
+ it('given missing Auth endpoint URL', () => {
83
+ wrapper.vm.model.authEndpoint = '';
84
+ wrapper.vm.model.scopes = 'openid profile email'; // set scope to be sure
85
+ wrapper.vm.oidcScope = ['openid', 'profile', 'email']; // TODO #13457: this is duplicated due wrong format of scopes
84
86
 
85
- expect(saveButton.disabled).toBe(false);
86
- });
87
+ const saveButton = wrapper.find('[data-testid="form-save"]').element as HTMLInputElement;
87
88
 
88
- it('have "Create" button disabled when provider is disabled and editing config before fields are filled in', async() => {
89
- wrapper.setData({ model: {}, editConfig: true });
90
- await nextTick();
89
+ expect(saveButton.disabled).toBe(true);
90
+ });
91
91
 
92
- const saveButton = wrapper.find('[data-testid="form-save"]').element as HTMLInputElement;
92
+ it('given missing required basic scopes', () => {
93
+ wrapper.vm.model.authEndpoint = 'whatever'; // set auth endpoint to be sure
94
+ wrapper.vm.model.scopes = 'something else'; // set wrong scope
95
+ wrapper.vm.oidcScope = ['something', 'else']; // TODO #13457: this is duplicated due wrong format of scopes
93
96
 
94
- expect(saveButton.disabled).toBe(true);
95
- });
97
+ const saveButton = wrapper.find('[data-testid="form-save"]').element as HTMLInputElement;
96
98
 
97
- it('have "Create" button disabled when provider is disabled and editing config after required fields and scope is missing openid', async() => {
98
- wrapper.setData({ oidcUrls: { url: validUrl, realm: validRealm } });
99
- await nextTick();
99
+ expect(saveButton.disabled).toBe(true);
100
+ });
100
101
 
101
- const saveButton = wrapper.find('[data-testid="form-save"]').element as HTMLInputElement;
102
+ it('when provider is disabled and editing config before fields are filled in', async() => {
103
+ wrapper.setData({ model: {}, editConfig: true });
104
+ await nextTick();
102
105
 
103
- expect(saveButton.disabled).toBe(true);
104
- });
106
+ const saveButton = wrapper.find('[data-testid="form-save"]').element as HTMLInputElement;
105
107
 
106
- it('have "Create" button enabled when customEndpoint is disabled and required fields are filled in', async() => {
107
- wrapper.setData({ oidcUrls: { url: validUrl, realm: validRealm }, oidcScope: validScope.split(' ') });
108
- await nextTick();
108
+ expect(saveButton.disabled).toBe(true);
109
+ });
109
110
 
110
- const saveButton = wrapper.find('[data-testid="form-save"]').element as HTMLInputElement;
111
+ it('when provider is disabled and editing config after required fields and scope is missing openid', async() => {
112
+ wrapper.setData({ oidcUrls: { url: validUrl, realm: validRealm } });
113
+ await nextTick();
111
114
 
112
- expect(saveButton.disabled).toBe(false);
113
- });
115
+ const saveButton = wrapper.find('[data-testid="form-save"]').element as HTMLInputElement;
114
116
 
115
- it('have "Create" button enabled when customEndpoint is enabled and required fields are filled in', async() => {
116
- wrapper.setData({ customEndpoint: { value: true }, oidcScope: validScope.split(' ') });
117
- await nextTick();
117
+ expect(saveButton.disabled).toBe(true);
118
+ });
119
+ });
118
120
 
119
- const saveButton = wrapper.find('[data-testid="form-save"]').element as HTMLInputElement;
121
+ describe('have "Create" button enabled', () => {
122
+ it('when customEndpoint is disabled and required fields are filled in', async() => {
123
+ wrapper.setData({ oidcUrls: { url: validUrl, realm: validRealm }, oidcScope: validScope.split(' ') });
124
+ await nextTick();
120
125
 
121
- expect(saveButton.disabled).toBe(false);
122
- });
126
+ const saveButton = wrapper.find('[data-testid="form-save"]').element as HTMLInputElement;
123
127
 
124
- it('updates issuer endpoint when oidcUrls.url and oidcUrls.realm changes', async() => {
125
- wrapper.setData({ oidcUrls: { url: validUrl } });
126
- await nextTick();
128
+ expect(saveButton.disabled).toBe(false);
129
+ });
127
130
 
128
- expect(wrapper.vm.model.issuer).toBe(`${ validUrl }/realms/`);
131
+ it('when customEndpoint is enabled and required fields are filled in', async() => {
132
+ wrapper.setData({ customEndpoint: { value: true }, oidcScope: validScope.split(' ') });
133
+ await nextTick();
129
134
 
130
- wrapper.setData({ oidcUrls: { realm: validRealm } });
131
- await nextTick();
135
+ const saveButton = wrapper.find('[data-testid="form-save"]').element as HTMLInputElement;
132
136
 
133
- expect(wrapper.vm.model.issuer).toBe(`${ validUrl }/realms/${ validRealm }`);
134
- });
137
+ expect(saveButton.disabled).toBe(false);
138
+ });
135
139
 
136
- it('`groupSearchEnabled` defaults to false', async() => {
137
- const groupSearchCheckbox = wrapper.getComponent('[data-testid="input-group-search"]');
140
+ it('when provider is enabled and not editing config', async() => {
141
+ wrapper.setData({ model: { enabled: true }, editConfig: false });
142
+ await nextTick();
138
143
 
139
- expect(groupSearchCheckbox.isVisible()).toBe(true);
140
- expect(wrapper.vm.model.groupSearchEnabled).toBe(false);
141
- });
144
+ const saveButton = wrapper.find('[data-testid="form-save"]').element as HTMLInputElement;
142
145
 
143
- it('`groupSearchEnabled` updates when checkbox is clicked', async() => {
144
- const groupSearchCheckbox = wrapper.getComponent('[data-testid="input-group-search"]');
146
+ expect(saveButton.disabled).toBe(false);
147
+ });
148
+ });
145
149
 
146
- await groupSearchCheckbox.find('[role="checkbox"]').trigger('click');
150
+ it('updates issuer endpoint when oidcUrls.url and oidcUrls.realm changes', async() => {
151
+ wrapper.setData({ oidcUrls: { url: validUrl } });
152
+ await nextTick();
147
153
 
148
- expect(groupSearchCheckbox.isVisible()).toBe(true);
149
- expect(wrapper.vm.model.groupSearchEnabled).toBe(true);
150
- });
154
+ expect(wrapper.vm.model.issuer).toBe(`${ validUrl }/realms/`);
151
155
 
152
- it('changing URL should update issuer and auth-endpoint if Keycloak', async() => {
153
- wrapper.vm.model.id = 'keycloakoidc';
154
- const newUrl = 'whatever';
156
+ wrapper.setData({ oidcUrls: { realm: validRealm } });
157
+ await nextTick();
155
158
 
156
- await wrapper.find(`[data-testid="oidc-url"]`).setValue(newUrl);
157
- await wrapper.vm.$nextTick();
159
+ expect(wrapper.vm.model.issuer).toBe(`${ validUrl }/realms/${ validRealm }`);
160
+ });
158
161
 
159
- const issuer = (wrapper.find('[data-testid="oidc-issuer"]').element as HTMLInputElement).value;
160
- const endpoint = (wrapper.find('[data-testid="oidc-auth-endpoint"]').element as HTMLInputElement).value;
162
+ it('`groupSearchEnabled` defaults to false', async() => {
163
+ const groupSearchCheckbox = wrapper.getComponent('[data-testid="input-group-search"]');
161
164
 
162
- expect(issuer).toBe(`${ newUrl }/realms/`);
163
- expect(endpoint).toBe(`${ newUrl }/realms//protocol/openid-connect/auth`);
164
- });
165
+ expect(groupSearchCheckbox.isVisible()).toBe(true);
166
+ expect(wrapper.vm.model.groupSearchEnabled).toBe(false);
167
+ });
168
+
169
+ it('`groupSearchEnabled` updates when checkbox is clicked', async() => {
170
+ const groupSearchCheckbox = wrapper.getComponent('[data-testid="input-group-search"]');
171
+
172
+ await groupSearchCheckbox.find('[role="checkbox"]').trigger('click');
173
+
174
+ expect(groupSearchCheckbox.isVisible()).toBe(true);
175
+ expect(wrapper.vm.model.groupSearchEnabled).toBe(true);
176
+ });
177
+
178
+ it('changing URL should update issuer and auth-endpoint if Keycloak', async() => {
179
+ wrapper.vm.model.id = 'keycloakoidc';
180
+ const newUrl = 'whatever';
181
+
182
+ await wrapper.find(`[data-testid="oidc-url"]`).setValue(newUrl);
183
+ await wrapper.vm.$nextTick();
184
+
185
+ const issuerValue = (wrapper.find('[data-testid="oidc-issuer"]').element as HTMLInputElement).value;
186
+ const endpointValue = (wrapper.find('[data-testid="oidc-auth-endpoint"]').element as HTMLInputElement).value;
187
+
188
+ expect(issuerValue).toBe(`${ newUrl }/realms/`);
189
+ expect(endpointValue).toBe(`${ newUrl }/realms//protocol/openid-connect/auth`);
190
+ });
191
+
192
+ it('changing realm should update issuer and auth-endpoint if Keycloak', async() => {
193
+ const newRealm = 'newRealm';
194
+ const oldUrl = 'oldUrl';
195
+
196
+ wrapper.vm.model.id = 'keycloakoidc';
197
+ wrapper.vm.oidcUrls.url = oldUrl;
198
+
199
+ await wrapper.find(`[data-testid="oidc-realm"]`).setValue(newRealm);
200
+ await wrapper.vm.$nextTick();
165
201
 
166
- it('changing realm should update issuer and auth-endpoint if Keycloak', async() => {
167
- const newRealm = 'newRealm';
168
- const oldUrl = 'oldUrl';
202
+ const issuerValue = (wrapper.find('[data-testid="oidc-issuer"]').element as HTMLInputElement).value;
203
+ const endpointValue = (wrapper.find('[data-testid="oidc-auth-endpoint"]').element as HTMLInputElement).value;
169
204
 
170
- wrapper.vm.model.id = 'keycloakoidc';
171
- wrapper.vm.oidcUrls.url = oldUrl;
205
+ expect(issuerValue).toBe(`${ oldUrl }/realms/${ newRealm }`);
206
+ expect(endpointValue).toBe(`${ oldUrl }/realms/${ newRealm }/protocol/openid-connect/auth`);
207
+ });
172
208
 
173
- await wrapper.find(`[data-testid="oidc-realm"]`).setValue(newRealm);
174
- await wrapper.vm.$nextTick();
209
+ it('clear URL should clear issuer and auth-endpoint if Keycloak', async() => {
210
+ wrapper.vm.model.id = 'keycloakoidc';
211
+ const newUrl = 'whatever';
212
+ const urlInput = wrapper.find(`[data-testid="oidc-url"]`);
175
213
 
176
- const issuer = (wrapper.find('[data-testid="oidc-issuer"]').element as HTMLInputElement).value;
177
- const endpoint = (wrapper.find('[data-testid="oidc-auth-endpoint"]').element as HTMLInputElement).value;
214
+ await urlInput.setValue(newUrl);
215
+ await wrapper.vm.$nextTick();
216
+ await urlInput.setValue('');
217
+ await wrapper.vm.$nextTick();
218
+ const issuer = (wrapper.find('[data-testid="oidc-issuer"]').element as HTMLInputElement).value;
219
+ const endpoint = (wrapper.find('[data-testid="oidc-auth-endpoint"]').element as HTMLInputElement).value;
178
220
 
179
- expect(issuer).toBe(`${ oldUrl }/realms/${ newRealm }`);
180
- expect(endpoint).toBe(`${ oldUrl }/realms/${ newRealm }/protocol/openid-connect/auth`);
221
+ expect(issuer).toBe('');
222
+ expect(endpoint).toBe('');
223
+ });
181
224
  });
182
225
  });