From d0c3fb2407316c5a57688c71e1110c947af75837 Mon Sep 17 00:00:00 2001 From: Richard Cox Date: Thu, 1 Feb 2024 15:40:17 +0000 Subject: [PATCH 01/71] Changes for new design - New visuals - Pagination controls --> load more - finished testing of label select with pagination off # Conflicts: # shell/edit/provisioning.cattle.io.cluster/__tests__/Basics.tests.ts --- pkg/aks/components/AksNodePool.vue | 2 +- pkg/aks/components/CruAks.vue | 2 +- shell/assets/styles/themes/_dark.scss | 3 +- shell/assets/styles/themes/_light.scss | 1 + shell/assets/styles/vendor/vue-select.scss | 5 + shell/assets/translations/en-us.yaml | 7 + shell/chart/rancher-backup/S3.vue | 76 +++++++- shell/chart/rancher-backup/index.vue | 11 +- shell/components/PodSecurityAdmission.vue | 2 +- shell/components/PromptRestore.vue | 2 +- shell/components/form/GitPicker.vue | 2 +- .../form/LabeledSelect/LabeledSelect.utils.ts | 1 + .../index.vue} | 163 +++++++++++++++--- .../labeled-select-pagination.ts | 134 ++++++++++++++ .../form/__tests__/LabeledSelect.test.ts | 2 +- .../hpa-scaling-rule.vue | 2 +- .../__tests__/Basics.test.ts | 2 +- shell/edit/ui.cattle.io.navlink.vue | 2 +- shell/plugins/steve/getters.js | 34 ++++ .../stories/InputFieldsAdvancedExample.vue | 2 +- storybook/stories/InputFieldsExample.vue | 2 +- 21 files changed, 415 insertions(+), 42 deletions(-) create mode 100644 shell/components/form/LabeledSelect/LabeledSelect.utils.ts rename shell/components/form/{LabeledSelect.vue => LabeledSelect/index.vue} (75%) create mode 100644 shell/components/form/LabeledSelect/labeled-select-pagination.ts diff --git a/pkg/aks/components/AksNodePool.vue b/pkg/aks/components/AksNodePool.vue index c1cbe552d2..49ab6a429c 100644 --- a/pkg/aks/components/AksNodePool.vue +++ b/pkg/aks/components/AksNodePool.vue @@ -5,7 +5,7 @@ import { mapGetters } from 'vuex'; import { _CREATE, _VIEW } from '@shell/config/query-params'; import type { AKSDiskType, AKSNodePool, AKSPoolMode } from '../types/index'; import LabeledInput from '@components/Form/LabeledInput/LabeledInput.vue'; -import LabeledSelect from '@shell/components/form/LabeledSelect.vue'; +import LabeledSelect from '@shell/components/form/LabeledSelect/index.vue'; import Taint from '@pkg/aks/components/Taint.vue'; import UnitInput from '@shell/components/form/UnitInput.vue'; import RadioGroup from '@components/Form/Radio/RadioGroup.vue'; diff --git a/pkg/aks/components/CruAks.vue b/pkg/aks/components/CruAks.vue index d3c51809a0..9ae3bf540d 100644 --- a/pkg/aks/components/CruAks.vue +++ b/pkg/aks/components/CruAks.vue @@ -16,7 +16,7 @@ import CreateEditView from '@shell/mixins/create-edit-view'; import FormValidation from '@shell/mixins/form-validation'; import SelectCredential from '@shell/edit/provisioning.cattle.io.cluster/SelectCredential.vue'; import CruResource from '@shell/components/CruResource.vue'; -import LabeledSelect from '@shell/components/form/LabeledSelect.vue'; +import LabeledSelect from '@shell/components/form/LabeledSelect/index.vue'; import LabeledInput from '@components/Form/LabeledInput/LabeledInput.vue'; import Checkbox from '@components/Form/Checkbox/Checkbox.vue'; import FileSelector from '@shell/components/form/FileSelector.vue'; diff --git a/shell/assets/styles/themes/_dark.scss b/shell/assets/styles/themes/_dark.scss index b867584863..a0e821c8f6 100644 --- a/shell/assets/styles/themes/_dark.scss +++ b/shell/assets/styles/themes/_dark.scss @@ -107,7 +107,8 @@ --dropdown-hover-bg : var(--link); --dropdown-disabled-bg : #{$disabled}; --dropdown-disabled-text : #{$disabled}; - --dropdown-highlight-text : var(--link); + --dropdown-group-text : #{$disabled}; + --dropdown-highlight-text : var(--link); --input-text : #{$lightest}; --input-label : #{$lighter}; diff --git a/shell/assets/styles/themes/_light.scss b/shell/assets/styles/themes/_light.scss index 457393810d..387d1abf8b 100644 --- a/shell/assets/styles/themes/_light.scss +++ b/shell/assets/styles/themes/_light.scss @@ -376,6 +376,7 @@ BODY, .theme-light { --dropdown-hover-bg : var(--link); --dropdown-disabled-text : var(--muted); --dropdown-disabled-bg : #{$disabled}; + --dropdown-group-text : #{$darker}; --dropdown-highlight-text : var(--link); --card-badge-text : #ffffff; diff --git a/shell/assets/styles/vendor/vue-select.scss b/shell/assets/styles/vendor/vue-select.scss index 3d774f82de..4dc95331e7 100644 --- a/shell/assets/styles/vendor/vue-select.scss +++ b/shell/assets/styles/vendor/vue-select.scss @@ -94,6 +94,11 @@ hr { cursor: default; } + + .vs__option-kind-group { + color: var(--dropdown-group-text); + cursor: default; + } } &.vs__dropdown-option--selected { diff --git a/shell/assets/translations/en-us.yaml b/shell/assets/translations/en-us.yaml index 015e7af1a0..6404679109 100644 --- a/shell/assets/translations/en-us.yaml +++ b/shell/assets/translations/en-us.yaml @@ -2759,6 +2759,13 @@ labels: annotations: title: Annotations +labelSelect: + noOptions: + empty: No options + noMatch: No matching options + pagination: + counts: '{count} / {totalCount} items' + more: Load More... landing: clusters: title: Clusters diff --git a/shell/chart/rancher-backup/S3.vue b/shell/chart/rancher-backup/S3.vue index d86a3fc197..6e5c4ffe3a 100644 --- a/shell/chart/rancher-backup/S3.vue +++ b/shell/chart/rancher-backup/S3.vue @@ -4,6 +4,7 @@ import { Checkbox } from '@components/Form/Checkbox'; import FileSelector from '@shell/components/form/FileSelector'; import LabeledSelect from '@shell/components/form/LabeledSelect'; import { mapGetters } from 'vuex'; +import { SECRET } from '@shell/config/types'; export default { components: { @@ -44,6 +45,7 @@ export default { this.$emit('valid', this.valid); } }, + computed: { credentialSecret: { get() { @@ -75,7 +77,75 @@ export default { // eslint-disable-next-line no-console console.warn(e); } - } + }, + + /** + * Given inputs make a paginated request and return the result + */ + async paginateSecrets({ + pageContent, + page, + filter, + pageSize, + resetPage + }) { + try { + // Construct params for request + const filterParam = !!filter ? [{ field: 'metadata.name', value: filter }] : []; + const url = this.$store.getters['cluster/urlFor'](SECRET, null, { + pagination: { + filter: filterParam, + sort: [{ asc: true, field: 'metadata.namespace' }, { asc: true, field: 'metadata.name' }], + page, + pageSize, + } + }); + + // Make request (note we're not bothering to persist anything to the store, response is transient) + const res = await this.$store.dispatch('cluster/request', { url }); + const options = resetPage ? res.data : pageContent.concat(res.data); + + // Create the new option collection by... + const namespaced = {}; + + // ... grouping by namespace + options.forEach((secret) => { + const ns = secret.metadata.namespace; + + if (secret.kind === 'group') { // this could contain a previous option set which contains groups + return; + } + if (!namespaced[ns]) { + namespaced[ns] = []; + } + namespaced[ns].push(secret); + }); + + let grouped = []; + + // ... then sort groups by name and combined into a single array + Object.keys(namespaced).sort().forEach((ns) => { + grouped.push({ + kind: 'group', + icon: 'icon-namespace', + id: ns, + metadata: { name: ns }, + disabled: true, + }); + grouped = grouped.concat(namespaced[ns]); + }); + + return { + page: grouped, + pages: res.pages, + total: res.count + }; + } catch (err) { + console.error(err); // eslint-disable-line no-console + } + + return { page: [] }; + }, }, created() { @@ -97,7 +167,9 @@ export default { :get-option-label="opt=>opt.metadata.name || ''" option-key="id" :mode="mode" - :options="secrets" + :paginate="paginateSecrets" + :searchable="true" + :filterable="false" :label="t('backupRestoreOperator.s3.credentialSecretName')" /> diff --git a/shell/chart/rancher-backup/index.vue b/shell/chart/rancher-backup/index.vue index 7d5a80e12c..b3eb031655 100644 --- a/shell/chart/rancher-backup/index.vue +++ b/shell/chart/rancher-backup/index.vue @@ -7,7 +7,7 @@ import { LabeledInput } from '@components/Form/LabeledInput'; import { Banner } from '@components/Banner'; import { get } from '@shell/utils/object'; import { allHash } from '@shell/utils/promise'; -import { STORAGE_CLASS, SECRET, PV } from '@shell/config/types'; +import { STORAGE_CLASS, PV } from '@shell/config/types'; import { mapGetters } from 'vuex'; import { STORAGE } from '@shell/config/labels-annotations'; @@ -41,10 +41,8 @@ export default { const hash = await allHash({ storageClasses: this.$store.dispatch('cluster/findAll', { type: STORAGE_CLASS }), persistentVolumes: this.$store.dispatch('cluster/findAll', { type: PV }), - secrets: this.$store.dispatch('cluster/findAll', { type: SECRET }), }); - this.secrets = hash.secrets; this.storageClasses = hash.storageClasses; this.persistentVolumes = hash.persistentVolumes; @@ -89,6 +87,12 @@ export default { watch: { storageSource(neu) { + if (!this.value.persistence) { + this.value.persistence = {}; + } + if (!this.value.s3) { + this.value.s3 = {}; + } switch (neu) { case 'pickSC': this.value.persistence.enabled = true; @@ -113,6 +117,7 @@ export default { this.value.s3.enabled = true; break; default: + this.value.persistence.enabled = false; this.value.s3.enabled = false; break; diff --git a/shell/components/PodSecurityAdmission.vue b/shell/components/PodSecurityAdmission.vue index 026133150f..31f69e1f87 100644 --- a/shell/components/PodSecurityAdmission.vue +++ b/shell/components/PodSecurityAdmission.vue @@ -1,7 +1,7 @@