@rancher/shell 3.0.2-rc.2 → 3.0.2-rc.4
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/styles/base/_basic.scss +7 -8
- package/assets/styles/global/_button.scss +10 -0
- package/assets/styles/global/_form.scss +2 -1
- package/assets/styles/global/_tooltip.scss +2 -2
- package/assets/styles/themes/_dark.scss +15 -3
- package/assets/styles/themes/_light.scss +7 -2
- package/assets/styles/vendor/vue-select.scss +4 -0
- package/assets/translations/en-us.yaml +66 -9
- package/assets/translations/zh-hans.yaml +2 -3
- package/components/AppModal.vue +50 -0
- package/components/BannerGraphic.vue +0 -42
- package/components/ButtonMultiAction.vue +1 -1
- package/components/Carousel.vue +88 -74
- package/components/CommunityLinks.vue +6 -1
- package/components/CopyToClipboardText.vue +3 -0
- package/components/Dialog.vue +20 -1
- package/components/GrowlManager.vue +9 -2
- package/components/LocaleSelector.vue +8 -1
- package/components/PaginatedResourceTable.vue +4 -7
- package/components/ProgressBarMulti.vue +14 -0
- package/components/PromptChangePassword.vue +3 -0
- package/components/Questions/Reference.vue +57 -28
- package/components/ResourceDetail/Masthead.vue +1 -1
- package/components/SelectIconGrid.vue +12 -1
- package/components/SideNav.vue +12 -38
- package/components/SortableTable/index.vue +1 -0
- package/components/Tabbed/index.vue +9 -1
- package/components/YamlEditor.vue +1 -0
- package/components/__tests__/Carousel.test.ts +56 -27
- package/components/auth/Principal.vue +5 -3
- package/components/fleet/FleetClusters.vue +82 -1
- package/components/fleet/FleetRepos.vue +13 -30
- package/components/fleet/ForceDirectedTreeChart/index.vue +2 -2
- package/components/form/ChangePassword.vue +2 -0
- package/components/form/ColorInput.vue +24 -1
- package/components/form/FileSelector.vue +2 -0
- package/components/form/KeyValue.vue +230 -160
- package/components/form/LabeledSelect.vue +2 -2
- package/components/form/PlusMinus.vue +14 -2
- package/components/form/ResourceLabeledSelect.vue +13 -53
- package/components/form/ResourceSelector.vue +1 -0
- package/components/form/ResourceTabs/index.vue +79 -36
- package/components/form/SSHKnownHosts/KnownHostsEditDialog.vue +192 -0
- package/components/form/SSHKnownHosts/__tests__/KnownHostsEditDialog.test.ts +104 -0
- package/components/form/SSHKnownHosts/index.vue +101 -0
- package/components/form/SecretSelector.vue +2 -2
- package/components/form/Select.vue +1 -1
- package/components/form/SelectOrCreateAuthSecret.vue +43 -11
- package/components/form/__tests__/KeyValue.test.ts +1 -1
- package/components/form/__tests__/SSHKnownHosts.test.ts +59 -0
- package/components/formatter/FleetClusterSummaryGraph.vue +2 -2
- package/components/formatter/FleetSummaryGraph.vue +6 -7
- package/components/formatter/WorkloadHealthScale.vue +7 -0
- package/components/nav/Group.vue +30 -4
- package/components/nav/Header.vue +82 -114
- package/components/nav/HeaderPageActionMenu.vue +27 -131
- package/components/nav/NamespaceFilter.vue +1 -1
- package/components/nav/Type.vue +15 -0
- package/composables/focusTrap.ts +68 -0
- package/config/home-links.js +21 -13
- package/config/labels-annotations.js +2 -0
- package/config/page-actions.js +1 -0
- package/config/pagination-table-headers.js +15 -1
- package/config/product/explorer.js +7 -17
- package/config/table-headers.js +6 -0
- package/config/version.js +5 -1
- package/core/plugin.ts +41 -1
- package/core/plugins.js +125 -72
- package/core/types-provisioning.ts +91 -2
- package/core/types.ts +55 -0
- package/detail/__tests__/autoscaling.horizontalpodautoscaler.test.ts +12 -3
- package/detail/catalog.cattle.io.app.vue +1 -1
- package/detail/fleet.cattle.io.cluster.vue +3 -3
- package/detail/namespace.vue +13 -19
- package/detail/networking.k8s.io.ingress.vue +13 -53
- package/detail/provisioning.cattle.io.cluster.vue +12 -1
- package/detail/secret.vue +25 -0
- package/detail/workload/index.vue +3 -3
- package/dialog/AddCustomBadgeDialog.vue +5 -1
- package/edit/auth/ldap/__tests__/config.test.ts +18 -0
- package/edit/auth/ldap/config.vue +24 -0
- package/edit/auth/saml.vue +8 -6
- package/edit/fleet.cattle.io.gitrepo.vue +34 -23
- package/edit/logging-flow/index.vue +4 -19
- package/edit/networking.k8s.io.ingress/index.vue +18 -65
- package/edit/networking.k8s.io.networkpolicy/index.vue +4 -5
- package/edit/provisioning.cattle.io.cluster/index.vue +27 -8
- package/edit/provisioning.cattle.io.cluster/rke2.vue +31 -115
- package/edit/provisioning.cattle.io.cluster/tabs/Basics.vue +2 -2
- package/edit/provisioning.cattle.io.cluster/tabs/networking/ACE.vue +14 -28
- package/edit/provisioning.cattle.io.cluster/tabs/networking/index.vue +25 -12
- package/edit/secret/index.vue +1 -1
- package/edit/secret/ssh.vue +21 -3
- package/edit/service.vue +1 -2
- package/list/networking.k8s.io.ingress.vue +1 -1
- package/list/node.vue +15 -8
- package/list/persistentvolume.vue +12 -4
- package/list/provisioning.cattle.io.cluster.vue +1 -0
- package/list/service.vue +1 -1
- package/list/workload.vue +4 -0
- package/mixins/chart.js +4 -1
- package/models/catalog.cattle.io.app.js +3 -1
- package/models/catalog.cattle.io.clusterrepo.js +56 -7
- package/models/fleet.cattle.io.bundle.js +0 -11
- package/models/fleet.cattle.io.cluster.js +17 -1
- package/models/fleet.cattle.io.gitrepo.js +88 -52
- package/models/provisioning.cattle.io.cluster.js +36 -1
- package/models/secret.js +5 -0
- package/models/service.js +1 -0
- package/models/workload.js +19 -1
- package/package.json +5 -4
- package/pages/account/index.vue +4 -0
- package/pages/c/_cluster/apps/charts/index.vue +4 -0
- package/pages/c/_cluster/explorer/ConfigBadge.vue +4 -2
- package/pages/c/_cluster/explorer/index.vue +13 -6
- package/pages/c/_cluster/fleet/GitRepoGraphConfig.js +3 -3
- package/pages/c/_cluster/fleet/index.vue +75 -89
- package/pages/c/_cluster/settings/links.vue +2 -2
- package/pages/c/_cluster/uiplugins/AddExtensionRepos.vue +3 -1
- package/pages/c/_cluster/uiplugins/CatalogList/CatalogLoadDialog.vue +3 -0
- package/pages/c/_cluster/uiplugins/CatalogList/CatalogUninstallDialog.vue +7 -1
- package/pages/c/_cluster/uiplugins/CatalogList/index.vue +3 -1
- package/pages/c/_cluster/uiplugins/DeveloperInstallDialog.vue +10 -7
- package/pages/c/_cluster/uiplugins/InstallDialog.vue +7 -0
- package/pages/c/_cluster/uiplugins/PluginInfoPanel.vue +181 -106
- package/pages/c/_cluster/uiplugins/SetupUIPlugins.vue +2 -0
- package/pages/c/_cluster/uiplugins/UninstallDialog.vue +9 -1
- package/pages/c/_cluster/uiplugins/index.vue +50 -12
- package/pages/diagnostic.vue +17 -15
- package/pages/home.vue +32 -6
- package/plugins/clean-html.js +50 -0
- package/plugins/dashboard-store/resource-class.js +4 -0
- package/plugins/plugin.js +54 -49
- package/plugins/steve/mutations.js +1 -1
- package/plugins/steve/steve-class.js +8 -0
- package/plugins/steve/steve-pagination-utils.ts +3 -1
- package/rancher-components/Accordion/Accordion.vue +4 -4
- package/rancher-components/BadgeState/BadgeState.vue +7 -0
- package/rancher-components/Card/Card.vue +12 -0
- package/rancher-components/Form/Checkbox/Checkbox.vue +9 -2
- package/rancher-components/Form/LabeledInput/LabeledInput.test.ts +18 -1
- package/rancher-components/Form/LabeledInput/LabeledInput.vue +19 -1
- package/rancher-components/Form/ToggleSwitch/ToggleSwitch.vue +39 -2
- package/rancher-components/RcButton/RcButton.vue +90 -0
- package/rancher-components/RcButton/index.ts +2 -0
- package/rancher-components/RcButton/types.ts +17 -0
- package/rancher-components/RcDropdown/RcDropdown.vue +122 -0
- package/rancher-components/RcDropdown/RcDropdownItem.vue +127 -0
- package/rancher-components/RcDropdown/RcDropdownSeparator.vue +6 -0
- package/rancher-components/RcDropdown/RcDropdownTrigger.vue +42 -0
- package/rancher-components/RcDropdown/index.ts +4 -0
- package/rancher-components/RcDropdown/types.ts +22 -0
- package/rancher-components/RcDropdown/useDropdownCollection.ts +46 -0
- package/rancher-components/RcDropdown/useDropdownContext.ts +110 -0
- package/scripts/test-plugins-build.sh +2 -0
- package/scripts/typegen.sh +2 -0
- package/store/catalog.js +1 -1
- package/tsconfig.json +2 -1
- package/types/components/paginatedResourceTable.ts +25 -0
- package/types/components/resourceLabeledSelect.ts +48 -0
- package/types/resources/fleet.d.ts +17 -0
- package/types/shell/index.d.ts +61 -0
- package/utils/auth.js +5 -1
- package/utils/cluster.js +106 -0
- package/utils/fleet.ts +35 -3
- package/utils/ingress.ts +64 -0
- package/utils/uiplugins.ts +56 -44
- package/utils/validators/cron-schedule.js +7 -2
- package/utils/validators/formRules/__tests__/index.test.ts +53 -17
- package/utils/validators/formRules/index.ts +20 -5
- package/vue.config.js +1 -1
- package/components/RelatedWorkloadsTable.vue +0 -50
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { LabelSelectPaginationFunctionOptions } from '@shell/components/form/labeled-select-utils/labeled-select.utils';
|
|
2
|
+
import { LabelSelectPaginateFn } from '@shell/types/components/labeledSelect';
|
|
3
|
+
|
|
4
|
+
type PaginateTypeOverridesFn = (opts: LabelSelectPaginationFunctionOptions) => LabelSelectPaginationFunctionOptions;
|
|
5
|
+
|
|
6
|
+
interface SharedSettings {
|
|
7
|
+
/**
|
|
8
|
+
* Provide specific LabelSelect options for this mode (paginated / not paginated)
|
|
9
|
+
*/
|
|
10
|
+
labelSelectOptions?: { [key: string]: any },
|
|
11
|
+
/**
|
|
12
|
+
* Map, filter, tweak, etc the resources to show in the LabelSelect
|
|
13
|
+
*/
|
|
14
|
+
updateResources?: (resources: any[]) => any[]
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Settings to use when the LabelSelect is paginating
|
|
19
|
+
*/
|
|
20
|
+
export interface ResourceLabeledSelectPaginateSettings extends SharedSettings {
|
|
21
|
+
/**
|
|
22
|
+
* Override the convenience function which fetches a page of results
|
|
23
|
+
*/
|
|
24
|
+
overrideRequest?: LabelSelectPaginateFn,
|
|
25
|
+
/**
|
|
26
|
+
* Override the default settings used in the convenience function to fetch a page of results
|
|
27
|
+
*/
|
|
28
|
+
requestSettings?: PaginateTypeOverridesFn,
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Settings to use when the LabelSelect is fetching all resources (not paginating)
|
|
33
|
+
*/
|
|
34
|
+
export type ResourceLabeledSelectSettings = SharedSettings
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Force a specific mode
|
|
38
|
+
*/
|
|
39
|
+
export enum RESOURCE_LABEL_SELECT_MODE {
|
|
40
|
+
/**
|
|
41
|
+
* Fetch all resources
|
|
42
|
+
*/
|
|
43
|
+
ALL_RESOURCES = 'ALL', // eslint-disable-line no-unused-vars
|
|
44
|
+
/**
|
|
45
|
+
* Determine if all resources are fetched given system settings
|
|
46
|
+
*/
|
|
47
|
+
DYNAMIC = 'DYNAMIC', // eslint-disable-line no-unused-vars
|
|
48
|
+
}
|
|
@@ -24,10 +24,19 @@ export interface BundleNonReadyBundle {
|
|
|
24
24
|
nonReadyStatus: BundleNonReadyResource[],
|
|
25
25
|
}
|
|
26
26
|
|
|
27
|
+
export interface Condition {
|
|
28
|
+
status: string,
|
|
29
|
+
type: string,
|
|
30
|
+
}
|
|
31
|
+
|
|
27
32
|
export interface BundleDeploymentStatus {
|
|
28
33
|
resources?: BundleDeploymentResource[],
|
|
29
34
|
modifiedStatus?: BundleModifiedResource[],
|
|
30
35
|
nonReadyStatus?: BundleNonReadyResource[],
|
|
36
|
+
appliedDeploymentId?: string,
|
|
37
|
+
ready: boolean
|
|
38
|
+
nonModified: boolean
|
|
39
|
+
conditions: Condition[],
|
|
31
40
|
}
|
|
32
41
|
|
|
33
42
|
export interface BundleStatusSummary {
|
|
@@ -38,3 +47,11 @@ export interface BundleStatus {
|
|
|
38
47
|
resourceKey?: BundleResourceKey[],
|
|
39
48
|
summary?: BundleStatusSummary,
|
|
40
49
|
}
|
|
50
|
+
|
|
51
|
+
export interface BundleDeployment {
|
|
52
|
+
spec: {
|
|
53
|
+
deploymentId: string,
|
|
54
|
+
stagedDeploymentId: string,
|
|
55
|
+
}
|
|
56
|
+
status?: BundleDeploymentStatus
|
|
57
|
+
}
|
package/types/shell/index.d.ts
CHANGED
|
@@ -125,6 +125,8 @@ export namespace FLEET {
|
|
|
125
125
|
export let CLUSTER_DISPLAY_NAME: string;
|
|
126
126
|
export let CLUSTER_NAME: string;
|
|
127
127
|
export let BUNDLE_ID: string;
|
|
128
|
+
export let BUNDLE_NAME: string;
|
|
129
|
+
export let BUNDLE_NAMESPACE: string;
|
|
128
130
|
let MANAGED_1: string;
|
|
129
131
|
export { MANAGED_1 as MANAGED };
|
|
130
132
|
let CLUSTER_NAMESPACE_1: string;
|
|
@@ -997,6 +999,9 @@ export namespace LAST_SEEN_TIME {
|
|
|
997
999
|
export { sort_50 as sort };
|
|
998
1000
|
export let tooltip: string;
|
|
999
1001
|
}
|
|
1002
|
+
export namespace EVENT_LAST_SEEN_TIME {
|
|
1003
|
+
let defaultSort: boolean;
|
|
1004
|
+
}
|
|
1000
1005
|
export namespace LAST_HEARTBEAT_TIME {
|
|
1001
1006
|
let name_58: string;
|
|
1002
1007
|
export { name_58 as name };
|
|
@@ -2203,6 +2208,21 @@ export const DEPRECATED: "Deprecated";
|
|
|
2203
2208
|
export const EXPERIMENTAL: "Experimental";
|
|
2204
2209
|
}
|
|
2205
2210
|
|
|
2211
|
+
// @shell/config/version
|
|
2212
|
+
|
|
2213
|
+
declare module '@shell/config/version' {
|
|
2214
|
+
export function isRancherPrime(): boolean;
|
|
2215
|
+
export function getVersionData(): {
|
|
2216
|
+
Version: string;
|
|
2217
|
+
RancherPrime: string;
|
|
2218
|
+
GitCommit: string;
|
|
2219
|
+
};
|
|
2220
|
+
export function setVersionData(v: any): void;
|
|
2221
|
+
export function getKubeVersionData(): {};
|
|
2222
|
+
export function setKubeVersionData(v: any): void;
|
|
2223
|
+
export const CURRENT_RANCHER_VERSION: "2.10";
|
|
2224
|
+
}
|
|
2225
|
+
|
|
2206
2226
|
// @shell/mixins/create-edit-view/impl
|
|
2207
2227
|
|
|
2208
2228
|
declare module '@shell/mixins/create-edit-view/impl' {
|
|
@@ -2402,8 +2422,11 @@ export default class ClusterRepo {
|
|
|
2402
2422
|
spec: {
|
|
2403
2423
|
url: string;
|
|
2404
2424
|
};
|
|
2425
|
+
get _isClusterRepoDisabled(): boolean;
|
|
2405
2426
|
get _availableActions(): any;
|
|
2406
2427
|
refresh(): Promise<void>;
|
|
2428
|
+
disableClusterRepo(): Promise<void>;
|
|
2429
|
+
enableClusterRepo(): Promise<void>;
|
|
2407
2430
|
get isGit(): boolean;
|
|
2408
2431
|
get isOciType(): any;
|
|
2409
2432
|
get isRancherSource(): boolean;
|
|
@@ -2429,6 +2452,8 @@ export default class ClusterRepo {
|
|
|
2429
2452
|
};
|
|
2430
2453
|
})[];
|
|
2431
2454
|
get stateObj(): any;
|
|
2455
|
+
get stateDisplay(): any;
|
|
2456
|
+
get stateBackground(): any;
|
|
2432
2457
|
waitForOperation(operationId: any, timeout: any, interval?: number): any;
|
|
2433
2458
|
}
|
|
2434
2459
|
}
|
|
@@ -2816,6 +2841,7 @@ export default class Resource {
|
|
|
2816
2841
|
get $dispatch(): any;
|
|
2817
2842
|
get $state(): any;
|
|
2818
2843
|
get $rootState(): any;
|
|
2844
|
+
get $plugin(): any;
|
|
2819
2845
|
get customValidationRules(): any[];
|
|
2820
2846
|
get _key(): any;
|
|
2821
2847
|
get schema(): any;
|
|
@@ -3117,6 +3143,10 @@ export default class SteveModel extends HybridModel {
|
|
|
3117
3143
|
set description(value: any);
|
|
3118
3144
|
get description(): any;
|
|
3119
3145
|
_description: any;
|
|
3146
|
+
/**
|
|
3147
|
+
* Get all model extensions for this model
|
|
3148
|
+
*/
|
|
3149
|
+
get modelExtensions(): any;
|
|
3120
3150
|
cleanForSave(data: any, forNew: any): any;
|
|
3121
3151
|
}
|
|
3122
3152
|
import HybridModel from './hybrid-class';
|
|
@@ -3153,6 +3183,31 @@ export namespace actions {
|
|
|
3153
3183
|
}
|
|
3154
3184
|
}
|
|
3155
3185
|
|
|
3186
|
+
// @shell/store/plugins
|
|
3187
|
+
|
|
3188
|
+
declare module '@shell/store/plugins' {
|
|
3189
|
+
export function simplify(key: any): any;
|
|
3190
|
+
export function configureCredential(name: any, opt: any): void;
|
|
3191
|
+
export function mapDriver(name: any, to: any): void;
|
|
3192
|
+
export const rke1Supports: string[];
|
|
3193
|
+
export const likelyFields: any[];
|
|
3194
|
+
export const iffyFields: any[];
|
|
3195
|
+
export const fullFields: any[];
|
|
3196
|
+
export const prefixFields: any[];
|
|
3197
|
+
export const suffixFields: any[];
|
|
3198
|
+
export function state(): {};
|
|
3199
|
+
export namespace getters {
|
|
3200
|
+
function credentialOptions(): (name: any) => any;
|
|
3201
|
+
function credentialDriverFor(): (name: any) => any;
|
|
3202
|
+
function credentialFieldForDriver(): (name: any) => any;
|
|
3203
|
+
function clusterDrivers(): any[];
|
|
3204
|
+
function schemaForDriver(state: any, getters: any, rootState: any, rootGetters: any): (name: any) => any;
|
|
3205
|
+
function fieldNamesForDriver(state: any, getters: any): (name: any) => Promise<string[]>;
|
|
3206
|
+
function fieldsForDriver(state: any, getters: any): (name: any) => Promise<{}>;
|
|
3207
|
+
function cloudProviderForDriver(): (name: any) => any;
|
|
3208
|
+
}
|
|
3209
|
+
}
|
|
3210
|
+
|
|
3156
3211
|
// @shell/store/prefs
|
|
3157
3212
|
|
|
3158
3213
|
declare module '@shell/store/prefs' {
|
|
@@ -3440,6 +3495,8 @@ export function filterHiddenLocalCluster(mgmtClusters: any, store: any): any;
|
|
|
3440
3495
|
*/
|
|
3441
3496
|
export function abbreviateClusterName(input: string): string;
|
|
3442
3497
|
export function labelForAddon(store: any, name: any, configuration?: boolean): any;
|
|
3498
|
+
export function filterOutDeprecatedPatchVersions(allVersions: any, currentVersion: any): any;
|
|
3499
|
+
export function getAllOptionsAfterCurrentVersion(store: any, versions: any, currentVersion: any, defaultVersion: any): any;
|
|
3443
3500
|
}
|
|
3444
3501
|
|
|
3445
3502
|
// @shell/utils/color
|
|
@@ -4502,6 +4559,10 @@ export function containerImages(spec: any, getters: any, errors: any): void;
|
|
|
4502
4559
|
|
|
4503
4560
|
declare module '@shell/utils/validators/cron-schedule' {
|
|
4504
4561
|
export function cronSchedule(schedule: string, getters: any, errors: any): void;
|
|
4562
|
+
export namespace cronScheduleRule {
|
|
4563
|
+
function validation(text: any): string;
|
|
4564
|
+
let message: string;
|
|
4565
|
+
}
|
|
4505
4566
|
}
|
|
4506
4567
|
|
|
4507
4568
|
// @shell/utils/validators/flow-output
|
package/utils/auth.js
CHANGED
|
@@ -116,7 +116,11 @@ export const checkSchemasForFindAllHash = (types, store) => {
|
|
|
116
116
|
const validSchema = value.schemaValidator ? value.schemaValidator(schema) : !!schema;
|
|
117
117
|
|
|
118
118
|
if (validSchema) {
|
|
119
|
-
|
|
119
|
+
const res = store.dispatch(`${ value.inStoreType }/findAll`, { type: value.type, opt: value.opt } );
|
|
120
|
+
|
|
121
|
+
if (!value.skipWait) {
|
|
122
|
+
hash[key] = res;
|
|
123
|
+
}
|
|
120
124
|
}
|
|
121
125
|
}
|
|
122
126
|
|
package/utils/cluster.js
CHANGED
|
@@ -4,6 +4,8 @@ import { CAPI } from '@shell/config/labels-annotations';
|
|
|
4
4
|
import { MANAGEMENT, VIRTUAL_HARVESTER_PROVIDER } from '@shell/config/types';
|
|
5
5
|
import { SETTING } from '@shell/config/settings';
|
|
6
6
|
import { PaginationFilterField, PaginationParamFilter } from '@shell/types/store/pagination.types';
|
|
7
|
+
import { compare, sortable } from '@shell/utils/version';
|
|
8
|
+
import { sortBy } from '@shell/utils/sort';
|
|
7
9
|
|
|
8
10
|
/**
|
|
9
11
|
* Combination of paginationFilterHiddenLocalCluster and paginationFilterOnlyKubernetesClusters
|
|
@@ -190,3 +192,107 @@ export function labelForAddon(store, name, configuration = true) {
|
|
|
190
192
|
|
|
191
193
|
return store.getters['i18n/withFallback'](key, null, fallback);
|
|
192
194
|
}
|
|
195
|
+
|
|
196
|
+
function getMostRecentPatchVersions(sortedVersions) {
|
|
197
|
+
// Get the most recent patch version for each Kubernetes minor version.
|
|
198
|
+
const versionMap = {};
|
|
199
|
+
|
|
200
|
+
sortedVersions.forEach((version) => {
|
|
201
|
+
const majorMinor = `${ semver.major(version.value) }.${ semver.minor(version.value) }`;
|
|
202
|
+
|
|
203
|
+
if (!versionMap[majorMinor]) {
|
|
204
|
+
// Because we start with a sorted list of versions, we know the
|
|
205
|
+
// highest patch version is first in the list, so we only keep the
|
|
206
|
+
// first of each minor version in the list.
|
|
207
|
+
versionMap[majorMinor] = version.value;
|
|
208
|
+
}
|
|
209
|
+
});
|
|
210
|
+
|
|
211
|
+
return versionMap;
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
export function filterOutDeprecatedPatchVersions(allVersions, currentVersion) {
|
|
215
|
+
// Get the most recent patch version for each Kubernetes minor version.
|
|
216
|
+
const mostRecentPatchVersions = getMostRecentPatchVersions(allVersions);
|
|
217
|
+
|
|
218
|
+
const filteredVersions = allVersions.filter((version) => {
|
|
219
|
+
// Always show pre-releases
|
|
220
|
+
if (semver.prerelease(version.value)) {
|
|
221
|
+
return true;
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
const majorMinor = `${ semver.major(version.value) }.${ semver.minor(version.value) }`;
|
|
225
|
+
|
|
226
|
+
// Always show current version, else show if we haven't shown anything for this major.minor version yet
|
|
227
|
+
if (version.value === currentVersion || mostRecentPatchVersions[majorMinor] === version.value) {
|
|
228
|
+
return true;
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
return false;
|
|
232
|
+
});
|
|
233
|
+
|
|
234
|
+
return filteredVersions;
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
export function getAllOptionsAfterCurrentVersion(store, versions, currentVersion, defaultVersion) {
|
|
238
|
+
const out = (versions || []).filter((obj) => !!obj.serverArgs).map((obj) => {
|
|
239
|
+
let disabled = false;
|
|
240
|
+
let experimental = false;
|
|
241
|
+
let isCurrentVersion = false;
|
|
242
|
+
let label = obj.id;
|
|
243
|
+
|
|
244
|
+
if (currentVersion) {
|
|
245
|
+
disabled = compare(obj.id, currentVersion) < 0;
|
|
246
|
+
isCurrentVersion = compare(obj.id, currentVersion) === 0;
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
if (defaultVersion) {
|
|
250
|
+
experimental = compare(defaultVersion, obj.id) < 0;
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
if (isCurrentVersion) {
|
|
254
|
+
label = `${ label } ${ store.getters['i18n/t']('cluster.kubernetesVersion.current') }`;
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
if (experimental) {
|
|
258
|
+
label = `${ label } ${ store.getters['i18n/t']('cluster.kubernetesVersion.experimental') }`;
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
return {
|
|
262
|
+
label,
|
|
263
|
+
value: obj.id,
|
|
264
|
+
sort: sortable(obj.id),
|
|
265
|
+
serverArgs: obj.serverArgs,
|
|
266
|
+
agentArgs: obj.agentArgs,
|
|
267
|
+
charts: obj.charts,
|
|
268
|
+
disabled,
|
|
269
|
+
};
|
|
270
|
+
});
|
|
271
|
+
|
|
272
|
+
if (currentVersion && !out.find((obj) => obj.value === currentVersion)) {
|
|
273
|
+
out.push({
|
|
274
|
+
label: `${ currentVersion } ${ store.getters['i18n/t']('cluster.kubernetesVersion.current') }`,
|
|
275
|
+
value: currentVersion,
|
|
276
|
+
sort: sortable(currentVersion),
|
|
277
|
+
});
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
const sorted = sortBy(out, 'sort:desc');
|
|
281
|
+
|
|
282
|
+
const mostRecentPatchVersions = getMostRecentPatchVersions(sorted);
|
|
283
|
+
|
|
284
|
+
const sortedWithDeprecatedLabel = sorted.map((optionData) => {
|
|
285
|
+
const majorMinor = `${ semver.major(optionData.value) }.${ semver.minor(optionData.value) }`;
|
|
286
|
+
|
|
287
|
+
if (mostRecentPatchVersions[majorMinor] === optionData.value) {
|
|
288
|
+
return optionData;
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
return {
|
|
292
|
+
...optionData,
|
|
293
|
+
label: `${ optionData.label } ${ store.getters['i18n/t']('cluster.kubernetesVersion.deprecated') }`
|
|
294
|
+
};
|
|
295
|
+
});
|
|
296
|
+
|
|
297
|
+
return sortedWithDeprecatedLabel;
|
|
298
|
+
}
|
package/utils/fleet.ts
CHANGED
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
import {
|
|
2
2
|
BundleDeploymentResource,
|
|
3
3
|
BundleResourceKey,
|
|
4
|
+
BundleDeployment,
|
|
4
5
|
BundleDeploymentStatus,
|
|
5
6
|
BundleStatus,
|
|
7
|
+
Condition,
|
|
6
8
|
} from '@shell/types/resources/fleet';
|
|
7
9
|
import { STATES_ENUM } from '@shell/plugins/dashboard-store/resource-class';
|
|
8
|
-
import { FLEET as
|
|
10
|
+
import { FLEET as FLEET_LABELS } from '@shell/config/labels-annotations';
|
|
9
11
|
|
|
10
12
|
interface Resource extends BundleDeploymentResource {
|
|
11
13
|
state: string,
|
|
@@ -28,6 +30,14 @@ function resourceKey(r: BundleResourceKey): string {
|
|
|
28
30
|
return `${ r.kind }/${ r.namespace }/${ r.name }`;
|
|
29
31
|
}
|
|
30
32
|
|
|
33
|
+
function conditionIsTrue(conditions: Condition[] | undefined, type: string): boolean {
|
|
34
|
+
if (!conditions) {
|
|
35
|
+
return false;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
return !!conditions.find((c) => c.type === type && c.status.toLowerCase() === 'true');
|
|
39
|
+
}
|
|
40
|
+
|
|
31
41
|
class Fleet {
|
|
32
42
|
resourceId(r: BundleResourceKey): string {
|
|
33
43
|
return r.namespace ? `${ r.namespace }/${ r.name }` : r.name;
|
|
@@ -147,11 +157,33 @@ class Fleet {
|
|
|
147
157
|
}
|
|
148
158
|
|
|
149
159
|
clusterIdFromBundleDeploymentLabels(labels?: Labels): string {
|
|
150
|
-
const clusterNamespace = labels?.[
|
|
151
|
-
const clusterName = labels?.[
|
|
160
|
+
const clusterNamespace = labels?.[FLEET_LABELS.CLUSTER_NAMESPACE];
|
|
161
|
+
const clusterName = labels?.[FLEET_LABELS.CLUSTER];
|
|
152
162
|
|
|
153
163
|
return `${ clusterNamespace }/${ clusterName }`;
|
|
154
164
|
}
|
|
165
|
+
|
|
166
|
+
bundleIdFromBundleDeploymentLabels(labels?: Labels): string {
|
|
167
|
+
const bundleNamespace = labels?.[FLEET_LABELS.BUNDLE_NAMESPACE];
|
|
168
|
+
const bundleName = labels?.[FLEET_LABELS.BUNDLE_NAME];
|
|
169
|
+
|
|
170
|
+
return `${ bundleNamespace }/${ bundleName }`;
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
bundleDeploymentState(bd: BundleDeployment): string {
|
|
174
|
+
// Ported from https://github.com/rancher/fleet/blob/534dbfdd6f74caf97bccd4cf977e42c5009b2432/internal/cmd/controller/summary/summary.go#L89
|
|
175
|
+
if (bd.status?.appliedDeploymentId !== bd.spec.deploymentId) {
|
|
176
|
+
return conditionIsTrue(bd.status?.conditions, 'Deployed') ? STATES_ENUM.WAIT_APPLIED : STATES_ENUM.ERR_APPLIED;
|
|
177
|
+
} else if (!bd.status?.ready) {
|
|
178
|
+
return STATES_ENUM.NOT_READY;
|
|
179
|
+
} else if (bd.spec.deploymentId !== bd.spec.stagedDeploymentId) {
|
|
180
|
+
return STATES_ENUM.OUT_OF_SYNC;
|
|
181
|
+
} else if (!bd.status?.nonModified) {
|
|
182
|
+
return STATES_ENUM.MODIFIED;
|
|
183
|
+
} else {
|
|
184
|
+
return STATES_ENUM.READY;
|
|
185
|
+
}
|
|
186
|
+
}
|
|
155
187
|
}
|
|
156
188
|
|
|
157
189
|
const instance = new Fleet();
|
package/utils/ingress.ts
ADDED
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import { SECRET, SERVICE } from '@shell/config/types';
|
|
2
|
+
import { SECRET_TYPES as TYPES } from '@shell/config/secret';
|
|
3
|
+
import { VuexStore } from '@shell/types/store/vuex';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Helper class for common functionality shared between the detail and edit ingress pages
|
|
7
|
+
*
|
|
8
|
+
* This could be an untyped mixin.. but this setups up us better for the future
|
|
9
|
+
*/
|
|
10
|
+
class IngressDetailEditHelper {
|
|
11
|
+
private $store: VuexStore;
|
|
12
|
+
private namespace: string;
|
|
13
|
+
|
|
14
|
+
constructor({
|
|
15
|
+
$store,
|
|
16
|
+
namespace,
|
|
17
|
+
}: {
|
|
18
|
+
$store: VuexStore
|
|
19
|
+
namespace: string,
|
|
20
|
+
}) {
|
|
21
|
+
this.$store = $store;
|
|
22
|
+
this.namespace = namespace;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Fetch services that will either be used to show
|
|
27
|
+
* - Create - the possible rule's target service
|
|
28
|
+
* - Edit - the selected and possible rule's target service
|
|
29
|
+
* - Detail - the selected rule's target service
|
|
30
|
+
*/
|
|
31
|
+
async fetchServices(args?: { namespace: string}): Promise<any[]> {
|
|
32
|
+
return this.$store.dispatch('cluster/findAll', { type: SERVICE, opt: { namespaced: args?.namespace || this.namespace } });
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Fetch secrets that will either be used to show
|
|
37
|
+
* - Create - the possible secrets to use as a certificates
|
|
38
|
+
* - Edit - the selected and possible secrets to use as a certificates
|
|
39
|
+
* - Detail - the selected secrets to use as certificates
|
|
40
|
+
*/
|
|
41
|
+
async fetchSecrets(args?: { namespace: string}): Promise<any[]> {
|
|
42
|
+
return this.$store.dispatch('cluster/findAll', { type: SECRET, opt: { namespaced: args?.namespace || this.namespace } });
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
findAndMapCerts(secrets: any[]) {
|
|
46
|
+
return secrets
|
|
47
|
+
.filter((secret) => secret._type === TYPES.TLS)
|
|
48
|
+
.map((secret) => {
|
|
49
|
+
const { id } = secret;
|
|
50
|
+
|
|
51
|
+
return id.slice(id.indexOf('/') + 1);
|
|
52
|
+
});
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
findAndMapServiceTargets(services: any[]) {
|
|
56
|
+
return services.map((service) => ({
|
|
57
|
+
label: service.metadata.name,
|
|
58
|
+
value: service.metadata.name,
|
|
59
|
+
ports: service.spec.ports?.map((p: any) => p.port)
|
|
60
|
+
}));
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
export default IngressDetailEditHelper;
|
package/utils/uiplugins.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { matchesSomeRegex } from '@shell/utils/string';
|
|
1
2
|
import { CATALOG as CATALOG_ANNOTATIONS } from '@shell/config/labels-annotations';
|
|
2
3
|
import { CATALOG } from '@shell/config/types';
|
|
3
4
|
import { UI_PLUGIN_BASE_URL, isSupportedChartVersion } from '@shell/config/uiplugins';
|
|
@@ -158,37 +159,56 @@ export async function installHelmChart(repo: any, chart: any, values: any = {},
|
|
|
158
159
|
}
|
|
159
160
|
|
|
160
161
|
/**
|
|
161
|
-
* Get the Helm repository object
|
|
162
162
|
*
|
|
163
163
|
* @param store Vue store
|
|
164
|
-
* @param url
|
|
165
|
-
* @param branch The branch of the Helm repository
|
|
164
|
+
* @param url Repository Url
|
|
166
165
|
* @returns HelmRepository
|
|
167
166
|
*/
|
|
168
|
-
export async function
|
|
167
|
+
export async function getHelmRepositoryExact(store: any, url: string): Promise<HelmRepository> {
|
|
168
|
+
return await getHelmRepository(store, (repository: any) => {
|
|
169
|
+
const target = repository.spec?.gitRepo || repository.spec?.url;
|
|
170
|
+
|
|
171
|
+
return target === url;
|
|
172
|
+
});
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
/**
|
|
176
|
+
*
|
|
177
|
+
* @param store Vue store
|
|
178
|
+
* @param urlRegexes Regex to match a community repository
|
|
179
|
+
* @returns HelmRepository
|
|
180
|
+
*/
|
|
181
|
+
export async function getHelmRepositoryMatch(store: any, urlRegexes: string[]): Promise<HelmRepository> {
|
|
182
|
+
return await getHelmRepository(store, (repository: any) => {
|
|
183
|
+
const target = repository.spec?.gitBranch ? repository.spec?.gitRepo : repository.spec?.url;
|
|
184
|
+
|
|
185
|
+
return matchesSomeRegex(target, urlRegexes);
|
|
186
|
+
});
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
/**
|
|
190
|
+
*
|
|
191
|
+
* @param store Vue store
|
|
192
|
+
* @param matchFn Match function for repository's urls
|
|
193
|
+
* @returns HelmRepository
|
|
194
|
+
*/
|
|
195
|
+
async function getHelmRepository(store: any, matchFn: (repository: any) => boolean): Promise<HelmRepository> {
|
|
169
196
|
if (store.getters['management/schemaFor'](CATALOG.CLUSTER_REPO)) {
|
|
170
197
|
const repos = await store.dispatch('management/findAll', { type: CATALOG.CLUSTER_REPO, opt: { force: true, watch: false } });
|
|
171
198
|
|
|
172
|
-
return repos.find(
|
|
173
|
-
const target = branch ? r.spec?.gitRepo : r.spec?.url ;
|
|
174
|
-
|
|
175
|
-
return target === url;
|
|
176
|
-
});
|
|
199
|
+
return repos.find(matchFn);
|
|
177
200
|
} else {
|
|
178
201
|
throw new Error('No permissions');
|
|
179
202
|
}
|
|
180
203
|
}
|
|
181
204
|
|
|
182
205
|
/**
|
|
183
|
-
* Refresh the Helm repository
|
|
184
|
-
* Ensures that we find the latest extension versions
|
|
185
206
|
*
|
|
186
207
|
* @param store Vue store
|
|
187
|
-
* @param
|
|
188
|
-
* @param gitBranch Extension Repository branch
|
|
208
|
+
* @param url Repository Url
|
|
189
209
|
*/
|
|
190
|
-
export async function refreshHelmRepository(store: any,
|
|
191
|
-
const repository = await
|
|
210
|
+
export async function refreshHelmRepository(store: any, url: string): Promise<void> {
|
|
211
|
+
const repository = await getHelmRepositoryExact(store, url);
|
|
192
212
|
|
|
193
213
|
const now = (new Date()).toISOString().replace(/\.\d+Z$/, 'Z');
|
|
194
214
|
|
|
@@ -202,40 +222,32 @@ export async function refreshHelmRepository(store: any, gitRepo: string, gitBran
|
|
|
202
222
|
}
|
|
203
223
|
|
|
204
224
|
/**
|
|
205
|
-
* Ensure the required Helm Repository exits, if it does not, add it with the specified name
|
|
206
|
-
*
|
|
207
|
-
* Wait until the newly added repository has been downloaded
|
|
208
225
|
*
|
|
209
226
|
* @param store Vue store
|
|
210
|
-
* @param
|
|
211
|
-
* @param
|
|
212
|
-
* @param branch
|
|
213
|
-
* @returns HelmRepository
|
|
227
|
+
* @param name Repository name
|
|
228
|
+
* @param url Repository Url
|
|
229
|
+
* @param branch Repository Branch
|
|
230
|
+
* @returns HelmRepository
|
|
214
231
|
*/
|
|
215
|
-
export async function
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
type: CATALOG.CLUSTER_REPO,
|
|
222
|
-
metadata: { name },
|
|
223
|
-
spec: {} as any
|
|
224
|
-
};
|
|
225
|
-
|
|
226
|
-
if (branch) {
|
|
227
|
-
data.spec.gitBranch = branch;
|
|
228
|
-
data.spec.gitRepo = url;
|
|
229
|
-
} else {
|
|
230
|
-
data.spec.url = url;
|
|
231
|
-
}
|
|
232
|
-
|
|
233
|
-
// Create a model for the new repository and save it
|
|
234
|
-
const repo = await store.dispatch('management/create', data);
|
|
232
|
+
export async function createHelmRepository(store: any, name: string, url: string, branch?: string): Promise<HelmRepository> {
|
|
233
|
+
const data = {
|
|
234
|
+
type: CATALOG.CLUSTER_REPO,
|
|
235
|
+
metadata: { name },
|
|
236
|
+
spec: {} as any
|
|
237
|
+
};
|
|
235
238
|
|
|
236
|
-
|
|
239
|
+
if (branch) {
|
|
240
|
+
data.spec.gitBranch = branch;
|
|
241
|
+
data.spec.gitRepo = url;
|
|
242
|
+
} else {
|
|
243
|
+
data.spec.url = url;
|
|
237
244
|
}
|
|
238
245
|
|
|
246
|
+
// Create a model for the new repository and save it
|
|
247
|
+
const repo = await store.dispatch('management/create', data);
|
|
248
|
+
|
|
249
|
+
const helmRepo = await repo.save();
|
|
250
|
+
|
|
239
251
|
// Poll the repository until it says it has been downloaded
|
|
240
252
|
let fetched = false;
|
|
241
253
|
let tries = 0;
|
|
@@ -278,7 +290,7 @@ export async function ensureHelmRepository(store: any, url: string, name: string
|
|
|
278
290
|
* Get the given Helm Chart from the specified Helm Repository
|
|
279
291
|
*
|
|
280
292
|
* @param store Vue store
|
|
281
|
-
* @param repository
|
|
293
|
+
* @param repository Repository Url
|
|
282
294
|
* @param chartName Helm Chart name
|
|
283
295
|
* @returns Helm Chart
|
|
284
296
|
*/
|
|
@@ -2,8 +2,13 @@ import cronstrue from 'cronstrue';
|
|
|
2
2
|
|
|
3
3
|
export function cronSchedule(schedule = '', getters, errors) {
|
|
4
4
|
try {
|
|
5
|
-
|
|
5
|
+
cronScheduleRule.validation(schedule);
|
|
6
6
|
} catch (e) {
|
|
7
|
-
errors.push(getters['i18n/t'](
|
|
7
|
+
errors.push(getters['i18n/t'](cronScheduleRule.message));
|
|
8
8
|
}
|
|
9
9
|
}
|
|
10
|
+
|
|
11
|
+
export const cronScheduleRule = {
|
|
12
|
+
validation: (text) => cronstrue.toString(text, { verbose: true }),
|
|
13
|
+
message: 'validation.invalidCron'
|
|
14
|
+
};
|