@rancher/shell 0.4.0 → 0.5.0
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.
- package/assets/images/providers/ovhcloudmks.svg +122 -0
- package/assets/images/providers/ovhcloudpubliccloud.svg +122 -0
- package/assets/styles/global/_layout.scss +99 -0
- package/assets/translations/en-us.yaml +30 -5
- package/assets/translations/zh-hans.yaml +1 -1
- package/babel.config.js +7 -1
- package/chart/monitoring/alerting/index.vue +7 -21
- package/chart/monitoring/grafana/index.vue +55 -0
- package/chart/monitoring/index.vue +51 -17
- package/chart/monitoring/prometheus/index.vue +37 -43
- package/chart/rancher-backup/index.vue +2 -1
- package/cloud-credential/azure.vue +4 -17
- package/components/AsyncButton.vue +17 -5
- package/components/Certificates.vue +164 -0
- package/components/CodeMirror.vue +19 -21
- package/components/CruResource.vue +1 -0
- package/components/DraggableZone.vue +2 -2
- package/components/EtcdInfoBanner.vue +1 -1
- package/components/ExplorerProjectsNamespaces.vue +25 -1
- package/components/IconOrSvg.vue +1 -1
- package/components/LandingPagePreference.vue +1 -4
- package/components/PodSecurityAdmission.vue +2 -2
- package/components/Questions/index.vue +1 -1
- package/components/ResourceDetail/Masthead.vue +16 -3
- package/components/ResourceTable.vue +14 -2
- package/components/ResourceYaml.vue +5 -0
- package/components/SideNav.vue +1 -1
- package/components/SingleClusterInfo.vue +1 -4
- package/components/Tabbed/index.vue +12 -0
- package/components/fleet/FleetRepos.vue +62 -27
- package/components/fleet/FleetResources.vue +6 -1
- package/components/form/ArrayListSelect.vue +10 -0
- package/components/form/Error.vue +3 -3
- package/components/form/Footer.vue +2 -2
- package/components/form/GitPicker.vue +83 -38
- package/components/form/KeyValue.vue +4 -0
- package/components/form/LabeledSelect.vue +4 -0
- package/components/formatter/Checked.vue +11 -3
- package/components/formatter/FleetClusterSummaryGraph.vue +27 -0
- package/components/formatter/FleetSummaryGraph.vue +23 -11
- package/components/formatter/LiveDuration.vue +1 -1
- package/components/formatter/PercentageBar.vue +1 -1
- package/components/formatter/__tests__/Checked.test.ts +19 -0
- package/components/nav/Group.vue +2 -2
- package/components/nav/Header.vue +0 -1
- package/components/nav/TopLevelMenu.vue +36 -6
- package/components/nav/Type.vue +1 -3
- package/components/nav/WindowManager/ContainerLogs.vue +101 -3
- package/components/nav/WindowManager/ContainerShell.vue +6 -1
- package/components/nav/WindowManager/__tests__/ContainerLogs.test.ts +186 -0
- package/components/nav/WindowManager/index.vue +11 -10
- package/components/nav/__tests__/TopLevelMenu.test.ts +33 -0
- package/components/nav/__tests__/Type.test.ts +1 -1
- package/components/nuxt/nuxt-child.js +14 -78
- package/components/nuxt/nuxt.js +1 -1
- package/{layouts → components/templates}/blank.vue +1 -1
- package/{layouts → components/templates}/default.vue +8 -98
- package/{layouts → components/templates}/error.vue +10 -19
- package/{layouts → components/templates}/home.vue +4 -1
- package/{layouts → components/templates}/plain.vue +4 -1
- package/{layouts → components/templates}/standalone.vue +1 -1
- package/{layouts → components/templates}/unauthenticated.vue +1 -1
- package/composables/useCompactInput.test.ts +36 -0
- package/composables/useCompactInput.ts +20 -0
- package/composables/useLabeledFormElement.test.ts +135 -0
- package/composables/useLabeledFormElement.ts +138 -0
- package/config/harvester-manager-types.js +2 -0
- package/config/private-label.js +22 -0
- package/config/product/explorer.js +3 -0
- package/config/product/fleet.js +6 -1
- package/config/product/manager.js +8 -2
- package/config/query-params.js +1 -0
- package/config/router.js +385 -364
- package/config/settings.ts +1 -0
- package/config/store.js +1 -1
- package/config/system-namespaces.js +3 -0
- package/config/table-headers.js +47 -0
- package/core/plugin-routes.ts +56 -114
- package/core/plugin.ts +16 -10
- package/core/plugins-loader.js +7 -9
- package/core/plugins.js +0 -3
- package/creators/app/files/.gitlab-ci.yml +1 -1
- package/detail/fleet.cattle.io.cluster.vue +11 -1
- package/detail/provisioning.cattle.io.cluster.vue +4 -3
- package/dialog/ScaleMachineDownDialog.vue +34 -17
- package/edit/__tests__/service.test.ts +89 -0
- package/edit/auth/googleoauth.vue +1 -5
- package/edit/cloudcredential.vue +2 -0
- package/edit/configmap.vue +2 -1
- package/edit/management.cattle.io.podsecurityadmissionconfigurationtemplate.vue +2 -2
- package/edit/networking.k8s.io.networkpolicy/__tests__/PolicyRuleTarget.spec.ts +1 -1
- package/edit/provisioning.cattle.io.cluster/SelectCredential.vue +15 -7
- package/edit/provisioning.cattle.io.cluster/__tests__/Advanced.test.ts +112 -0
- package/edit/provisioning.cattle.io.cluster/__tests__/Basics.test.ts +473 -0
- package/edit/provisioning.cattle.io.cluster/__tests__/{CustomCommand.tests.ts → CustomCommand.test.ts} +4 -0
- package/edit/provisioning.cattle.io.cluster/__tests__/DrainOptions.test.ts +1 -1
- package/edit/provisioning.cattle.io.cluster/__tests__/index.test.ts +73 -0
- package/edit/provisioning.cattle.io.cluster/__tests__/rke2.test.ts +7 -1
- package/edit/provisioning.cattle.io.cluster/__tests__/utils/cluster.ts +386 -0
- package/edit/provisioning.cattle.io.cluster/import.vue +2 -2
- package/edit/provisioning.cattle.io.cluster/index.vue +92 -36
- package/edit/provisioning.cattle.io.cluster/rke2.vue +171 -583
- package/edit/provisioning.cattle.io.cluster/tabs/AddOnConfig.vue +137 -0
- package/edit/provisioning.cattle.io.cluster/tabs/Advanced.vue +157 -0
- package/edit/provisioning.cattle.io.cluster/{Basics.vue → tabs/Basics.vue} +94 -19
- package/edit/provisioning.cattle.io.cluster/{MachinePool.vue → tabs/MachinePool.vue} +1 -0
- package/edit/provisioning.cattle.io.cluster/tabs/etcd/index.vue +135 -0
- package/edit/provisioning.cattle.io.cluster/tabs/networking/index.vue +189 -0
- package/edit/provisioning.cattle.io.cluster/tabs/registries/index.vue +144 -0
- package/edit/provisioning.cattle.io.cluster/tabs/upgrade/index.vue +76 -0
- package/edit/service.vue +12 -0
- package/edit/workload/mixins/workload.js +1 -1
- package/initialize/App.js +25 -71
- package/initialize/client.js +21 -162
- package/initialize/index.js +27 -123
- package/list/management.cattle.io.feature.vue +1 -7
- package/list/node.vue +1 -0
- package/machine-config/__tests__/vmwarevsphere.test.ts +100 -21
- package/machine-config/vmwarevsphere.vue +73 -51
- package/middleware/authenticated.js +10 -17
- package/mixins/auth-config.js +2 -7
- package/mixins/brand.js +29 -41
- package/mixins/create-edit-view/index.js +2 -2
- package/mixins/labeled-form-element.ts +6 -1
- package/models/__tests__/management.cattle.io.node.ts +85 -0
- package/models/__tests__/management.cattle.io.nodepool.ts +83 -0
- package/models/__tests__/namespace.test.ts +49 -9
- package/models/__tests__/workload.test.ts +91 -0
- package/models/cluster/node.js +4 -4
- package/models/cluster.x-k8s.io.machinedeployment.js +14 -0
- package/models/fleet.cattle.io.cluster.js +4 -0
- package/models/fleet.cattle.io.gitrepo.js +56 -13
- package/models/management.cattle.io.kontainerdriver.js +1 -1
- package/models/management.cattle.io.node.js +18 -14
- package/models/management.cattle.io.nodepool.js +17 -0
- package/models/namespace.js +1 -1
- package/models/pod.js +20 -0
- package/models/provisioning.cattle.io.cluster.js +20 -3
- package/models/secret.js +117 -18
- package/models/workload.js +16 -0
- package/models/workload.service.js +18 -0
- package/package.json +10 -9
- package/pages/about.vue +0 -1
- package/pages/account/create-key.vue +0 -1
- package/pages/account/index.vue +0 -1
- package/pages/auth/login.vue +0 -1
- package/pages/auth/logout.vue +0 -2
- package/pages/auth/setup.vue +0 -4
- package/pages/auth/verify.vue +14 -8
- package/pages/c/_cluster/apps/charts/install.vue +4 -4
- package/pages/c/_cluster/apps/index.vue +0 -2
- package/pages/c/_cluster/auth/index.vue +0 -2
- package/pages/c/_cluster/ecm/index.vue +0 -2
- package/pages/c/_cluster/explorer/index.vue +28 -2
- package/pages/c/_cluster/fleet/index.vue +1 -1
- package/pages/c/_cluster/index.vue +0 -2
- package/pages/c/_cluster/settings/banners.vue +0 -2
- package/pages/c/_cluster/settings/brand.vue +0 -2
- package/pages/c/_cluster/settings/index.vue +0 -2
- package/pages/c/_cluster/settings/links.vue +0 -1
- package/pages/c/_cluster/settings/performance.vue +0 -1
- package/pages/c/_cluster/uiplugins/CatalogList/CatalogLoadDialog.vue +2 -1
- package/pages/c/_cluster/uiplugins/CatalogList/index.vue +10 -46
- package/pages/c/_cluster/uiplugins/index.vue +0 -2
- package/pages/diagnostic.vue +1 -2
- package/pages/fail-whale.vue +0 -1
- package/pages/prefs.vue +0 -1
- package/pages/support/index.vue +2 -8
- package/pkg/auto-import.js +1 -1
- package/plugins/axios.js +0 -36
- package/plugins/back-button.js +3 -5
- package/plugins/codemirror-loader.js +1 -1
- package/plugins/codemirror.js +41 -0
- package/plugins/dashboard-store/__tests__/{mutations.spec.ts → mutations.test.ts} +1 -1
- package/plugins/dashboard-store/__tests__/resource-class.test.ts +49 -0
- package/plugins/dashboard-store/__tests__/utils/store-mocks.ts +7 -0
- package/plugins/dashboard-store/actions.js +30 -4
- package/plugins/dashboard-store/classify.js +1 -18
- package/plugins/dashboard-store/getters.js +10 -5
- package/plugins/dashboard-store/index.js +0 -12
- package/plugins/dashboard-store/mutations.js +0 -4
- package/plugins/dashboard-store/resource-class.js +59 -18
- package/plugins/steve/__tests__/steve-class.spec.ts +59 -0
- package/plugins/steve/__tests__/utils/steve-mocks.ts +31 -0
- package/plugins/steve/getters.js +4 -1
- package/plugins/steve/norman-class.js +19 -0
- package/plugins/steve/steve-class.js +22 -0
- package/plugins/steve/subscribe.js +4 -10
- package/rancher-components/Accordion/Accordion.test.ts +45 -0
- package/rancher-components/Accordion/Accordion.vue +86 -0
- package/rancher-components/Accordion/index.ts +1 -0
- package/rancher-components/BadgeState/BadgeState.vue +3 -3
- package/rancher-components/Banner/Banner.vue +2 -2
- package/rancher-components/Card/Card.vue +3 -3
- package/rancher-components/Form/Checkbox/Checkbox.vue +3 -3
- package/rancher-components/Form/LabeledInput/LabeledInput.test.ts +18 -1
- package/rancher-components/Form/LabeledInput/LabeledInput.vue +65 -24
- package/rancher-components/Form/Radio/RadioButton.test.ts +7 -3
- package/rancher-components/Form/Radio/RadioButton.vue +13 -7
- package/rancher-components/Form/Radio/RadioGroup.test.ts +30 -0
- package/rancher-components/Form/Radio/RadioGroup.vue +8 -3
- package/rancher-components/Form/TextArea/TextAreaAutoGrow.vue +6 -4
- package/rancher-components/Form/ToggleSwitch/ToggleSwitch.vue +7 -4
- package/rancher-components/LabeledTooltip/LabeledTooltip.vue +9 -4
- package/rancher-components/StringList/StringList.test.ts +270 -0
- package/rancher-components/StringList/StringList.vue +65 -26
- package/rancher-components/components/Accordion/Accordion.test.ts +45 -0
- package/rancher-components/components/Accordion/Accordion.vue +86 -0
- package/rancher-components/components/Accordion/index.ts +1 -0
- package/rancher-components/components/BadgeState/BadgeState.vue +3 -3
- package/rancher-components/components/Banner/Banner.vue +2 -2
- package/rancher-components/components/Card/Card.vue +3 -3
- package/rancher-components/components/Form/Checkbox/Checkbox.vue +3 -3
- package/rancher-components/components/Form/LabeledInput/LabeledInput.test.ts +18 -1
- package/rancher-components/components/Form/LabeledInput/LabeledInput.vue +57 -24
- package/rancher-components/components/Form/Radio/RadioButton.vue +13 -7
- package/rancher-components/components/Form/Radio/RadioGroup.vue +4 -3
- package/rancher-components/components/Form/TextArea/TextAreaAutoGrow.vue +6 -4
- package/rancher-components/components/Form/ToggleSwitch/ToggleSwitch.vue +7 -4
- package/rancher-components/components/LabeledTooltip/LabeledTooltip.vue +9 -4
- package/rancher-components/components/StringList/StringList.vue +8 -8
- package/scripts/.gitlab/workflows/build-extension-catalog.gitlab-ci.yml +50 -0
- package/scripts/extension/parse-tag-name +2 -2
- package/scripts/publish-shell.sh +10 -0
- package/scripts/test-plugins-build.sh +85 -9
- package/server/har-file.js +183 -0
- package/store/catalog.js +1 -1
- package/store/features.js +1 -0
- package/store/i18n.js +11 -0
- package/store/index.js +10 -11
- package/store/prefs.js +33 -35
- package/store/type-map.js +8 -7
- package/tsconfig.json +35 -9
- package/tsconfig.paths.json +21 -0
- package/types/shell/index.d.ts +427 -234
- package/types/vue-shim.d.ts +42 -0
- package/utils/__tests__/create-yaml.test.ts +60 -0
- package/utils/axios.js +0 -19
- package/utils/azure.js +24 -0
- package/utils/create-yaml.js +17 -10
- package/utils/git.ts +1 -1
- package/utils/monitoring.js +1 -1
- package/utils/nuxt.js +18 -39
- package/utils/object.js +14 -0
- package/utils/router.scrollBehavior.js +12 -14
- package/utils/time.js +1 -1
- package/utils/url.ts +1 -1
- package/vue.config.js +23 -2
- package/.DS_Store +0 -0
- package/assets/images/providers/aks-black.svg +0 -28
- package/assets/images/providers/aks.svg +0 -31
- package/edit/provisioning.cattle.io.cluster/__tests__/Basics.tests.ts +0 -234
- package/initialize/layouts.ts +0 -26
- package/mixins/fetch.server.js +0 -73
- package/pages/c/index.vue +0 -9
- package/pages/rio/mesh.vue +0 -508
- package/plugins/transitions.js +0 -4
- package/scripts/.DS_Store +0 -0
- package/scripts/verdaccio.log +0 -205
- package/tsconfig.default.json +0 -46
- package/yarn-error.log +0 -200
- /package/components/form/__tests__/{NameNsDescription.ts → NameNsDescription.test.ts} +0 -0
- /package/edit/networking.k8s.io.networkpolicy/__tests__/utils/{selectors.ts → selectors.test.ts} +0 -0
- /package/edit/provisioning.cattle.io.cluster/{AgentConfiguration.vue → tabs/AgentConfiguration.vue} +0 -0
- /package/edit/provisioning.cattle.io.cluster/{MemberRoles.vue → tabs/MemberRoles.vue} +0 -0
- /package/edit/provisioning.cattle.io.cluster/{S3Config.vue → tabs/etcd/S3Config.vue} +0 -0
- /package/edit/provisioning.cattle.io.cluster/{ACE.vue → tabs/networking/ACE.vue} +0 -0
- /package/edit/provisioning.cattle.io.cluster/{RegistryConfigs.vue → tabs/registries/RegistryConfigs.vue} +0 -0
- /package/edit/provisioning.cattle.io.cluster/{RegistryMirrors.vue → tabs/registries/RegistryMirrors.vue} +0 -0
- /package/edit/provisioning.cattle.io.cluster/{DrainOptions.vue → tabs/upgrade/DrainOptions.vue} +0 -0
- /package/plugins/dashboard-store/__tests__/{actions.spec.ts → actions.test.ts} +0 -0
- /package/plugins/dashboard-store/__tests__/{getters.spec.ts → getters.test.ts} +0 -0
- /package/rancher-components/BadgeState/{BadgeState.spec.ts → BadgeState.test.ts} +0 -0
- /package/rancher-components/components/BadgeState/{BadgeState.spec.ts → BadgeState.test.ts} +0 -0
|
@@ -23,10 +23,6 @@ function registerType(state, type) {
|
|
|
23
23
|
// Not enumerable so they don't get sent back to the client for SSR
|
|
24
24
|
Object.defineProperty(cache, 'map', { value: new Map() });
|
|
25
25
|
|
|
26
|
-
if ( process.server && !cache.list.__rehydrateAll ) {
|
|
27
|
-
Object.defineProperty(cache.list, '__rehydrateAll', { value: `${ state.config.namespace }/${ type }`, enumerable: true });
|
|
28
|
-
}
|
|
29
|
-
|
|
30
26
|
Vue.set(state.types, type, cache);
|
|
31
27
|
}
|
|
32
28
|
|
|
@@ -105,6 +105,7 @@ export const STATES_ENUM = {
|
|
|
105
105
|
ERRORING: 'erroring',
|
|
106
106
|
ERRORS: 'errors',
|
|
107
107
|
EXPIRED: 'expired',
|
|
108
|
+
EXPIRING: 'expiring',
|
|
108
109
|
FAIL: 'fail',
|
|
109
110
|
FAILED: 'failed',
|
|
110
111
|
HEALTHY: 'healthy',
|
|
@@ -167,6 +168,13 @@ export const STATES_ENUM = {
|
|
|
167
168
|
WARNING: 'warning',
|
|
168
169
|
};
|
|
169
170
|
|
|
171
|
+
export function mapStateToEnum(statusString) {
|
|
172
|
+
// e.g. in fleet Status is Capitalized. This function will map it to the enum
|
|
173
|
+
return Object.values(STATES_ENUM).find((val) => {
|
|
174
|
+
return val.toLowerCase() === statusString.toLocaleLowerCase();
|
|
175
|
+
});
|
|
176
|
+
}
|
|
177
|
+
|
|
170
178
|
export const STATES = {
|
|
171
179
|
[STATES_ENUM.IN_USE]: {
|
|
172
180
|
color: 'success', icon: 'dot-open', label: 'In Use', compoundIcon: 'checkmark'
|
|
@@ -253,7 +261,10 @@ export const STATES = {
|
|
|
253
261
|
color: 'error', icon: 'error', label: 'Errors', compoundIcon: 'error'
|
|
254
262
|
},
|
|
255
263
|
[STATES_ENUM.EXPIRED]: {
|
|
256
|
-
color: '
|
|
264
|
+
color: 'error', icon: 'error', label: 'Expired', compoundIcon: 'warning'
|
|
265
|
+
},
|
|
266
|
+
[STATES_ENUM.EXPIRING]: {
|
|
267
|
+
color: 'warning', icon: 'error', label: 'Expiring', compoundIcon: 'error'
|
|
257
268
|
},
|
|
258
269
|
[STATES_ENUM.FAIL]: {
|
|
259
270
|
color: 'error', icon: 'error', label: 'Fail', compoundIcon: 'error'
|
|
@@ -512,6 +523,28 @@ export function stateDisplay(state) {
|
|
|
512
523
|
return key.split(/-/).map(ucFirst).join('-');
|
|
513
524
|
}
|
|
514
525
|
|
|
526
|
+
export function primaryDisplayStatusFromCount(status) {
|
|
527
|
+
const statusOrder = [
|
|
528
|
+
STATES_ENUM.ERROR,
|
|
529
|
+
STATES_ENUM.FAILED,
|
|
530
|
+
STATES_ENUM.WARNING,
|
|
531
|
+
STATES_ENUM.MODIFIED,
|
|
532
|
+
STATES_ENUM.WAIT_APPLIED,
|
|
533
|
+
STATES_ENUM.ORPHANED,
|
|
534
|
+
STATES_ENUM.MISSING,
|
|
535
|
+
STATES_ENUM.UNKNOWN,
|
|
536
|
+
STATES_ENUM.NOT_READY,
|
|
537
|
+
STATES_ENUM.READY,
|
|
538
|
+
];
|
|
539
|
+
|
|
540
|
+
// sort status by order of statusOrder
|
|
541
|
+
const existingStatuses = Object.keys(status).filter((key) => {
|
|
542
|
+
return status[key] > 0 && statusOrder.includes(key.toLowerCase());
|
|
543
|
+
}).sort((a, b) => statusOrder.indexOf(a.toLowerCase()) - statusOrder.indexOf(b.toLowerCase()));
|
|
544
|
+
|
|
545
|
+
return existingStatuses[0] ? existingStatuses[0] : STATES_ENUM.UNKNOWN;
|
|
546
|
+
}
|
|
547
|
+
|
|
515
548
|
export function stateSort(color, display) {
|
|
516
549
|
color = color.replace(/^(text|bg)-/, '');
|
|
517
550
|
|
|
@@ -1089,6 +1122,16 @@ export default class Resource {
|
|
|
1089
1122
|
return this._save(...arguments);
|
|
1090
1123
|
}
|
|
1091
1124
|
|
|
1125
|
+
/**
|
|
1126
|
+
* Remove any unwanted properties from the object that will be saved
|
|
1127
|
+
*/
|
|
1128
|
+
cleanForSave(data, forNew) {
|
|
1129
|
+
delete data.__rehydrate;
|
|
1130
|
+
delete data.__clone;
|
|
1131
|
+
|
|
1132
|
+
return data;
|
|
1133
|
+
}
|
|
1134
|
+
|
|
1092
1135
|
/**
|
|
1093
1136
|
* Allow to handle the response of the save request
|
|
1094
1137
|
* @param {*} res Full request response
|
|
@@ -1096,9 +1139,6 @@ export default class Resource {
|
|
|
1096
1139
|
processSaveResponse(res) { }
|
|
1097
1140
|
|
|
1098
1141
|
async _save(opt = {}) {
|
|
1099
|
-
delete this.__rehydrate;
|
|
1100
|
-
delete this.__clone;
|
|
1101
|
-
|
|
1102
1142
|
const forNew = !this.id;
|
|
1103
1143
|
|
|
1104
1144
|
const errors = await this.validationErrors(this, opt.ignoreFields);
|
|
@@ -1145,22 +1185,24 @@ export default class Resource {
|
|
|
1145
1185
|
// @TODO remove this once the API maps steve _type <-> k8s type in both directions
|
|
1146
1186
|
opt.data = this.toSave() || { ...this };
|
|
1147
1187
|
|
|
1148
|
-
if (opt
|
|
1188
|
+
if (opt.data._type) {
|
|
1149
1189
|
opt.data.type = opt.data._type;
|
|
1150
1190
|
}
|
|
1151
1191
|
|
|
1152
|
-
if (opt
|
|
1192
|
+
if (opt.data._name) {
|
|
1153
1193
|
opt.data.name = opt.data._name;
|
|
1154
1194
|
}
|
|
1155
1195
|
|
|
1156
|
-
if (opt
|
|
1196
|
+
if (opt.data._labels) {
|
|
1157
1197
|
opt.data.labels = opt.data._labels;
|
|
1158
1198
|
}
|
|
1159
1199
|
|
|
1160
|
-
if (opt
|
|
1200
|
+
if (opt.data._annotations) {
|
|
1161
1201
|
opt.data.annotations = opt.data._annotations;
|
|
1162
1202
|
}
|
|
1163
1203
|
|
|
1204
|
+
opt.data = this.cleanForSave(opt.data, forNew);
|
|
1205
|
+
|
|
1164
1206
|
// handle "replace" opt as a query param _replace=true for norman PUT requests
|
|
1165
1207
|
if (opt?.replace && opt.method === 'put') {
|
|
1166
1208
|
const argParam = opt.url.includes('?') ? '&' : '?';
|
|
@@ -1218,19 +1260,11 @@ export default class Resource {
|
|
|
1218
1260
|
// ------------------------------------------------------------------
|
|
1219
1261
|
|
|
1220
1262
|
currentRoute() {
|
|
1221
|
-
|
|
1222
|
-
return this.$rootState.$route;
|
|
1223
|
-
} else {
|
|
1224
|
-
return window.$nuxt.$route;
|
|
1225
|
-
}
|
|
1263
|
+
return window.$nuxt.$route;
|
|
1226
1264
|
}
|
|
1227
1265
|
|
|
1228
1266
|
currentRouter() {
|
|
1229
|
-
|
|
1230
|
-
return this.$rootState.$router;
|
|
1231
|
-
} else {
|
|
1232
|
-
return window.$nuxt.$router;
|
|
1233
|
-
}
|
|
1267
|
+
return window.$nuxt.$router;
|
|
1234
1268
|
}
|
|
1235
1269
|
|
|
1236
1270
|
get listLocation() {
|
|
@@ -1931,4 +1965,11 @@ export default class Resource {
|
|
|
1931
1965
|
get creationTimestamp() {
|
|
1932
1966
|
return this.metadata?.creationTimestamp;
|
|
1933
1967
|
}
|
|
1968
|
+
|
|
1969
|
+
/**
|
|
1970
|
+
* Allows model to specify JSON Paths that should be folded in the YAML editor by default
|
|
1971
|
+
*/
|
|
1972
|
+
get yamlFolding() {
|
|
1973
|
+
return [];
|
|
1974
|
+
}
|
|
1934
1975
|
}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import Steve from '@shell/plugins/steve/steve-class.js';
|
|
2
|
+
import { steveClassJunkObject } from './utils/steve-mocks';
|
|
3
|
+
|
|
4
|
+
describe('class: Steve', () => {
|
|
5
|
+
describe('given custom resource keys', () => {
|
|
6
|
+
const customResource = steveClassJunkObject;
|
|
7
|
+
|
|
8
|
+
it('should keep internal keys', () => {
|
|
9
|
+
const steve = new Steve(customResource, {
|
|
10
|
+
getters: { schemaFor: () => ({ linkFor: jest.fn() }) },
|
|
11
|
+
dispatch: jest.fn(),
|
|
12
|
+
rootGetters: { 'i18n/t': jest.fn() },
|
|
13
|
+
});
|
|
14
|
+
|
|
15
|
+
expect({ ...steve }).toStrictEqual(customResource);
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
describe('method: save', () => {
|
|
19
|
+
it('should remove all the internal keys', async() => {
|
|
20
|
+
const dispatch = jest.fn();
|
|
21
|
+
const steve = new Steve(customResource, {
|
|
22
|
+
getters: { schemaFor: () => ({ linkFor: jest.fn() }) },
|
|
23
|
+
dispatch,
|
|
24
|
+
rootGetters: { 'i18n/t': jest.fn() },
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
const expectation = {
|
|
28
|
+
type: customResource.type,
|
|
29
|
+
metadata: {
|
|
30
|
+
resourceVersion: 'whatever',
|
|
31
|
+
fields: 'whatever',
|
|
32
|
+
clusterName: 'whatever',
|
|
33
|
+
deletionGracePeriodSeconds: 'whatever',
|
|
34
|
+
generateName: 'whatever',
|
|
35
|
+
},
|
|
36
|
+
spec: { versions: {} }
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
await steve.save();
|
|
40
|
+
|
|
41
|
+
const opt = {
|
|
42
|
+
data: expectation,
|
|
43
|
+
headers: {
|
|
44
|
+
accept: 'application/json',
|
|
45
|
+
'content-type': 'application/json',
|
|
46
|
+
},
|
|
47
|
+
method: 'post',
|
|
48
|
+
url: undefined,
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
// Data sent should have been cleaned
|
|
52
|
+
expect(dispatch).toHaveBeenCalledWith('request', { opt, type: customResource.type });
|
|
53
|
+
|
|
54
|
+
// Original workload model should remain unchanged
|
|
55
|
+
expect({ ...steve }).toStrictEqual(customResource);
|
|
56
|
+
});
|
|
57
|
+
});
|
|
58
|
+
});
|
|
59
|
+
});
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { resourceClassJunkObject } from '@shell/plugins/dashboard-store/__tests__/utils/store-mocks';
|
|
2
|
+
|
|
3
|
+
const customType = 'asdasd';
|
|
4
|
+
|
|
5
|
+
export const steveClassJunkObject = {
|
|
6
|
+
...resourceClassJunkObject,
|
|
7
|
+
type: customType,
|
|
8
|
+
__clone: 'whatever',
|
|
9
|
+
metadata: {
|
|
10
|
+
clusterName: 'whatever',
|
|
11
|
+
creationTimestamp: 'whatever',
|
|
12
|
+
deletionGracePeriodSeconds: 'whatever',
|
|
13
|
+
deletionTimestamp: 'whatever',
|
|
14
|
+
fields: 'whatever',
|
|
15
|
+
finalizers: 'whatever',
|
|
16
|
+
generateName: 'whatever',
|
|
17
|
+
generation: 'whatever',
|
|
18
|
+
initializers: 'whatever',
|
|
19
|
+
managedFields: 'whatever',
|
|
20
|
+
ownerReferences: 'whatever',
|
|
21
|
+
relationships: 'whatever',
|
|
22
|
+
selfLink: 'whatever',
|
|
23
|
+
state: 'whatever',
|
|
24
|
+
uid: 'whatever',
|
|
25
|
+
resourceVersion: 'whatever',
|
|
26
|
+
},
|
|
27
|
+
spec: { versions: { schema: 'whatever' } },
|
|
28
|
+
links: 'whatever',
|
|
29
|
+
status: 'whatever',
|
|
30
|
+
stringData: 'whatever',
|
|
31
|
+
};
|
package/plugins/steve/getters.js
CHANGED
|
@@ -24,11 +24,14 @@ const GC_IGNORE_TYPES = {
|
|
|
24
24
|
[UI.NAV_LINK]: true,
|
|
25
25
|
};
|
|
26
26
|
|
|
27
|
+
// Include calls to /v1 AND /k8s/clusters/<cluster id>/v1
|
|
28
|
+
const steveRegEx = new RegExp('(/v1)|(\/k8s\/clusters\/[a-z0-9-]+\/v1)');
|
|
29
|
+
|
|
27
30
|
export default {
|
|
28
31
|
urlOptions: () => (url, opt) => {
|
|
29
32
|
opt = opt || {};
|
|
30
33
|
const parsedUrl = parse(url);
|
|
31
|
-
const isSteve = parsedUrl.path
|
|
34
|
+
const isSteve = steveRegEx.test(parsedUrl.path);
|
|
32
35
|
|
|
33
36
|
// Filter
|
|
34
37
|
if ( opt.filter ) {
|
|
@@ -3,6 +3,7 @@ import pickBy from 'lodash/pickBy';
|
|
|
3
3
|
import Vue from 'vue';
|
|
4
4
|
import { matchesSomeRegex } from '@shell/utils/string';
|
|
5
5
|
import Resource from '@shell/plugins/dashboard-store/resource-class';
|
|
6
|
+
import { findBy } from '@shell/utils/array';
|
|
6
7
|
|
|
7
8
|
export default class NormanModel extends Resource {
|
|
8
9
|
setLabels(val) {
|
|
@@ -56,4 +57,22 @@ export default class NormanModel extends Resource {
|
|
|
56
57
|
Vue.set(this, key, { ...spec[key] });
|
|
57
58
|
});
|
|
58
59
|
}
|
|
60
|
+
|
|
61
|
+
isCondition(condition, withStatus = 'True') {
|
|
62
|
+
if ( !this.conditions ) {
|
|
63
|
+
return false;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
const entry = findBy((this.conditions || []), 'type', condition);
|
|
67
|
+
|
|
68
|
+
if ( !entry ) {
|
|
69
|
+
return false;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
if ( !withStatus ) {
|
|
73
|
+
return true;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
return (entry.status || '').toLowerCase() === `${ withStatus }`.toLowerCase();
|
|
77
|
+
}
|
|
59
78
|
}
|
|
@@ -1,5 +1,17 @@
|
|
|
1
1
|
import { DESCRIPTION } from '@shell/config/labels-annotations';
|
|
2
2
|
import HybridModel from './hybrid-class';
|
|
3
|
+
import { NEVER_ADD } from '@shell/utils/create-yaml';
|
|
4
|
+
import { deleteProperty } from '@shell/utils/object';
|
|
5
|
+
|
|
6
|
+
// Some fields that are removed for YAML (NEVER_ADD) are required via API
|
|
7
|
+
const STEVE_ADD = [
|
|
8
|
+
'metadata.resourceVersion',
|
|
9
|
+
'metadata.fields',
|
|
10
|
+
'metadata.clusterName',
|
|
11
|
+
'metadata.deletionGracePeriodSeconds',
|
|
12
|
+
'metadata.generateName',
|
|
13
|
+
];
|
|
14
|
+
const STEVE_NEVER_SAVE = NEVER_ADD.filter((na) => !STEVE_ADD.includes(na));
|
|
3
15
|
|
|
4
16
|
export default class SteveModel extends HybridModel {
|
|
5
17
|
get name() {
|
|
@@ -28,4 +40,14 @@ export default class SteveModel extends HybridModel {
|
|
|
28
40
|
|
|
29
41
|
this._description = value;
|
|
30
42
|
}
|
|
43
|
+
|
|
44
|
+
cleanForSave(data, forNew) {
|
|
45
|
+
const val = super.cleanForSave(data);
|
|
46
|
+
|
|
47
|
+
for (const field of STEVE_NEVER_SAVE) {
|
|
48
|
+
deleteProperty(val, field);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
return val;
|
|
52
|
+
}
|
|
31
53
|
}
|
|
@@ -332,10 +332,6 @@ const sharedActions = {
|
|
|
332
332
|
|
|
333
333
|
commit('setWantSocket', true);
|
|
334
334
|
|
|
335
|
-
if ( process.server ) {
|
|
336
|
-
return;
|
|
337
|
-
}
|
|
338
|
-
|
|
339
335
|
state.debugSocket && console.info(`Subscribe [${ getters.storeName }]`); // eslint-disable-line no-console
|
|
340
336
|
|
|
341
337
|
const url = `${ state.config.baseUrl }/subscribe`;
|
|
@@ -601,7 +597,7 @@ const defaultActions = {
|
|
|
601
597
|
},
|
|
602
598
|
|
|
603
599
|
rehydrateSubscribe({ state, dispatch }) {
|
|
604
|
-
if (
|
|
600
|
+
if ( state.wantSocket && !state.socket ) {
|
|
605
601
|
dispatch('subscribe');
|
|
606
602
|
}
|
|
607
603
|
},
|
|
@@ -728,11 +724,9 @@ const defaultActions = {
|
|
|
728
724
|
}
|
|
729
725
|
|
|
730
726
|
// Try resending any frames that were attempted to be sent while the socket was down, once.
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
dispatch('sendImmediate', obj);
|
|
735
|
-
}
|
|
727
|
+
for ( const obj of state.pendingFrames.slice() ) {
|
|
728
|
+
commit('dequeuePendingFrame', obj);
|
|
729
|
+
dispatch('sendImmediate', obj);
|
|
736
730
|
}
|
|
737
731
|
},
|
|
738
732
|
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { shallowMount } from '@vue/test-utils';
|
|
2
|
+
import { Accordion } from './index';
|
|
3
|
+
|
|
4
|
+
describe('component: Accordion', () => {
|
|
5
|
+
it('is closed initially by default', () => {
|
|
6
|
+
const title = 'Test Title';
|
|
7
|
+
|
|
8
|
+
const wrapper = shallowMount(Accordion, { propsData: { title } });
|
|
9
|
+
|
|
10
|
+
expect(wrapper.find('[data-testid="accordion-body"]').isVisible()).toBe(false);
|
|
11
|
+
expect(wrapper.find('[data-testid="accordion-header"]').text()).toBe(title);
|
|
12
|
+
});
|
|
13
|
+
|
|
14
|
+
it('is opened initially when openInitially prop is true', () => {
|
|
15
|
+
const wrapper = shallowMount(Accordion, { propsData: { openInitially: true } });
|
|
16
|
+
|
|
17
|
+
expect(wrapper.find('[data-testid="accordion-body"]').isVisible()).toBe(true);
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
it('when closed, opens when the header is clicked', async() => {
|
|
21
|
+
const wrapper = shallowMount(Accordion, { });
|
|
22
|
+
|
|
23
|
+
await wrapper.find('[data-testid="accordion-header"]').trigger('click');
|
|
24
|
+
expect(wrapper.find('[data-testid="accordion-body"]').isVisible()).toBe(true);
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
it('when open, closes when the header is clicked', async() => {
|
|
28
|
+
const wrapper = shallowMount(Accordion, { propsData: { openInitially: true } });
|
|
29
|
+
|
|
30
|
+
await wrapper.find('[data-testid="accordion-header"]').trigger('click');
|
|
31
|
+
expect(wrapper.find('[data-testid="accordion-body"]').isVisible()).toBe(false);
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
it('displays a chevron when closed', async() => {
|
|
35
|
+
const wrapper = shallowMount(Accordion, { propsData: { } });
|
|
36
|
+
|
|
37
|
+
expect(wrapper.find('[data-testid="accordion-header"] .icon-chevron-up').exists()).toBe(true);
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
it('displays an inverted chevron when open', async() => {
|
|
41
|
+
const wrapper = shallowMount(Accordion, { propsData: { openInitially: true } });
|
|
42
|
+
|
|
43
|
+
expect(wrapper.find('[data-testid="accordion-header"] .icon-chevron-down').exists()).toBe(true);
|
|
44
|
+
});
|
|
45
|
+
});
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import { defineComponent } from 'vue';
|
|
3
|
+
import { mapGetters } from 'vuex';
|
|
4
|
+
|
|
5
|
+
export default defineComponent({
|
|
6
|
+
props: {
|
|
7
|
+
title: {
|
|
8
|
+
type: String,
|
|
9
|
+
default: ''
|
|
10
|
+
},
|
|
11
|
+
|
|
12
|
+
titleKey: {
|
|
13
|
+
type: String,
|
|
14
|
+
default: null
|
|
15
|
+
},
|
|
16
|
+
|
|
17
|
+
openInitially: {
|
|
18
|
+
type: Boolean,
|
|
19
|
+
default: false
|
|
20
|
+
}
|
|
21
|
+
},
|
|
22
|
+
|
|
23
|
+
data() {
|
|
24
|
+
return { isOpen: this.openInitially };
|
|
25
|
+
},
|
|
26
|
+
|
|
27
|
+
computed: { ...mapGetters({ t: 'i18n/t' }) },
|
|
28
|
+
|
|
29
|
+
methods: {
|
|
30
|
+
toggle() {
|
|
31
|
+
this.isOpen = !this.isOpen;
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
});
|
|
35
|
+
</script>
|
|
36
|
+
|
|
37
|
+
<template>
|
|
38
|
+
<div class="accordion-container">
|
|
39
|
+
<div
|
|
40
|
+
class="accordion-header"
|
|
41
|
+
data-testid="accordion-header"
|
|
42
|
+
@click="toggle"
|
|
43
|
+
>
|
|
44
|
+
<i
|
|
45
|
+
class="icon text-primary"
|
|
46
|
+
:class="{'icon-chevron-down':isOpen, 'icon-chevron-up':!isOpen}"
|
|
47
|
+
data-testid="accordion-chevron"
|
|
48
|
+
/>
|
|
49
|
+
<slot name="header">
|
|
50
|
+
<h4
|
|
51
|
+
data-testid="accordion-title-slot-content"
|
|
52
|
+
class="mb-0"
|
|
53
|
+
>
|
|
54
|
+
{{ titleKey ? t(titleKey) : title }}
|
|
55
|
+
</h4>
|
|
56
|
+
</slot>
|
|
57
|
+
</div>
|
|
58
|
+
<div
|
|
59
|
+
v-show="isOpen"
|
|
60
|
+
class="accordion-body"
|
|
61
|
+
data-testid="accordion-body"
|
|
62
|
+
>
|
|
63
|
+
<slot />
|
|
64
|
+
</div>
|
|
65
|
+
</div>
|
|
66
|
+
</template>
|
|
67
|
+
|
|
68
|
+
<style lang="scss" scoped>
|
|
69
|
+
.accordion-container {
|
|
70
|
+
border: 1px solid var(--border)
|
|
71
|
+
}
|
|
72
|
+
.accordion-header {
|
|
73
|
+
padding: 5px;
|
|
74
|
+
display: flex;
|
|
75
|
+
align-items: center;
|
|
76
|
+
&>*{
|
|
77
|
+
padding: 5px 0px 5px 0px;
|
|
78
|
+
}
|
|
79
|
+
I {
|
|
80
|
+
margin: 0px 10px 0px 10px;
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
.accordion-body {
|
|
84
|
+
padding: 10px;
|
|
85
|
+
}
|
|
86
|
+
</style>
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { default as Accordion } from './Accordion.vue';
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
|
-
import
|
|
2
|
+
import { PropType, defineComponent } from 'vue';
|
|
3
3
|
|
|
4
4
|
interface Badge {
|
|
5
5
|
stateBackground: string;
|
|
@@ -11,7 +11,7 @@ interface Badge {
|
|
|
11
11
|
* <p>Represents a badge whose label and color is either taken from the value property or
|
|
12
12
|
* from the label and color properties. The state property takes precedence.</p>
|
|
13
13
|
*/
|
|
14
|
-
export default
|
|
14
|
+
export default defineComponent({
|
|
15
15
|
props: {
|
|
16
16
|
/**
|
|
17
17
|
* A value having the properties `stateBackground` and `stateDisplay`
|
|
@@ -59,7 +59,7 @@ export default Vue.extend({
|
|
|
59
59
|
</script>
|
|
60
60
|
|
|
61
61
|
<template>
|
|
62
|
-
<span :class="
|
|
62
|
+
<span :class="['badge-state', bg]">
|
|
63
63
|
<i
|
|
64
64
|
v-if="icon"
|
|
65
65
|
class="icon"
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
|
-
import
|
|
2
|
+
import { defineComponent } from 'vue';
|
|
3
3
|
import { nlToBr } from '@shell/utils/string';
|
|
4
4
|
import { stringify } from '@shell/utils/error';
|
|
5
5
|
|
|
6
|
-
export default
|
|
6
|
+
export default defineComponent({
|
|
7
7
|
props: {
|
|
8
8
|
/**
|
|
9
9
|
* A color class that represents the color of the banner.
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
|
-
import
|
|
2
|
+
import { defineComponent, PropType } from 'vue';
|
|
3
3
|
|
|
4
|
-
export default
|
|
4
|
+
export default defineComponent({
|
|
5
5
|
name: 'Card',
|
|
6
6
|
props: {
|
|
7
7
|
/**
|
|
@@ -22,7 +22,7 @@ export default Vue.extend({
|
|
|
22
22
|
* The function to invoke when the default action button is clicked.
|
|
23
23
|
*/
|
|
24
24
|
buttonAction: {
|
|
25
|
-
type: Function
|
|
25
|
+
type: Function as PropType<(event: MouseEvent) => void>,
|
|
26
26
|
default: (): void => { }
|
|
27
27
|
},
|
|
28
28
|
/**
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
|
-
import
|
|
2
|
+
import { PropType, defineComponent } from 'vue';
|
|
3
3
|
import { _EDIT, _VIEW } from '@shell/config/query-params';
|
|
4
4
|
import { addObject, removeObject } from '@shell/utils/array';
|
|
5
5
|
import cloneDeep from 'lodash/cloneDeep';
|
|
6
6
|
|
|
7
|
-
export default
|
|
7
|
+
export default defineComponent({
|
|
8
8
|
name: 'Checkbox',
|
|
9
9
|
|
|
10
10
|
props: {
|
|
@@ -140,7 +140,7 @@ export default Vue.extend({
|
|
|
140
140
|
/**
|
|
141
141
|
* Toggles the checked state for the checkbox and emits an 'input' event.
|
|
142
142
|
*/
|
|
143
|
-
clicked(event: MouseEvent): boolean | void {
|
|
143
|
+
clicked(event: MouseEvent | KeyboardEvent): boolean | void {
|
|
144
144
|
if ((event.target as HTMLLinkElement).tagName === 'A' && (event.target as HTMLLinkElement).href) {
|
|
145
145
|
// Ignore links inside the checkbox label so you can click them
|
|
146
146
|
return true;
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
|
|
2
1
|
import { mount } from '@vue/test-utils';
|
|
3
2
|
import { LabeledInput } from './index';
|
|
4
3
|
|
|
@@ -20,4 +19,22 @@ describe('component: LabeledInput', () => {
|
|
|
20
19
|
expect(wrapper.emitted('input')).toHaveLength(1);
|
|
21
20
|
expect(wrapper.emitted('input')![0][0]).toBe(value);
|
|
22
21
|
});
|
|
22
|
+
|
|
23
|
+
it('using mode "multiline" should emit input value correctly', () => {
|
|
24
|
+
const value = 'any-string';
|
|
25
|
+
const delay = 1;
|
|
26
|
+
const wrapper = mount(LabeledInput as any, {
|
|
27
|
+
propsData: { delay, multiline: true },
|
|
28
|
+
mocks: { $store: { getters: { 'i18n/t': jest.fn() } } }
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
jest.useFakeTimers();
|
|
32
|
+
wrapper.find('input').setValue('1');
|
|
33
|
+
wrapper.find('input').setValue(value);
|
|
34
|
+
jest.advanceTimersByTime(delay);
|
|
35
|
+
jest.useRealTimers();
|
|
36
|
+
|
|
37
|
+
expect(wrapper.emitted('input')).toHaveLength(1);
|
|
38
|
+
expect(wrapper.emitted('input')![0][0]).toBe(value);
|
|
39
|
+
});
|
|
23
40
|
});
|