@rancher/shell 3.0.8-rc.8 → 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/brand/suse/dark/rancher-logo.svg +1 -64
- package/assets/styles/global/_tooltip.scss +6 -1
- package/assets/translations/en-us.yaml +14 -1
- package/components/ActionMenuShell.vue +3 -1
- package/components/BackLink.vue +8 -0
- package/components/BannerGraphic.vue +1 -5
- package/components/BrandImage.vue +17 -6
- package/components/Cron/CronExpressionEditor.vue +1 -1
- package/components/Cron/CronExpressionEditorModal.vue +1 -1
- package/components/CruResource.vue +8 -1
- package/components/Drawer/ResourceDetailDrawer/ConfigTab.vue +1 -0
- package/components/Drawer/ResourceDetailDrawer/__tests__/composables.test.ts +50 -1
- package/components/Drawer/ResourceDetailDrawer/composables.ts +19 -0
- package/components/Drawer/ResourceDetailDrawer/index.vue +4 -1
- package/components/Drawer/ResourceDetailDrawer/types.ts +2 -1
- package/components/LocaleSelector.vue +2 -2
- package/components/ModalManager.vue +11 -1
- package/components/Questions/__tests__/Yaml.test.ts +1 -1
- package/components/Questions/__tests__/index.test.ts +159 -0
- package/components/RelatedResources.vue +5 -0
- package/components/Resource/Detail/Metadata/Annotations/index.vue +2 -2
- package/components/Resource/Detail/Metadata/Labels/index.vue +2 -2
- package/components/Resource/Detail/Metadata/index.vue +3 -3
- package/components/Resource/Detail/ResourcePopover/index.vue +5 -1
- package/components/Resource/Detail/composables.ts +2 -2
- 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/__tests__/index.test.ts +86 -0
- package/components/Tabbed/index.vue +37 -2
- package/components/__tests__/NamespaceFilter.test.ts +49 -0
- package/components/auth/SelectPrincipal.vue +28 -6
- package/components/auth/__tests__/SelectPrincipal.test.ts +119 -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/InternalExternalIP.vue +4 -1
- package/components/formatter/LinkName.vue +5 -0
- package/components/formatter/__tests__/InternalExternalIP.test.ts +1 -1
- 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/components/templates/standalone.vue +1 -1
- package/composables/cruResource.ts +27 -0
- package/composables/focusTrap.ts +3 -1
- package/composables/resourceDetail.ts +15 -0
- package/composables/useI18n.ts +10 -1
- package/composables/useLabeledFormElement.ts +3 -4
- package/config/__test__/uiplugins.test.ts +309 -0
- package/config/labels-annotations.js +1 -0
- package/config/product/explorer.js +3 -1
- 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 +7 -7
- package/config/types.js +7 -0
- package/config/uiplugins.js +46 -2
- package/core/__tests__/extension-manager-impl.test.js +437 -0
- package/core/extension-manager-impl.js +21 -25
- 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 +5 -1
- package/core/types.ts +35 -0
- package/detail/provisioning.cattle.io.cluster.vue +9 -6
- package/dialog/DeveloperLoadExtensionDialog.vue +13 -4
- package/dialog/MoveNamespaceDialog.vue +20 -4
- package/dialog/RollbackWorkloadDialog.vue +2 -5
- 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 +100 -3
- package/edit/autoscaling.horizontalpodautoscaler/index.vue +1 -0
- package/edit/configmap.vue +1 -0
- package/edit/constraints.gatekeeper.sh.constraint/index.vue +1 -0
- package/edit/fleet.cattle.io.helmop.vue +11 -6
- package/edit/helm.cattle.io.projecthelmchart.vue +1 -0
- package/edit/k8s.cni.cncf.io.networkattachmentdefinition.vue +1 -0
- package/edit/logging-flow/index.vue +1 -0
- package/edit/logging.banzaicloud.io.output/index.vue +1 -0
- package/edit/management.cattle.io.fleetworkspace.vue +1 -1
- package/edit/management.cattle.io.project.vue +1 -0
- package/edit/monitoring.coreos.com.alertmanagerconfig/index.vue +4 -1
- package/edit/monitoring.coreos.com.alertmanagerconfig/receiverConfig.vue +2 -1
- package/edit/monitoring.coreos.com.prometheusrule/index.vue +1 -0
- package/edit/monitoring.coreos.com.receiver/index.vue +2 -1
- package/edit/monitoring.coreos.com.route.vue +1 -1
- package/edit/namespace.vue +1 -0
- package/edit/networking.istio.io.destinationrule/index.vue +1 -0
- package/edit/networking.k8s.io.ingress/index.vue +1 -0
- package/edit/networking.k8s.io.networkpolicy/PolicyRules.vue +1 -0
- package/edit/networking.k8s.io.networkpolicy/index.vue +1 -0
- package/edit/node.vue +1 -0
- package/edit/persistentvolume/index.vue +27 -22
- package/edit/persistentvolume/plugins/awsElasticBlockStore.vue +13 -14
- package/edit/persistentvolume/plugins/azureDisk.vue +49 -48
- package/edit/persistentvolume/plugins/azureFile.vue +15 -14
- package/edit/persistentvolume/plugins/cephfs.vue +15 -14
- package/edit/persistentvolume/plugins/cinder.vue +15 -14
- package/edit/persistentvolume/plugins/csi.vue +18 -16
- package/edit/persistentvolume/plugins/fc.vue +13 -14
- package/edit/persistentvolume/plugins/flexVolume.vue +15 -14
- package/edit/persistentvolume/plugins/flocker.vue +1 -3
- package/edit/persistentvolume/plugins/gcePersistentDisk.vue +13 -14
- package/edit/persistentvolume/plugins/glusterfs.vue +15 -14
- package/edit/persistentvolume/plugins/hostPath.vue +40 -39
- package/edit/persistentvolume/plugins/iscsi.vue +13 -14
- package/edit/persistentvolume/plugins/local.vue +1 -3
- package/edit/persistentvolume/plugins/longhorn.vue +23 -22
- package/edit/persistentvolume/plugins/nfs.vue +15 -14
- package/edit/persistentvolume/plugins/photonPersistentDisk.vue +1 -14
- package/edit/persistentvolume/plugins/portworxVolume.vue +15 -14
- package/edit/persistentvolume/plugins/quobyte.vue +15 -14
- package/edit/persistentvolume/plugins/rbd.vue +15 -14
- package/edit/persistentvolume/plugins/scaleIO.vue +15 -14
- package/edit/persistentvolume/plugins/storageos.vue +15 -14
- package/edit/persistentvolume/plugins/vsphereVolume.vue +1 -3
- 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 +9 -8
- package/edit/resources.cattle.io.restore.vue +1 -1
- package/edit/secret/index.vue +1 -1
- package/edit/service.vue +1 -0
- package/edit/serviceaccount.vue +1 -0
- package/edit/storage.k8s.io.storageclass/index.vue +1 -0
- package/edit/workload/Job.vue +2 -2
- package/edit/workload/index.vue +2 -1
- package/edit/workload/mixins/workload.js +1 -1
- package/initialize/App.vue +4 -4
- package/initialize/install-plugins.js +19 -5
- package/machine-config/azure.vue +1 -1
- package/machine-config/components/GCEImage.vue +1 -1
- package/mixins/__tests__/brand.spec.ts +2 -2
- package/mixins/brand.js +1 -7
- package/mixins/create-edit-view/index.js +5 -0
- package/models/__tests__/provisioning.cattle.io.cluster.test.ts +128 -5
- package/models/chart.js +70 -74
- package/models/management.cattle.io.cluster.js +21 -3
- package/models/provisioning.cattle.io.cluster.js +31 -11
- package/package.json +11 -10
- package/pages/auth/login.vue +4 -6
- package/pages/auth/setup.vue +1 -1
- package/pages/auth/verify.vue +3 -3
- package/pages/c/_cluster/apps/charts/__tests__/chart.test.ts +135 -0
- package/pages/c/_cluster/apps/charts/chart.vue +33 -15
- 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/explorer/index.vue +8 -6
- package/pages/c/_cluster/fleet/index.vue +4 -7
- package/pages/c/_cluster/manager/hostedprovider/index.vue +12 -6
- package/pages/c/_cluster/settings/brand.vue +1 -1
- package/pages/c/_cluster/settings/index.vue +5 -0
- package/pages/c/_cluster/uiplugins/__tests__/index.test.ts +7 -0
- package/pages/c/_cluster/uiplugins/catalogs.vue +147 -0
- package/pages/c/_cluster/uiplugins/index.vue +126 -184
- 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-client-init.js +3 -0
- package/plugins/dashboard-store/getters.js +19 -2
- package/plugins/dashboard-store/model-loader.js +1 -1
- package/plugins/dashboard-store/mutations.js +23 -2
- package/plugins/dashboard-store/resource-class.js +11 -5
- package/plugins/i18n.js +8 -0
- package/plugins/plugin.js +2 -2
- package/plugins/steve/__tests__/steve-pagination-utils.test.ts +506 -0
- package/plugins/steve/steve-class.js +1 -1
- package/plugins/steve/steve-pagination-utils.ts +131 -47
- package/rancher-components/Form/Checkbox/Checkbox.vue +1 -1
- package/rancher-components/Form/LabeledInput/LabeledInput.vue +1 -1
- package/rancher-components/Pill/RcStatusBadge/RcStatusBadge.vue +6 -42
- package/rancher-components/Pill/RcStatusBadge/index.ts +0 -1
- package/rancher-components/Pill/RcStatusBadge/types.ts +1 -1
- package/rancher-components/Pill/RcStatusIndicator/RcStatusIndicator.vue +5 -28
- package/rancher-components/Pill/RcStatusIndicator/types.ts +2 -1
- package/rancher-components/Pill/types.ts +0 -1
- package/rancher-components/RcDropdown/useDropdownContext.ts +2 -4
- package/rancher-components/RcIcon/RcIcon.test.ts +51 -0
- package/rancher-components/RcIcon/RcIcon.vue +46 -0
- package/rancher-components/RcIcon/index.ts +1 -0
- package/rancher-components/RcIcon/types.ts +160 -0
- package/rancher-components/RcItemCard/RcItemCard.vue +1 -1
- package/rancher-components/utils/status.test.ts +67 -0
- package/rancher-components/utils/status.ts +77 -0
- package/scripts/publish-shell.sh +25 -0
- package/scripts/typegen.sh +1 -0
- package/store/__tests__/catalog.test.ts +1 -1
- package/store/__tests__/type-map.test.ts +164 -2
- package/store/action-menu.js +8 -0
- package/store/auth.js +25 -13
- package/store/catalog.js +6 -0
- package/store/i18n.js +3 -3
- package/store/index.js +8 -6
- package/store/notifications.ts +2 -0
- package/store/prefs.js +6 -7
- package/store/type-map.js +17 -7
- package/store/wm.ts +4 -4
- 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 +54 -3
- package/types/store/__tests__/pagination.types.spec.ts +137 -0
- package/types/store/pagination.types.ts +157 -9
- package/types/vue-shim.d.ts +5 -4
- package/utils/__tests__/provider.test.ts +98 -0
- package/utils/__tests__/router.test.js +238 -0
- package/utils/__tests__/selector-typed.test.ts +263 -0
- package/utils/cluster.js +4 -1
- package/utils/color.js +1 -1
- package/utils/dynamic-content/__tests__/info.test.ts +6 -0
- package/utils/dynamic-content/info.ts +43 -0
- package/utils/favicon.js +4 -4
- package/utils/fleet.ts +8 -1
- package/utils/pagination-utils.ts +2 -2
- package/utils/pagination-wrapper.ts +1 -1
- package/utils/provider.ts +14 -0
- package/utils/router.js +50 -0
- package/utils/selector-typed.ts +6 -2
- package/utils/unit-tests/pagination-utils.spec.ts +8 -8
- package/vue.config.js +3 -3
- package/composables/useExtensionManager.ts +0 -17
- 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/plugins/nuxt-client-init.js +0 -3
- package/types/internal-api/shell/growl.d.ts +0 -25
- package/types/internal-api/shell/slideIn.d.ts +0 -15
|
@@ -165,7 +165,7 @@ class PaginationUtils {
|
|
|
165
165
|
/**
|
|
166
166
|
* Is pagination enabled at a global level or for a specific resource
|
|
167
167
|
*/
|
|
168
|
-
isEnabled({ rootGetters, $
|
|
168
|
+
isEnabled({ rootGetters, $extension }: any, enabledFor: PaginationResourceContext) {
|
|
169
169
|
// Cache must be enabled to support pagination api
|
|
170
170
|
if (!this.isSteveCacheEnabled({ rootGetters })) {
|
|
171
171
|
return false;
|
|
@@ -184,7 +184,7 @@ class PaginationUtils {
|
|
|
184
184
|
}
|
|
185
185
|
|
|
186
186
|
// Does an extension say this type is enabled?
|
|
187
|
-
const plugin = $
|
|
187
|
+
const plugin = $extension as ExtensionManager;
|
|
188
188
|
const paginationExtensionPoints = plugin.getAll()[EXT_IDS.SERVER_SIDE_PAGINATION_RESOURCES];
|
|
189
189
|
|
|
190
190
|
if (paginationExtensionPoints) {
|
|
@@ -69,7 +69,7 @@ class PaginationWrapper<T extends object> {
|
|
|
69
69
|
this.classify = formatResponse?.classify || false;
|
|
70
70
|
this.reactive = formatResponse?.reactive || false;
|
|
71
71
|
|
|
72
|
-
this.isEnabled = paginationUtils.isEnabled({ rootGetters: $store.getters, $
|
|
72
|
+
this.isEnabled = paginationUtils.isEnabled({ rootGetters: $store.getters, $extension: this.$store.$extension }, enabledFor);
|
|
73
73
|
}
|
|
74
74
|
|
|
75
75
|
async request({ pagination, forceWatch }: {
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { IClusterProvisioner, ClusterProvisionerContext } from '@shell/core/types';
|
|
2
|
+
|
|
3
|
+
export function getHostedProviders(context: ClusterProvisionerContext) {
|
|
4
|
+
return context?.$extension?.getProviders(context)?.filter((p: IClusterProvisioner) => p.group === 'hosted') || [];
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
export function isHostedProvider(context: ClusterProvisionerContext, provisioner: string) {
|
|
8
|
+
if (!provisioner) {
|
|
9
|
+
return false;
|
|
10
|
+
}
|
|
11
|
+
const provisioners = new Set(getHostedProviders(context).map((p: IClusterProvisioner) => p.id.toLowerCase()));
|
|
12
|
+
|
|
13
|
+
return provisioners.has(provisioner.toLowerCase());
|
|
14
|
+
}
|
package/utils/router.js
CHANGED
|
@@ -117,3 +117,53 @@ export function findMeta(route, key) {
|
|
|
117
117
|
|
|
118
118
|
return undefined;
|
|
119
119
|
}
|
|
120
|
+
|
|
121
|
+
/**
|
|
122
|
+
* Find a route definition given a routeName
|
|
123
|
+
* @param {*} router VueRouter instance
|
|
124
|
+
* @param {*} routeName the name we want to look up
|
|
125
|
+
* @returns the route definition or undefined if it wasn't found
|
|
126
|
+
*/
|
|
127
|
+
export function findRouteDefinitionByName(router, routeName) {
|
|
128
|
+
const routes = router.getRoutes();
|
|
129
|
+
|
|
130
|
+
return routes.find((r) => r.name === routeName);
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
/**
|
|
134
|
+
* Looks for the route definition and then ensures there's only valid params
|
|
135
|
+
* @param {*} router VueRouter instance
|
|
136
|
+
* @param {*} routeRecord an object conforming to the Route Record interface
|
|
137
|
+
* @returns the passed in routeLocation with only valid params.
|
|
138
|
+
*/
|
|
139
|
+
export function filterLocationValidParams(router, routeRecord) {
|
|
140
|
+
if (!routeRecord || !routeRecord.name || !routeRecord.params) {
|
|
141
|
+
console.warn('filterLocationValidParams received invalid arguments'); // eslint-disable-line no-console
|
|
142
|
+
|
|
143
|
+
return routeRecord;
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
const routeDefinition = findRouteDefinitionByName(router, routeRecord.name);
|
|
147
|
+
|
|
148
|
+
if (!routeDefinition) {
|
|
149
|
+
console.warn('Could not find a route definition given the routeRecord', routeRecord); // eslint-disable-line no-console
|
|
150
|
+
|
|
151
|
+
return routeRecord;
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
const specifiedParams = routeRecord.params;
|
|
155
|
+
const validParams = {};
|
|
156
|
+
|
|
157
|
+
Object.entries(specifiedParams).forEach(([key, value]) => {
|
|
158
|
+
const pathParam = `:${ key }`;
|
|
159
|
+
|
|
160
|
+
if (routeDefinition.path.includes(pathParam)) {
|
|
161
|
+
validParams[key] = value;
|
|
162
|
+
}
|
|
163
|
+
});
|
|
164
|
+
|
|
165
|
+
return {
|
|
166
|
+
...routeRecord,
|
|
167
|
+
params: validParams
|
|
168
|
+
};
|
|
169
|
+
}
|
package/utils/selector-typed.ts
CHANGED
|
@@ -199,8 +199,12 @@ export function labelSelectorToSelector(labelSelector?: KubeLabelSelector): stri
|
|
|
199
199
|
});
|
|
200
200
|
|
|
201
201
|
(labelSelector?.matchExpressions || []).forEach((value: KubeLabelSelectorExpression) => {
|
|
202
|
-
if (value.operator === 'In' && value.values
|
|
203
|
-
|
|
202
|
+
if (value.operator === 'In' && value.values !== undefined) {
|
|
203
|
+
if (value.values?.length === 1) {
|
|
204
|
+
res.push(`${ value.key }=${ value.values[0] }`);
|
|
205
|
+
} else {
|
|
206
|
+
res.push(`${ value.key } in (${ value.values.join(',') })`);
|
|
207
|
+
}
|
|
204
208
|
} else {
|
|
205
209
|
throw new Error(`Unsupported matchExpression found when converting to selector string. ${ value }`);
|
|
206
210
|
}
|
|
@@ -163,14 +163,14 @@ describe('pagination-utils', () => {
|
|
|
163
163
|
|
|
164
164
|
it('should return false if steve cache is disabled', () => {
|
|
165
165
|
mockRootGetters['features/get'].mockImplementation((feature: string) => feature === STEVE_CACHE ? false : undefined);
|
|
166
|
-
const result = paginationUtils.isEnabled({ rootGetters: mockRootGetters, $
|
|
166
|
+
const result = paginationUtils.isEnabled({ rootGetters: mockRootGetters, $extension: mockPlugin }, enabledFor);
|
|
167
167
|
|
|
168
168
|
expect(result).toBe(false);
|
|
169
169
|
});
|
|
170
170
|
|
|
171
171
|
it('should return false if pagination settings are not defined', () => {
|
|
172
172
|
jest.spyOn(paginationUtils, 'getSettings').mockReturnValue(undefined);
|
|
173
|
-
const result = paginationUtils.isEnabled({ rootGetters: mockRootGetters, $
|
|
173
|
+
const result = paginationUtils.isEnabled({ rootGetters: mockRootGetters, $extension: mockPlugin }, enabledFor);
|
|
174
174
|
|
|
175
175
|
expect(result).toBe(false);
|
|
176
176
|
|
|
@@ -189,7 +189,7 @@ describe('pagination-utils', () => {
|
|
|
189
189
|
return null;
|
|
190
190
|
});
|
|
191
191
|
|
|
192
|
-
const result = paginationUtils.isEnabled({ rootGetters: mockRootGetters, $
|
|
192
|
+
const result = paginationUtils.isEnabled({ rootGetters: mockRootGetters, $extension: mockPlugin }, undefined as unknown as PaginationResourceContext);
|
|
193
193
|
|
|
194
194
|
expect(result).toBe(false);
|
|
195
195
|
});
|
|
@@ -200,7 +200,7 @@ describe('pagination-utils', () => {
|
|
|
200
200
|
|
|
201
201
|
mockPlugin.getAll.mockReturnValue({ [EXT_IDS.SERVER_SIDE_PAGINATION_RESOURCES]: { 'my-ext': () => extensionSettings } });
|
|
202
202
|
|
|
203
|
-
const result = paginationUtils.isEnabled({ rootGetters: mockRootGetters, $
|
|
203
|
+
const result = paginationUtils.isEnabled({ rootGetters: mockRootGetters, $extension: mockPlugin }, enabledFor);
|
|
204
204
|
|
|
205
205
|
expect(result).toBe(true);
|
|
206
206
|
});
|
|
@@ -215,7 +215,7 @@ describe('pagination-utils', () => {
|
|
|
215
215
|
// Mocking PAGINATION_SETTINGS_STORE_DEFAULTS behavior
|
|
216
216
|
jest.spyOn(paginationUtils, 'getStoreDefault').mockReturnValue(defaultSettings);
|
|
217
217
|
|
|
218
|
-
const result = paginationUtils.isEnabled({ rootGetters: mockRootGetters, $
|
|
218
|
+
const result = paginationUtils.isEnabled({ rootGetters: mockRootGetters, $extension: mockPlugin }, enabledFor);
|
|
219
219
|
|
|
220
220
|
expect(result).toBe(true);
|
|
221
221
|
});
|
|
@@ -235,7 +235,7 @@ describe('pagination-utils', () => {
|
|
|
235
235
|
// Mocking PAGINATION_SETTINGS_STORE_DEFAULTS behavior
|
|
236
236
|
jest.spyOn(paginationUtils, 'getStoreDefault').mockReturnValue({ cluster: { resources: { enableAll: true } } });
|
|
237
237
|
|
|
238
|
-
const result = paginationUtils.isEnabled({ rootGetters: mockRootGetters, $
|
|
238
|
+
const result = paginationUtils.isEnabled({ rootGetters: mockRootGetters, $extension: mockPlugin }, enabledFor);
|
|
239
239
|
|
|
240
240
|
expect(result).toBe(true);
|
|
241
241
|
});
|
|
@@ -255,7 +255,7 @@ describe('pagination-utils', () => {
|
|
|
255
255
|
return null;
|
|
256
256
|
});
|
|
257
257
|
|
|
258
|
-
const result = paginationUtils.isEnabled({ rootGetters: mockRootGetters, $
|
|
258
|
+
const result = paginationUtils.isEnabled({ rootGetters: mockRootGetters, $extension: mockPlugin }, enabledFor);
|
|
259
259
|
|
|
260
260
|
expect(result).toBe(true);
|
|
261
261
|
});
|
|
@@ -275,7 +275,7 @@ describe('pagination-utils', () => {
|
|
|
275
275
|
return null;
|
|
276
276
|
});
|
|
277
277
|
|
|
278
|
-
const result = paginationUtils.isEnabled({ rootGetters: mockRootGetters, $
|
|
278
|
+
const result = paginationUtils.isEnabled({ rootGetters: mockRootGetters, $extension: mockPlugin }, enabledFor);
|
|
279
279
|
|
|
280
280
|
expect(result).toBe(false);
|
|
281
281
|
});
|
package/vue.config.js
CHANGED
|
@@ -323,16 +323,16 @@ const getVirtualModules = (dir, includePkg) => {
|
|
|
323
323
|
|
|
324
324
|
// Package file must have rancher field to be a plugin
|
|
325
325
|
if (includePkg(name) && library.rancher) {
|
|
326
|
-
reqs += `$
|
|
326
|
+
reqs += `$extension.registerBuiltinExtension('${ name }', require(\'~/pkg/${ name }\')); `;
|
|
327
327
|
}
|
|
328
328
|
});
|
|
329
329
|
}
|
|
330
330
|
|
|
331
331
|
Object.keys(librariesIndex).forEach((i) => {
|
|
332
|
-
reqs += `$
|
|
332
|
+
reqs += `$extension.loadAsync('${ i }', '/pkg/${ i }/${ librariesIndex[i] }');`;
|
|
333
333
|
});
|
|
334
334
|
|
|
335
|
-
return new VirtualModulesPlugin({ 'node_modules/@rancher/dynamic.js': `export default function ($
|
|
335
|
+
return new VirtualModulesPlugin({ 'node_modules/@rancher/dynamic.js': `export default function ($extension) { ${ reqs } };` });
|
|
336
336
|
};
|
|
337
337
|
|
|
338
338
|
const getAutoImport = () => new webpack.NormalModuleReplacementPlugin(/^@rancher\/auto-import$/, (resource) => {
|
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
import { ExtensionManager } from '@shell/types/extension-manager';
|
|
2
|
-
import { getExtensionManager } from '@shell/core/extension-manager-impl';
|
|
3
|
-
|
|
4
|
-
/**
|
|
5
|
-
* Provides access to the registered extension manager instance. Used within Vue
|
|
6
|
-
* components or other composables that require extension functionality.
|
|
7
|
-
* @returns The extension manager instance
|
|
8
|
-
*/
|
|
9
|
-
export const useExtensionManager = (): ExtensionManager => {
|
|
10
|
-
const extension = getExtensionManager();
|
|
11
|
-
|
|
12
|
-
if (!extension) {
|
|
13
|
-
throw new Error('useExtensionManager must be called after the extensionManager has been initialized');
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
return extension;
|
|
17
|
-
};
|
package/core/plugins.js
DELETED
|
@@ -1,38 +0,0 @@
|
|
|
1
|
-
import { throttle } from 'lodash';
|
|
2
|
-
import { initExtensionManager } from './extension-manager-impl';
|
|
3
|
-
|
|
4
|
-
export default function(context, inject) {
|
|
5
|
-
const extensionManager = initExtensionManager(context);
|
|
6
|
-
const deprecationMessage = '[DEPRECATED] `this.$plugin` is deprecated and will be removed in a future version. Use `this.$extension` instead.';
|
|
7
|
-
|
|
8
|
-
inject('plugin', deprecationProxy(extensionManager, deprecationMessage));
|
|
9
|
-
inject('extension', extensionManager);
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
/**
|
|
13
|
-
* Proxy to log a deprecation warning when target is accessed. Only prints
|
|
14
|
-
* deprecation warnings in dev builds.
|
|
15
|
-
* @param {*} target the object to proxy
|
|
16
|
-
* @param {*} message the deprecation warning to print to the console
|
|
17
|
-
* @returns The proxied target that prints a deprecation warning when target is
|
|
18
|
-
* accessed
|
|
19
|
-
*/
|
|
20
|
-
const deprecationProxy = (target, message) => {
|
|
21
|
-
const logWarning = throttle(() => {
|
|
22
|
-
// eslint-disable-next-line no-console
|
|
23
|
-
console.warn(message);
|
|
24
|
-
}, 150);
|
|
25
|
-
|
|
26
|
-
const deprecationHandler = {
|
|
27
|
-
get(target, prop) {
|
|
28
|
-
logWarning();
|
|
29
|
-
|
|
30
|
-
return Reflect.get(target, prop);
|
|
31
|
-
}
|
|
32
|
-
};
|
|
33
|
-
|
|
34
|
-
// an empty handler allows the proxy to behave just like the original target
|
|
35
|
-
const proxyHandler = !!process.env.dev ? deprecationHandler : {};
|
|
36
|
-
|
|
37
|
-
return new Proxy(target, proxyHandler);
|
|
38
|
-
};
|
|
@@ -1,32 +0,0 @@
|
|
|
1
|
-
import { VTooltip } from 'floating-vue';
|
|
2
|
-
import { purifyHTML } from '@shell/plugins/clean-html';
|
|
3
|
-
|
|
4
|
-
function purifyContent(value) {
|
|
5
|
-
const type = typeof value;
|
|
6
|
-
|
|
7
|
-
if (type === 'string') {
|
|
8
|
-
return purifyHTML(value);
|
|
9
|
-
} else if (value && type === 'object' && typeof value.content === 'string') {
|
|
10
|
-
return { ...value, content: purifyHTML(value.content) };
|
|
11
|
-
} else {
|
|
12
|
-
return value;
|
|
13
|
-
}
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
function beforeMount(el, { value, oldValue, modifiers }) {
|
|
17
|
-
const purifiedValue = purifyContent(value);
|
|
18
|
-
|
|
19
|
-
VTooltip.beforeMount(
|
|
20
|
-
el,
|
|
21
|
-
{
|
|
22
|
-
value: purifiedValue, oldValue, modifiers
|
|
23
|
-
});
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
const cleanTooltipDirective = {
|
|
27
|
-
...VTooltip,
|
|
28
|
-
beforeMount,
|
|
29
|
-
updated: beforeMount,
|
|
30
|
-
};
|
|
31
|
-
|
|
32
|
-
export default cleanTooltipDirective;
|
|
@@ -1,37 +0,0 @@
|
|
|
1
|
-
import { Store } from 'vuex';
|
|
2
|
-
|
|
3
|
-
interface PluginContext {
|
|
4
|
-
store: Store<any>;
|
|
5
|
-
[key: string]: any;
|
|
6
|
-
}
|
|
7
|
-
|
|
8
|
-
export default function(context: PluginContext, inject: (key: string, value: any) => void) {
|
|
9
|
-
const { store } = context;
|
|
10
|
-
|
|
11
|
-
// Load all API modules
|
|
12
|
-
const apiContext = (require as any).context(
|
|
13
|
-
'@shell/plugins/internal-api', // the base directory
|
|
14
|
-
true, // whether to search subdirectories
|
|
15
|
-
/\.api\.ts$/ // only .api.ts files
|
|
16
|
-
);
|
|
17
|
-
|
|
18
|
-
apiContext.keys().forEach((relativePath: string) => {
|
|
19
|
-
const mod = apiContext(relativePath);
|
|
20
|
-
const ApiClass = mod.default;
|
|
21
|
-
|
|
22
|
-
if (typeof ApiClass === 'function') {
|
|
23
|
-
// Check for a static `apiName` property, or fallback to filename
|
|
24
|
-
let apiName: string = ApiClass.apiName();
|
|
25
|
-
|
|
26
|
-
if (!apiName) {
|
|
27
|
-
// fallback to filename (strip leading ‘./’ and extension)
|
|
28
|
-
apiName = `$${ relativePath.replace(/^\.\//, '').replace(/\.\w+$/, '') }`;
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
const instance = new ApiClass(store);
|
|
32
|
-
|
|
33
|
-
// The inject() method automatically adds the `$` prefix
|
|
34
|
-
inject(apiName, instance);
|
|
35
|
-
}
|
|
36
|
-
});
|
|
37
|
-
}
|
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
export abstract class BaseApi {
|
|
2
|
-
// The Vuex store, available to all API classes
|
|
3
|
-
protected $store: any;
|
|
4
|
-
|
|
5
|
-
// Documented requirement: each API should define its static apiName.
|
|
6
|
-
static apiName(): string {
|
|
7
|
-
throw new Error('apiName() static method has not been implemented');
|
|
8
|
-
}
|
|
9
|
-
|
|
10
|
-
constructor(store: any) {
|
|
11
|
-
this.$store = store;
|
|
12
|
-
}
|
|
13
|
-
}
|
|
@@ -1,108 +0,0 @@
|
|
|
1
|
-
import { GrowlConfig } from '@shell/types/internal-api/shell/growl';
|
|
2
|
-
import { ModalConfig } from '@shell/types/internal-api/shell/modal';
|
|
3
|
-
import { SlideInConfig } from '@shell/types/internal-api/shell/slideIn';
|
|
4
|
-
|
|
5
|
-
import { BaseApi } from '@shell/plugins/internal-api/shared/base-api';
|
|
6
|
-
|
|
7
|
-
export default class ShellApi extends BaseApi {
|
|
8
|
-
static apiName() {
|
|
9
|
-
return 'shell';
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
/**
|
|
13
|
-
* Dispatches a growl notification.
|
|
14
|
-
*
|
|
15
|
-
* @param config - Configuration for the growl notification.
|
|
16
|
-
* - If `message` is a string, it is treated as the main content of the notification.
|
|
17
|
-
* - If `message` is a `DetailedMessage` object, `title` and `description` are extracted.
|
|
18
|
-
*
|
|
19
|
-
* Example:
|
|
20
|
-
* ```ts
|
|
21
|
-
* this.$shell.growl({ message: 'Operation successful!', type: 'success' });
|
|
22
|
-
* this.$shell.growl({ message: { title: 'Warning', description: 'Check your input.' }, type: 'warning' });
|
|
23
|
-
* ```
|
|
24
|
-
*/
|
|
25
|
-
protected growl(config: GrowlConfig): void {
|
|
26
|
-
const { type = 'error', timeout = 5000 } = config;
|
|
27
|
-
|
|
28
|
-
let title = '';
|
|
29
|
-
let description = '';
|
|
30
|
-
|
|
31
|
-
if (typeof config.message === 'string') {
|
|
32
|
-
description = config.message;
|
|
33
|
-
} else {
|
|
34
|
-
title = config.message.title || '';
|
|
35
|
-
description = config.message.description;
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
this.$store.dispatch(
|
|
39
|
-
`growl/${ type }`,
|
|
40
|
-
{
|
|
41
|
-
title,
|
|
42
|
-
message: description,
|
|
43
|
-
timeout,
|
|
44
|
-
},
|
|
45
|
-
{ root: true }
|
|
46
|
-
);
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
/**
|
|
50
|
-
* Opens a modal by committing to the Vuex store.
|
|
51
|
-
*
|
|
52
|
-
* This method updates the store's `modal` module to show a modal with the
|
|
53
|
-
* specified configuration. The modal is rendered using the `ModalManager` component,
|
|
54
|
-
* and its content is dynamically loaded based on the `component` field in the configuration.
|
|
55
|
-
*
|
|
56
|
-
* @param config A `ModalConfig` object defining the modal’s content and behavior.
|
|
57
|
-
*
|
|
58
|
-
* Example:
|
|
59
|
-
* ```ts
|
|
60
|
-
* this.$shell.modal({
|
|
61
|
-
* component: MyCustomModal,
|
|
62
|
-
* componentProps: { title: 'Hello Modal' },
|
|
63
|
-
* resources: [someResource],
|
|
64
|
-
* modalWidth: '800px',
|
|
65
|
-
* closeOnClickOutside: false
|
|
66
|
-
* });
|
|
67
|
-
* ```
|
|
68
|
-
*/
|
|
69
|
-
protected modal(config: ModalConfig): void {
|
|
70
|
-
this.$store.commit('modal/openModal', {
|
|
71
|
-
component: config.component,
|
|
72
|
-
componentProps: config.componentProps || {},
|
|
73
|
-
resources: config.resources || [],
|
|
74
|
-
modalWidth: config.modalWidth || '600px',
|
|
75
|
-
closeOnClickOutside: config.closeOnClickOutside ?? true,
|
|
76
|
-
// modalSticky: config.modalSticky ?? false // Not implemented yet
|
|
77
|
-
});
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
/**
|
|
81
|
-
* Opens the slide-in panel with the specified component and props.
|
|
82
|
-
*
|
|
83
|
-
* This method commits the `open` mutation to the `slideInPanel` Vuex module,
|
|
84
|
-
* which sets the current component to be rendered and its associated props.
|
|
85
|
-
* The slide-in panel becomes visible after the mutation.
|
|
86
|
-
*
|
|
87
|
-
* @param config - The configuration object for the slide-in panel.
|
|
88
|
-
*
|
|
89
|
-
* Example Usage:
|
|
90
|
-
* ```ts
|
|
91
|
-
* import MyComponent from '@/components/MyComponent.vue';
|
|
92
|
-
*
|
|
93
|
-
* this.$shell.slideInPanel({
|
|
94
|
-
* component: MyComponent,
|
|
95
|
-
* componentProps: { foo: 'bar' }
|
|
96
|
-
* });
|
|
97
|
-
* ```
|
|
98
|
-
*
|
|
99
|
-
* @param config.component - A Vue component (imported SFC, functional component, etc.) to be rendered in the panel.
|
|
100
|
-
* @param config.componentProps - (Optional) Props to pass to the component. These should align with the component's defined props.
|
|
101
|
-
*/
|
|
102
|
-
protected slideInPanel(config: SlideInConfig): void {
|
|
103
|
-
this.$store.commit('slideInPanel/open', {
|
|
104
|
-
component: config.component,
|
|
105
|
-
componentProps: config.componentProps || {}
|
|
106
|
-
});
|
|
107
|
-
}
|
|
108
|
-
}
|
|
@@ -1,25 +0,0 @@
|
|
|
1
|
-
export interface DetailedMessage {
|
|
2
|
-
title?: string;
|
|
3
|
-
description: string;
|
|
4
|
-
}
|
|
5
|
-
|
|
6
|
-
export interface GrowlConfig {
|
|
7
|
-
/**
|
|
8
|
-
* The content of the notification message.
|
|
9
|
-
* Either a simple string or an object with `title` and `description` for detailed notifications.
|
|
10
|
-
*/
|
|
11
|
-
message: string | DetailedMessage;
|
|
12
|
-
|
|
13
|
-
/**
|
|
14
|
-
* Optional type of the growl notification.
|
|
15
|
-
* Determines the visual style of the notification.
|
|
16
|
-
* Defaults to `'error'` if not provided.
|
|
17
|
-
*/
|
|
18
|
-
type?: 'success' | 'info' | 'warning' | 'error';
|
|
19
|
-
|
|
20
|
-
/**
|
|
21
|
-
* Optional duration (in milliseconds) for which the notification should be displayed.
|
|
22
|
-
* Defaults to `5000` milliseconds. A value of `0` keeps the notification indefinitely.
|
|
23
|
-
*/
|
|
24
|
-
timeout?: number;
|
|
25
|
-
}
|
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
import type { Component } from 'vue';
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* Configuration object for opening a slide-in panel.
|
|
5
|
-
*
|
|
6
|
-
* @property component - The Vue component to render in the slide-in panel.
|
|
7
|
-
* This should be a valid Vue Component, such as an imported SFC or functional component.
|
|
8
|
-
*
|
|
9
|
-
* @property componentProps - (Optional) An object containing props to be passed to the component rendered in the slide-in panel.
|
|
10
|
-
* Keys should match the props defined in the provided component.
|
|
11
|
-
*/
|
|
12
|
-
export interface SlideInConfig {
|
|
13
|
-
component: Component | null;
|
|
14
|
-
componentProps?: Record<string, any>;
|
|
15
|
-
}
|