@rancher/shell 3.0.8-rc.9 → 3.0.8
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/apis/impl/apis.ts +61 -0
- package/apis/index.ts +40 -0
- package/apis/intf/modal.ts +90 -0
- package/apis/intf/shell.ts +36 -0
- package/apis/intf/slide-in.ts +98 -0
- package/apis/intf/system.ts +41 -0
- package/apis/shell/__tests__/modal.test.ts +80 -0
- package/apis/shell/__tests__/notifications.test.ts +71 -0
- package/apis/shell/__tests__/slide-in.test.ts +54 -0
- package/apis/shell/__tests__/system.test.ts +129 -0
- package/apis/shell/index.ts +38 -0
- package/apis/shell/modal.ts +41 -0
- package/apis/shell/notifications.ts +65 -0
- package/apis/shell/slide-in.ts +33 -0
- package/apis/shell/system.ts +65 -0
- package/apis/vue-shim.d.ts +11 -0
- package/assets/styles/global/_tooltip.scss +6 -1
- package/assets/translations/en-us.yaml +5 -0
- package/components/ActionMenuShell.vue +3 -1
- package/components/CruResource.vue +8 -1
- package/components/Drawer/ResourceDetailDrawer/__tests__/composables.test.ts +50 -1
- package/components/Drawer/ResourceDetailDrawer/composables.ts +19 -0
- package/components/Drawer/ResourceDetailDrawer/index.vue +3 -1
- package/components/LocaleSelector.vue +2 -2
- package/components/ModalManager.vue +11 -1
- package/components/Questions/__tests__/Yaml.test.ts +1 -1
- package/components/RelatedResources.vue +5 -0
- package/components/Resource/Detail/ResourcePopover/index.vue +5 -1
- package/components/ResourceDetail/Masthead/latest.vue +23 -21
- package/components/ResourceDetail/index.vue +3 -0
- package/components/ResourceTable.vue +54 -21
- package/components/SlideInPanelManager.vue +16 -11
- package/components/SortableTable/THead.vue +2 -1
- package/components/SortableTable/index.vue +20 -2
- package/components/Tabbed/index.vue +37 -2
- package/components/__tests__/NamespaceFilter.test.ts +49 -0
- package/components/auth/SelectPrincipal.vue +4 -0
- package/components/auth/login/ldap.vue +3 -3
- package/components/fleet/FleetSecretSelector.vue +1 -1
- package/components/form/KeyValue.vue +1 -1
- package/components/form/NameNsDescription.vue +1 -1
- package/components/form/NodeScheduling.vue +2 -2
- package/components/form/ResourceTabs/composable.ts +2 -2
- package/components/form/ResourceTabs/index.vue +0 -2
- package/components/form/__tests__/NameNsDescription.test.ts +42 -0
- package/components/formatter/LinkName.vue +5 -0
- package/components/nav/Group.vue +25 -7
- package/components/nav/Header.vue +1 -1
- package/components/nav/NamespaceFilter.vue +1 -0
- package/components/nav/Type.vue +17 -6
- package/components/nav/WindowManager/panels/TabBodyContainer.vue +1 -1
- package/components/nav/__tests__/Type.test.ts +59 -0
- package/composables/cruResource.ts +27 -0
- package/composables/focusTrap.ts +3 -1
- package/composables/resourceDetail.ts +15 -0
- package/composables/useLabeledFormElement.ts +3 -4
- package/config/product/fleet.js +1 -1
- package/config/router/navigation-guards/clusters.js +3 -3
- package/config/router/navigation-guards/products.js +1 -1
- package/config/router/routes.js +1 -5
- package/core/__tests__/extension-manager-impl.test.js +437 -0
- package/core/extension-manager-impl.js +6 -27
- package/core/plugin-helpers.ts +2 -2
- package/core/plugin.ts +9 -1
- package/core/plugins-loader.js +2 -2
- package/core/types-provisioning.ts +4 -0
- package/core/types.ts +35 -0
- package/detail/provisioning.cattle.io.cluster.vue +8 -6
- package/dialog/DeveloperLoadExtensionDialog.vue +1 -1
- package/dialog/MoveNamespaceDialog.vue +20 -4
- package/dialog/SearchDialog.vue +1 -0
- package/dialog/__tests__/MoveNamespaceDialog.test.ts +249 -0
- package/directives/__tests__/clean-tooltip.test.ts +298 -0
- package/directives/clean-tooltip.ts +234 -0
- package/edit/__tests__/fleet.cattle.io.gitrepo.test.ts +2 -2
- package/edit/__tests__/fleet.cattle.io.helmop.test.ts +98 -1
- package/edit/fleet.cattle.io.helmop.vue +5 -0
- package/edit/provisioning.cattle.io.cluster/__tests__/rke2.test.ts +21 -21
- package/edit/provisioning.cattle.io.cluster/index.vue +5 -5
- package/edit/provisioning.cattle.io.cluster/rke2.vue +8 -8
- package/edit/resources.cattle.io.restore.vue +1 -1
- package/edit/workload/Job.vue +2 -2
- package/edit/workload/index.vue +1 -1
- package/initialize/install-plugins.js +4 -5
- package/machine-config/azure.vue +1 -1
- package/machine-config/components/GCEImage.vue +1 -1
- package/models/__tests__/provisioning.cattle.io.cluster.test.ts +16 -0
- package/models/chart.js +70 -74
- package/models/management.cattle.io.cluster.js +1 -1
- package/models/provisioning.cattle.io.cluster.js +11 -3
- package/package.json +7 -7
- package/pages/auth/login.vue +3 -3
- package/pages/auth/setup.vue +1 -1
- package/pages/auth/verify.vue +3 -3
- package/pages/c/_cluster/apps/charts/index.vue +122 -24
- package/pages/c/_cluster/apps/charts/install.vue +33 -0
- package/pages/c/_cluster/explorer/__tests__/index.test.ts +1 -1
- package/pages/c/_cluster/fleet/index.vue +4 -7
- package/pages/c/_cluster/settings/index.vue +5 -0
- package/pkg/auto-import.js +3 -3
- package/pkg/dynamic-importer.lib.js +1 -1
- package/pkg/import.js +1 -1
- package/plugins/__tests__/mutations.tests.ts +179 -0
- package/plugins/dashboard-store/getters.js +1 -1
- package/plugins/dashboard-store/model-loader.js +1 -1
- package/plugins/dashboard-store/mutations.js +23 -2
- package/plugins/dashboard-store/resource-class.js +8 -3
- package/plugins/plugin.js +2 -2
- package/plugins/steve/__tests__/steve-pagination-utils.test.ts +301 -128
- package/plugins/steve/steve-class.js +1 -1
- package/plugins/steve/steve-pagination-utils.ts +108 -43
- package/rancher-components/Form/Checkbox/Checkbox.vue +1 -1
- package/rancher-components/Form/LabeledInput/LabeledInput.vue +1 -1
- package/rancher-components/RcDropdown/useDropdownContext.ts +2 -4
- package/rancher-components/RcItemCard/RcItemCard.vue +1 -1
- package/scripts/publish-shell.sh +25 -0
- package/store/__tests__/catalog.test.ts +1 -1
- package/store/__tests__/type-map.test.ts +164 -2
- package/store/auth.js +23 -11
- package/store/i18n.js +3 -3
- package/store/index.js +5 -3
- package/store/notifications.ts +2 -0
- package/store/prefs.js +2 -2
- package/store/type-map.js +17 -7
- package/types/internal-api/shell/modal.d.ts +6 -6
- package/types/notifications/index.ts +126 -15
- package/types/rancher/index.d.ts +9 -0
- package/types/shell/index.d.ts +16 -1
- package/types/vue-shim.d.ts +5 -4
- package/utils/__tests__/router.test.js +238 -0
- package/utils/cluster.js +4 -1
- package/utils/fleet.ts +8 -1
- package/utils/pagination-utils.ts +2 -2
- package/utils/pagination-wrapper.ts +1 -1
- package/utils/router.js +50 -0
- package/utils/unit-tests/pagination-utils.spec.ts +8 -8
- package/vue.config.js +3 -3
- package/composables/useExtensionManager.ts +0 -17
- package/core/__test__/extension-manager-impl.test.js +0 -236
- package/core/plugins.js +0 -38
- package/directives/clean-tooltip.js +0 -32
- package/plugins/internal-api/index.ts +0 -37
- package/plugins/internal-api/shared/base-api.ts +0 -13
- package/plugins/internal-api/shell/shell.api.ts +0 -108
- package/types/internal-api/shell/growl.d.ts +0 -25
- package/types/internal-api/shell/slideIn.d.ts +0 -15
|
@@ -37,20 +37,35 @@ interface Namespace extends ModelNamespace {
|
|
|
37
37
|
}
|
|
38
38
|
}
|
|
39
39
|
|
|
40
|
+
interface NamespaceProjectFilterResult {
|
|
41
|
+
/**
|
|
42
|
+
* True if the ns should be filtered IN. False if filtered OUT.
|
|
43
|
+
*/
|
|
44
|
+
[nsName: string]: boolean;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* Helper class, contains namespace / project filter specific functions
|
|
49
|
+
*/
|
|
40
50
|
class NamespaceProjectFilters {
|
|
41
51
|
/**
|
|
42
52
|
* User needs all resources.... except if there's some settings which should remove resources in specific circumstances
|
|
43
53
|
*/
|
|
44
54
|
protected handlePrefAndSettingFilter(args: {
|
|
45
55
|
allNamespaces: Namespace[],
|
|
56
|
+
/**
|
|
57
|
+
* Reserved / Obscure namespaces are ones used to support clusters and users. By default these are hidden
|
|
58
|
+
*/
|
|
46
59
|
showReservedRancherNamespaces: boolean,
|
|
60
|
+
/**
|
|
61
|
+
* Has product config disabled system projects and namespaces
|
|
62
|
+
*/
|
|
47
63
|
productHidesSystemNamespaces: boolean,
|
|
48
|
-
}):
|
|
64
|
+
}): NamespaceProjectFilterResult {
|
|
49
65
|
const { allNamespaces, showReservedRancherNamespaces, productHidesSystemNamespaces } = args;
|
|
50
66
|
|
|
51
|
-
// These are AND'd together
|
|
52
67
|
// Not ns 1 AND ns 2
|
|
53
|
-
|
|
68
|
+
return allNamespaces.reduce((res, ns) => {
|
|
54
69
|
// Links to ns.isObscure and covers things like `c-`, `user-`, etc (see OBSCURE_NAMESPACE_PREFIX)
|
|
55
70
|
const hideObscure = showReservedRancherNamespaces ? false : ns.isObscure;
|
|
56
71
|
|
|
@@ -58,23 +73,11 @@ class NamespaceProjectFilters {
|
|
|
58
73
|
const hideSystem = productHidesSystemNamespaces ? ns.isSystem : false;
|
|
59
74
|
|
|
60
75
|
if (hideObscure || hideSystem) {
|
|
61
|
-
res
|
|
76
|
+
res[ns.name] = false;
|
|
62
77
|
}
|
|
63
78
|
|
|
64
79
|
return res;
|
|
65
|
-
},
|
|
66
|
-
|
|
67
|
-
if (filterNamespaces.length) {
|
|
68
|
-
return [new PaginationParamFilter({
|
|
69
|
-
fields: [{
|
|
70
|
-
value: filterNamespaces.join(','),
|
|
71
|
-
equality: PaginationFilterEquality.NOT_IN,
|
|
72
|
-
field: 'metadata.namespace',
|
|
73
|
-
}],
|
|
74
|
-
})];
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
return [];
|
|
80
|
+
}, {} as NamespaceProjectFilterResult);
|
|
78
81
|
}
|
|
79
82
|
|
|
80
83
|
/**
|
|
@@ -88,31 +91,88 @@ class NamespaceProjectFilters {
|
|
|
88
91
|
allNamespaces: Namespace[],
|
|
89
92
|
isAllSystem: boolean,
|
|
90
93
|
isAllUser: boolean,
|
|
91
|
-
}) {
|
|
92
|
-
const { allNamespaces, isAllSystem } = args;
|
|
94
|
+
}): NamespaceProjectFilterResult {
|
|
95
|
+
const { allNamespaces, isAllSystem, isAllUser } = args;
|
|
93
96
|
const allSystem = allNamespaces.filter((ns) => ns.isSystem);
|
|
94
97
|
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
98
|
+
return allSystem.reduce((res, ns) => {
|
|
99
|
+
if (isAllSystem) {
|
|
100
|
+
// We want to filter IN system namespaces
|
|
101
|
+
res[ns.name] = true;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
if (isAllUser) {
|
|
105
|
+
// We want to filter OUT system namespaces
|
|
106
|
+
res[ns.name] = false;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
return res;
|
|
110
|
+
}, {} as NamespaceProjectFilterResult);
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
/**
|
|
114
|
+
* Combine result `b` into `a` and return result
|
|
115
|
+
*/
|
|
116
|
+
protected combineNsProjectFilterResults(a: NamespaceProjectFilterResult, b: NamespaceProjectFilterResult): NamespaceProjectFilterResult {
|
|
117
|
+
// Start with `a`
|
|
118
|
+
const res = { ...a };
|
|
119
|
+
|
|
120
|
+
// Merge entries from `b` into `a` if they don't exist in `a`. This maintains a hierarchy
|
|
121
|
+
// 1. if something has been excluded in `a` ignore requests to include given `b`
|
|
122
|
+
// 2. if something has been included in `a` ignore requests to exclude given `b`
|
|
123
|
+
Object.entries(b).forEach(([ns, include]) => {
|
|
124
|
+
if (res[ns] === undefined) {
|
|
125
|
+
res[ns] = include;
|
|
126
|
+
}
|
|
127
|
+
});
|
|
128
|
+
|
|
129
|
+
return res;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
/**
|
|
133
|
+
* Convert @NamespaceProjectFilterResult into @PaginationParamFilter
|
|
134
|
+
*/
|
|
135
|
+
protected createFiltersFromNamespaceProjectFilterResult(filterResult: NamespaceProjectFilterResult): PaginationParamFilter[] {
|
|
136
|
+
const inList: string[] = [];
|
|
137
|
+
const outList: string[] = [];
|
|
138
|
+
|
|
139
|
+
Object.entries(filterResult).forEach(([ns, include]) => {
|
|
140
|
+
if (include) {
|
|
141
|
+
inList.push(ns);
|
|
142
|
+
} else {
|
|
143
|
+
outList.push(ns);
|
|
144
|
+
}
|
|
145
|
+
});
|
|
146
|
+
|
|
147
|
+
const res: PaginationParamFilter[] = [];
|
|
148
|
+
|
|
149
|
+
// There's no point having both IN and OUT lists together, so prefer the IN list
|
|
150
|
+
if (inList.length) {
|
|
151
|
+
res.push(new PaginationParamFilter({
|
|
152
|
+
fields: [{
|
|
153
|
+
value: inList.join(','),
|
|
154
|
+
equality: PaginationFilterEquality.IN,
|
|
155
|
+
field: 'metadata.namespace',
|
|
156
|
+
}],
|
|
157
|
+
}));
|
|
158
|
+
} else if (outList.length) {
|
|
159
|
+
res.push(new PaginationParamFilter({
|
|
160
|
+
fields: [{
|
|
161
|
+
value: outList.join(','),
|
|
162
|
+
equality: PaginationFilterEquality.NOT_IN,
|
|
163
|
+
field: 'metadata.namespace',
|
|
164
|
+
}],
|
|
110
165
|
}));
|
|
111
166
|
}
|
|
167
|
+
|
|
168
|
+
return res;
|
|
112
169
|
}
|
|
113
170
|
|
|
114
171
|
/**
|
|
115
172
|
* User needs resources in a set of projects or namespaces
|
|
173
|
+
*
|
|
174
|
+
* Mainly deals with the projectornamespaces filter, also ensures namespace in local cluster matching target project's aren't included
|
|
175
|
+
*
|
|
116
176
|
*/
|
|
117
177
|
protected handleSelectionFilter(neu: string[], isLocalCluster: boolean) {
|
|
118
178
|
// User has one or more projects or namespaces. We can pass this straight through to projectsornamespaces
|
|
@@ -124,12 +184,12 @@ class NamespaceProjectFilters {
|
|
|
124
184
|
];
|
|
125
185
|
|
|
126
186
|
if (isLocalCluster) {
|
|
127
|
-
//
|
|
128
|
-
//
|
|
187
|
+
// We need to be careful of the local cluster where there's namespaces related to projects with the same id
|
|
188
|
+
// In this case
|
|
129
189
|
// - We're including resources in the project and it's related namespace (via projectsornamespaces)
|
|
130
190
|
// - We're also then excluding resources in the related namespace (via below `filter`)
|
|
131
191
|
|
|
132
|
-
// Exclude resources NOT in
|
|
192
|
+
// Exclude resources NOT in project's backing namespace 1 AND not in project's backing namespace 2
|
|
133
193
|
// &filter=metadata.namespace!=pn1&filter=metadata.namespace!=pn2
|
|
134
194
|
return {
|
|
135
195
|
projectsOrNamespaces,
|
|
@@ -352,24 +412,29 @@ class StevePaginationUtils extends NamespaceProjectFilters {
|
|
|
352
412
|
let projectsOrNamespaces: PaginationParamProjectOrNamespace[] = [];
|
|
353
413
|
// used to return resources in / not in namespaces
|
|
354
414
|
// &filter=metadata.namespace=abc
|
|
355
|
-
|
|
415
|
+
const filters: PaginationParamFilter[] = [];
|
|
416
|
+
let nsProjectFilterResults = {};
|
|
356
417
|
|
|
357
418
|
if (!showReservedRancherNamespaces || productHidesSystemNamespaces) {
|
|
358
|
-
// We need to hide reserved namespaces ('c-', 'user-', etc) OR system namespaces
|
|
359
|
-
|
|
419
|
+
// We need to hide reserved namespaces ('c-', 'user-', etc) OR system namespaces (given product may hide them)
|
|
420
|
+
nsProjectFilterResults = this.combineNsProjectFilterResults(nsProjectFilterResults, this.handlePrefAndSettingFilter({
|
|
360
421
|
allNamespaces, showReservedRancherNamespaces, productHidesSystemNamespaces
|
|
361
|
-
});
|
|
422
|
+
}));
|
|
362
423
|
}
|
|
363
424
|
|
|
364
425
|
const isAllSystem = selection[0] === NAMESPACE_FILTER_ALL_SYSTEM;
|
|
365
426
|
const isAllUser = selection[0] === NAMESPACE_FILTER_ALL_USER;
|
|
366
427
|
|
|
367
428
|
if (selection.length === 1 && (isAllSystem || isAllUser)) {
|
|
368
|
-
// Filter by resources either in or not in system namespaces
|
|
369
|
-
|
|
429
|
+
// Filter by resources either in or not in system namespaces (given user selection)
|
|
430
|
+
nsProjectFilterResults = this.combineNsProjectFilterResults(nsProjectFilterResults, this.handleSystemOrUserFilter({
|
|
370
431
|
allNamespaces, isAllSystem, isAllUser
|
|
371
432
|
}));
|
|
433
|
+
|
|
434
|
+
filters.push(...this.createFiltersFromNamespaceProjectFilterResult(nsProjectFilterResults));
|
|
372
435
|
} else {
|
|
436
|
+
filters.push(...this.createFiltersFromNamespaceProjectFilterResult(nsProjectFilterResults));
|
|
437
|
+
|
|
373
438
|
// User has one or more projects or namespaces
|
|
374
439
|
const res = this.handleSelectionFilter(selection, isLocalCluster);
|
|
375
440
|
|
|
@@ -1,9 +1,7 @@
|
|
|
1
|
-
import { ref, provide, nextTick,
|
|
1
|
+
import { ref, provide, nextTick, EmitFn } from 'vue';
|
|
2
2
|
import { useDropdownCollection } from './useDropdownCollection';
|
|
3
3
|
import { RcButtonType } from '@components/RcButton';
|
|
4
4
|
|
|
5
|
-
const rcDropdownEmits = defineEmits(['update:open']);
|
|
6
|
-
|
|
7
5
|
/**
|
|
8
6
|
* Composable that provides the context for a dropdown menu. Includes methods
|
|
9
7
|
* and state for managing the dropdown's visibility, focus, and keyboard
|
|
@@ -13,7 +11,7 @@ const rcDropdownEmits = defineEmits(['update:open']);
|
|
|
13
11
|
* @returns Dropdown context methods and state. Used for programmatic
|
|
14
12
|
* interactions and setting focus.
|
|
15
13
|
*/
|
|
16
|
-
export const useDropdownContext = (emit:
|
|
14
|
+
export const useDropdownContext = (emit: EmitFn<['update:open']>) => {
|
|
17
15
|
const {
|
|
18
16
|
dropdownItems,
|
|
19
17
|
firstDropdownItem,
|
|
@@ -72,7 +72,7 @@ interface RcItemCardProps {
|
|
|
72
72
|
id: string;
|
|
73
73
|
|
|
74
74
|
/** Any object value associated with this card */
|
|
75
|
-
value
|
|
75
|
+
value?: ItemValue;
|
|
76
76
|
|
|
77
77
|
/** Card title, status icons and action menu. Image will be included in the header in small variant too */
|
|
78
78
|
header: Header;
|
package/scripts/publish-shell.sh
CHANGED
|
@@ -8,6 +8,7 @@ SHELL_DIR=$BASE_DIR/shell/
|
|
|
8
8
|
CREATORS_DIR=$BASE_DIR/creators/extension
|
|
9
9
|
FORCE_PUBLISH_TO_NPM="false"
|
|
10
10
|
DEFAULT_NPM_REGISTRY="https://registry.npmjs.org"
|
|
11
|
+
DUMMY_VERSION="99.99.99"
|
|
11
12
|
|
|
12
13
|
# if TAG doesn't exist, we can exit as it's needed for any type of publish.
|
|
13
14
|
if [ -z "$TAG" ]; then
|
|
@@ -84,6 +85,14 @@ function publish() {
|
|
|
84
85
|
fi
|
|
85
86
|
}
|
|
86
87
|
|
|
88
|
+
update_version_in_package_json() {
|
|
89
|
+
local package_json_path="$1"
|
|
90
|
+
local version="$2"
|
|
91
|
+
|
|
92
|
+
sed -i.bak -e "s/\"version\": \"[0-9]*.[0-9]*.[0-9]*\(-alpha\.[0-9]*\|-release[0-9]*.[0-9]*.[0-9]*\|-rc\.[0-9]*\)\{0,1\}\",/\"version\": \"${version}\",/g" "$package_json_path"
|
|
93
|
+
rm "${package_json_path}.bak"
|
|
94
|
+
}
|
|
95
|
+
|
|
87
96
|
echo "TAG ${TAG}"
|
|
88
97
|
|
|
89
98
|
# let's get the package name and version from the tag
|
|
@@ -102,10 +111,26 @@ fi
|
|
|
102
111
|
case $PKG_NAME in
|
|
103
112
|
"shell")
|
|
104
113
|
echo "Publishing only Shell pkg via tagged release"
|
|
114
|
+
|
|
115
|
+
# with the changes in https://github.com/rancher/dashboard/pull/16166/files#diff-d954ab41ef46f7fdbaaf6d8c2bc715ad2cc823a829317b6ff93a3c94a92811f1
|
|
116
|
+
# with NPM 11.3 --dry--run now does additional checks, one of them is the version number
|
|
117
|
+
# so for dry runs we need to provide a valid version number here (not something published before)
|
|
118
|
+
if [ ${DRY_RUN} == "true" ]; then
|
|
119
|
+
update_version_in_package_json "${SHELL_DIR}/package.json" "${DUMMY_VERSION}"
|
|
120
|
+
fi
|
|
121
|
+
|
|
105
122
|
publish "Shell" ${SHELL_DIR} ${PKG_V}
|
|
106
123
|
;;
|
|
107
124
|
"creators")
|
|
108
125
|
echo "Publishing only Creators pkg via tagged release"
|
|
126
|
+
|
|
127
|
+
# with the changes in https://github.com/rancher/dashboard/pull/16166/files#diff-d954ab41ef46f7fdbaaf6d8c2bc715ad2cc823a829317b6ff93a3c94a92811f1
|
|
128
|
+
# with NPM 11.3 --dry--run now does additional checks, one of them is the version number
|
|
129
|
+
# so for dry runs we need to provide a valid version number here (not something published before)
|
|
130
|
+
if [ ${DRY_RUN} == "true" ]; then
|
|
131
|
+
update_version_in_package_json "${CREATORS_DIR}/package.json" "${DUMMY_VERSION}"
|
|
132
|
+
fi
|
|
133
|
+
|
|
109
134
|
publish "Extension creator" ${CREATORS_DIR} ${PKG_V}
|
|
110
135
|
;;
|
|
111
136
|
*)
|
|
@@ -1116,7 +1116,169 @@ describe('type-map', () => {
|
|
|
1116
1116
|
});
|
|
1117
1117
|
});
|
|
1118
1118
|
});
|
|
1119
|
+
|
|
1120
|
+
describe('activeProducts', () => {
|
|
1121
|
+
// Basic schemas for product filtering tests
|
|
1122
|
+
const productSchemas = {
|
|
1123
|
+
myType: {
|
|
1124
|
+
id: 'mytype',
|
|
1125
|
+
_id: 'mytype',
|
|
1126
|
+
type: SCHEMA,
|
|
1127
|
+
_group: 'mygroup',
|
|
1128
|
+
},
|
|
1129
|
+
anotherType: {
|
|
1130
|
+
id: 'anothertype',
|
|
1131
|
+
_id: 'anothertype',
|
|
1132
|
+
type: SCHEMA,
|
|
1133
|
+
_group: 'anothergroup',
|
|
1134
|
+
},
|
|
1135
|
+
};
|
|
1136
|
+
|
|
1137
|
+
const createProductState = (products) => ({
|
|
1138
|
+
products,
|
|
1139
|
+
schemaGeneration: 1,
|
|
1140
|
+
});
|
|
1141
|
+
|
|
1142
|
+
const createProductRootGetters = (moduleSchemas = [], moduleName = 'cluster') => ({
|
|
1143
|
+
'prefs/get': () => false,
|
|
1144
|
+
[`${ moduleName }/all`]: (resource) => {
|
|
1145
|
+
if (resource === SCHEMA) {
|
|
1146
|
+
return moduleSchemas;
|
|
1147
|
+
}
|
|
1148
|
+
|
|
1149
|
+
return [];
|
|
1150
|
+
},
|
|
1151
|
+
});
|
|
1152
|
+
|
|
1153
|
+
describe('ifHaveType', () => {
|
|
1154
|
+
it('should show product when matching type exists', () => {
|
|
1155
|
+
const state = createProductState([{
|
|
1156
|
+
name: 'test-product',
|
|
1157
|
+
inStore: 'cluster',
|
|
1158
|
+
ifHaveType: 'mytype',
|
|
1159
|
+
}]);
|
|
1160
|
+
const rootGetters = createProductRootGetters([productSchemas.myType]);
|
|
1161
|
+
|
|
1162
|
+
const active = getters.activeProducts(state, {}, {}, rootGetters);
|
|
1163
|
+
|
|
1164
|
+
expect(active).toHaveLength(1);
|
|
1165
|
+
expect(active[0].name).toBe('test-product');
|
|
1166
|
+
});
|
|
1167
|
+
|
|
1168
|
+
it('should hide product when matching type does not exist', () => {
|
|
1169
|
+
const state = createProductState([{
|
|
1170
|
+
name: 'test-product',
|
|
1171
|
+
inStore: 'cluster',
|
|
1172
|
+
ifHaveType: 'missingtype',
|
|
1173
|
+
}]);
|
|
1174
|
+
const rootGetters = createProductRootGetters([productSchemas.myType]);
|
|
1175
|
+
|
|
1176
|
+
const active = getters.activeProducts(state, {}, {}, rootGetters);
|
|
1177
|
+
|
|
1178
|
+
expect(active).toHaveLength(0);
|
|
1179
|
+
});
|
|
1180
|
+
});
|
|
1181
|
+
|
|
1182
|
+
describe('ifNotHaveType', () => {
|
|
1183
|
+
it('should show product when matching type does NOT exist', () => {
|
|
1184
|
+
const state = createProductState([{
|
|
1185
|
+
name: 'test-product',
|
|
1186
|
+
inStore: 'cluster',
|
|
1187
|
+
ifNotHaveType: 'missingtype',
|
|
1188
|
+
}]);
|
|
1189
|
+
const rootGetters = createProductRootGetters([productSchemas.myType]);
|
|
1190
|
+
|
|
1191
|
+
const active = getters.activeProducts(state, {}, {}, rootGetters);
|
|
1192
|
+
|
|
1193
|
+
expect(active).toHaveLength(1);
|
|
1194
|
+
expect(active[0].name).toBe('test-product');
|
|
1195
|
+
});
|
|
1196
|
+
|
|
1197
|
+
it('should hide product when matching type exists', () => {
|
|
1198
|
+
const state = createProductState([{
|
|
1199
|
+
name: 'test-product',
|
|
1200
|
+
inStore: 'cluster',
|
|
1201
|
+
ifNotHaveType: 'mytype',
|
|
1202
|
+
}]);
|
|
1203
|
+
const rootGetters = createProductRootGetters([productSchemas.myType]);
|
|
1204
|
+
|
|
1205
|
+
const active = getters.activeProducts(state, {}, {}, rootGetters);
|
|
1206
|
+
|
|
1207
|
+
expect(active).toHaveLength(0);
|
|
1208
|
+
});
|
|
1209
|
+
|
|
1210
|
+
it('should support regex pattern in ifNotHaveType', () => {
|
|
1211
|
+
const state = createProductState([{
|
|
1212
|
+
name: 'test-product',
|
|
1213
|
+
inStore: 'cluster',
|
|
1214
|
+
ifNotHaveType: 'my.*',
|
|
1215
|
+
}]);
|
|
1216
|
+
const rootGetters = createProductRootGetters([productSchemas.myType]);
|
|
1217
|
+
|
|
1218
|
+
const active = getters.activeProducts(state, {}, {}, rootGetters);
|
|
1219
|
+
|
|
1220
|
+
expect(active).toHaveLength(0);
|
|
1221
|
+
});
|
|
1222
|
+
|
|
1223
|
+
it('should show product when regex pattern does not match any type', () => {
|
|
1224
|
+
const state = createProductState([{
|
|
1225
|
+
name: 'test-product',
|
|
1226
|
+
inStore: 'cluster',
|
|
1227
|
+
ifNotHaveType: 'nomatch.*',
|
|
1228
|
+
}]);
|
|
1229
|
+
const rootGetters = createProductRootGetters([productSchemas.myType]);
|
|
1230
|
+
|
|
1231
|
+
const active = getters.activeProducts(state, {}, {}, rootGetters);
|
|
1232
|
+
|
|
1233
|
+
expect(active).toHaveLength(1);
|
|
1234
|
+
expect(active[0].name).toBe('test-product');
|
|
1235
|
+
});
|
|
1236
|
+
});
|
|
1237
|
+
|
|
1238
|
+
describe('combined ifHaveType and ifNotHaveType', () => {
|
|
1239
|
+
it('should show product when ifHaveType matches and ifNotHaveType does not match', () => {
|
|
1240
|
+
const state = createProductState([{
|
|
1241
|
+
name: 'test-product',
|
|
1242
|
+
inStore: 'cluster',
|
|
1243
|
+
ifHaveType: 'mytype',
|
|
1244
|
+
ifNotHaveType: 'missingtype',
|
|
1245
|
+
}]);
|
|
1246
|
+
const rootGetters = createProductRootGetters([productSchemas.myType]);
|
|
1247
|
+
|
|
1248
|
+
const active = getters.activeProducts(state, {}, {}, rootGetters);
|
|
1249
|
+
|
|
1250
|
+
expect(active).toHaveLength(1);
|
|
1251
|
+
expect(active[0].name).toBe('test-product');
|
|
1252
|
+
});
|
|
1253
|
+
|
|
1254
|
+
it('should hide product when ifHaveType matches but ifNotHaveType also matches', () => {
|
|
1255
|
+
const state = createProductState([{
|
|
1256
|
+
name: 'test-product',
|
|
1257
|
+
inStore: 'cluster',
|
|
1258
|
+
ifHaveType: 'mytype',
|
|
1259
|
+
ifNotHaveType: 'anothertype',
|
|
1260
|
+
}]);
|
|
1261
|
+
const rootGetters = createProductRootGetters([productSchemas.myType, productSchemas.anotherType]);
|
|
1262
|
+
|
|
1263
|
+
const active = getters.activeProducts(state, {}, {}, rootGetters);
|
|
1264
|
+
|
|
1265
|
+
expect(active).toHaveLength(0);
|
|
1266
|
+
});
|
|
1267
|
+
|
|
1268
|
+
it('should hide product when ifHaveType does not match', () => {
|
|
1269
|
+
const state = createProductState([{
|
|
1270
|
+
name: 'test-product',
|
|
1271
|
+
inStore: 'cluster',
|
|
1272
|
+
ifHaveType: 'missingtype',
|
|
1273
|
+
ifNotHaveType: 'anothermissingtype',
|
|
1274
|
+
}]);
|
|
1275
|
+
const rootGetters = createProductRootGetters([productSchemas.myType]);
|
|
1276
|
+
|
|
1277
|
+
const active = getters.activeProducts(state, {}, {}, rootGetters);
|
|
1278
|
+
|
|
1279
|
+
expect(active).toHaveLength(0);
|
|
1280
|
+
});
|
|
1281
|
+
});
|
|
1282
|
+
});
|
|
1119
1283
|
});
|
|
1120
1284
|
});
|
|
1121
|
-
|
|
1122
|
-
// getTree - Remove ignored schemas, not-applicable to ns filter
|
package/store/auth.js
CHANGED
|
@@ -149,12 +149,16 @@ export const actions = {
|
|
|
149
149
|
force = true;
|
|
150
150
|
}
|
|
151
151
|
|
|
152
|
-
|
|
152
|
+
const providers = dispatch('rancher/findAll', {
|
|
153
153
|
type: 'authProvider',
|
|
154
154
|
opt: {
|
|
155
|
-
url:
|
|
155
|
+
url: `/v1-public/authproviders`,
|
|
156
|
+
watch: false,
|
|
157
|
+
force
|
|
156
158
|
}
|
|
157
159
|
}, { root: true });
|
|
160
|
+
|
|
161
|
+
return providers;
|
|
158
162
|
},
|
|
159
163
|
|
|
160
164
|
getAuthConfigs({ dispatch }) {
|
|
@@ -349,13 +353,21 @@ export const actions = {
|
|
|
349
353
|
const driver = await dispatch('getAuthProvider', provider);
|
|
350
354
|
|
|
351
355
|
try {
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
356
|
+
return await dispatch(
|
|
357
|
+
'management/request',
|
|
358
|
+
{
|
|
359
|
+
url: `/v1-public/login`,
|
|
360
|
+
method: 'post',
|
|
361
|
+
data: {
|
|
362
|
+
type: driver.type,
|
|
363
|
+
description: 'UI session',
|
|
364
|
+
responseType: 'cookie',
|
|
365
|
+
...body
|
|
366
|
+
},
|
|
367
|
+
redirectUnauthorized: false,
|
|
368
|
+
},
|
|
369
|
+
{ root: true }
|
|
370
|
+
);
|
|
359
371
|
} catch (err) {
|
|
360
372
|
if (err._status === 401) {
|
|
361
373
|
return Promise.reject(LOGIN_ERRORS.CLIENT_UNAUTHORIZED);
|
|
@@ -402,14 +414,14 @@ export const actions = {
|
|
|
402
414
|
}
|
|
403
415
|
|
|
404
416
|
// Unload plugins - we will load again on login
|
|
405
|
-
await rootState.$
|
|
417
|
+
await rootState.$extension.logout();
|
|
406
418
|
|
|
407
419
|
let logoutAction = '';
|
|
408
420
|
const data = {};
|
|
409
421
|
|
|
410
422
|
// SLO - Single-sign logout - will logout auth provider from all places where it's logged in
|
|
411
423
|
if (options.slo) {
|
|
412
|
-
logoutAction = '?
|
|
424
|
+
logoutAction = '?all';
|
|
413
425
|
data.finalRedirectUrl = returnTo({ isSlo: true }, this);
|
|
414
426
|
}
|
|
415
427
|
|
package/store/i18n.js
CHANGED
|
@@ -285,8 +285,8 @@ export const actions = {
|
|
|
285
285
|
return;
|
|
286
286
|
}
|
|
287
287
|
|
|
288
|
-
const lastLoad = rootState.$
|
|
289
|
-
const i18nExt = rootState.$
|
|
288
|
+
const lastLoad = rootState.$extension?.lastLoad;
|
|
289
|
+
const i18nExt = rootState.$extension?.getDynamic('l10n', locale);
|
|
290
290
|
const reload = lastLoaded < lastLoad;
|
|
291
291
|
|
|
292
292
|
lastLoaded = lastLoad;
|
|
@@ -314,7 +314,7 @@ export const actions = {
|
|
|
314
314
|
|
|
315
315
|
// load all of the default locales from the plugins for fallback
|
|
316
316
|
if (locale !== DEFAULT_LOCALE) {
|
|
317
|
-
const defaultI18nExt = rootState.$
|
|
317
|
+
const defaultI18nExt = rootState.$extension?.getDynamic('l10n', DEFAULT_LOCALE);
|
|
318
318
|
|
|
319
319
|
if (defaultI18nExt && defaultI18nExt.length) {
|
|
320
320
|
defaultI18nExt.forEach((fn) => {
|
package/store/index.js
CHANGED
|
@@ -233,7 +233,7 @@ const updateActiveNamespaceCache = (state, activeNamespaceCache) => {
|
|
|
233
233
|
* Are we in the vai enabled world where mgmt clusters are paginated?
|
|
234
234
|
*/
|
|
235
235
|
const paginateClusters = ({ rootGetters, state }) => {
|
|
236
|
-
return paginationUtils.isEnabled({ rootGetters, $
|
|
236
|
+
return paginationUtils.isEnabled({ rootGetters, $extension: state.$extension }, { store: 'management', resource: { id: MANAGEMENT.CLUSTER, context: 'side-bar' } });
|
|
237
237
|
};
|
|
238
238
|
|
|
239
239
|
export const state = () => {
|
|
@@ -262,6 +262,7 @@ export const state = () => {
|
|
|
262
262
|
$router: markRaw({}),
|
|
263
263
|
$route: markRaw({}),
|
|
264
264
|
$plugin: markRaw({}),
|
|
265
|
+
$extension: markRaw({}),
|
|
265
266
|
showWorkspaceSwitcher: true,
|
|
266
267
|
localCluster: null,
|
|
267
268
|
};
|
|
@@ -775,6 +776,7 @@ export const mutations = {
|
|
|
775
776
|
},
|
|
776
777
|
|
|
777
778
|
setPlugin(state, pluginDefinition) {
|
|
779
|
+
state.$extension = markRaw(pluginDefinition || {});
|
|
778
780
|
state.$plugin = markRaw(pluginDefinition || {});
|
|
779
781
|
},
|
|
780
782
|
|
|
@@ -1195,7 +1197,7 @@ export const actions = {
|
|
|
1195
1197
|
|
|
1196
1198
|
store.dispatch('gcStopIntervals');
|
|
1197
1199
|
|
|
1198
|
-
Object.values(this.$
|
|
1200
|
+
Object.values(this.$extension.getPlugins()).forEach((p) => {
|
|
1199
1201
|
if (p.onLogOut) {
|
|
1200
1202
|
p.onLogOut(store);
|
|
1201
1203
|
}
|
|
@@ -1254,7 +1256,7 @@ export const actions = {
|
|
|
1254
1256
|
dashboardClientInit({ dispatch, commit, rootState }, context) {
|
|
1255
1257
|
commit('setRouter', context.app.router);
|
|
1256
1258
|
commit('setRoute', context.route);
|
|
1257
|
-
commit('setPlugin', context.app.$
|
|
1259
|
+
commit('setPlugin', context.app.$extension);
|
|
1258
1260
|
|
|
1259
1261
|
dispatch('management/rehydrateSubscribe');
|
|
1260
1262
|
dispatch('cluster/rehydrateSubscribe');
|
package/store/notifications.ts
CHANGED
|
@@ -299,6 +299,8 @@ export const actions = {
|
|
|
299
299
|
|
|
300
300
|
// Show a growl for the notification if necessary
|
|
301
301
|
dispatch('growl/notification', notification, { root: true });
|
|
302
|
+
|
|
303
|
+
return notification.id;
|
|
302
304
|
},
|
|
303
305
|
|
|
304
306
|
async fromGrowl( { commit, getters }: any, notification: Notification) {
|
package/store/prefs.js
CHANGED
|
@@ -233,13 +233,13 @@ export const getters = {
|
|
|
233
233
|
}
|
|
234
234
|
const clusterPref = getters['get'](CLUSTER);
|
|
235
235
|
|
|
236
|
-
return { name: 'c-cluster-explorer', params: {
|
|
236
|
+
return { name: 'c-cluster-explorer', params: { cluster: clusterPref } };
|
|
237
237
|
}
|
|
238
238
|
case (!!afterLoginRoutePref.match(/.+-dashboard$/)):
|
|
239
239
|
{
|
|
240
240
|
const clusterId = afterLoginRoutePref.split('-dashboard')[0];
|
|
241
241
|
|
|
242
|
-
return { name: 'c-cluster-explorer', params: {
|
|
242
|
+
return { name: 'c-cluster-explorer', params: { cluster: clusterId } };
|
|
243
243
|
}
|
|
244
244
|
default:
|
|
245
245
|
return { name: afterLoginRoutePref };
|