@rancher/shell 0.3.1 → 0.3.2
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/global/_gauges.scss +1 -1
- package/assets/styles/global/_layout.scss +4 -0
- package/assets/styles/themes/_dark.scss +1 -0
- package/assets/translations/en-us.yaml +4 -0
- package/assets/translations/zh-hans.yaml +175 -44
- package/components/ActionMenu.vue +28 -7
- package/components/DetailTop.vue +14 -1
- package/components/ExtensionPanel.vue +42 -0
- package/components/IconOrSvg.vue +31 -2
- package/components/ResourceDetail/Masthead.vue +16 -3
- package/components/ResourceList/index.vue +15 -2
- package/components/ResourceTable.vue +3 -1
- package/components/SortableTable/THead.vue +6 -9
- package/components/SortableTable/filtering.js +1 -1
- package/components/SortableTable/selection.js +15 -3
- package/components/Tabbed/Tab.vue +1 -1
- package/components/form/ResourceTabs/index.vue +23 -0
- package/components/nav/Header.vue +69 -5
- package/config/product/backup.js +1 -1
- package/config/query-params.js +1 -0
- package/config/uiplugins.js +3 -3
- package/core/plugin-helpers.js +171 -0
- package/core/plugin.ts +61 -1
- package/core/plugins.js +33 -0
- package/core/types.ts +128 -2
- package/edit/catalog.cattle.io.clusterrepo.vue +3 -0
- package/edit/monitoring.coreos.com.alertmanagerconfig/receiverConfig.vue +14 -2
- package/edit/provisioning.cattle.io.cluster/__tests__/rke2.test.ts +3 -0
- package/edit/provisioning.cattle.io.cluster/rke2.vue +21 -18
- package/package.json +1 -1
- package/pages/c/_cluster/apps/charts/index.vue +17 -0
- package/pages/c/_cluster/explorer/index.vue +39 -0
- package/pages/c/_cluster/uiplugins/DeveloperInstallDialog.vue +2 -0
- package/pages/c/_cluster/uiplugins/InstallDialog.vue +3 -0
- package/pages/c/_cluster/uiplugins/PluginInfoPanel.vue +8 -1
- package/pages/c/_cluster/uiplugins/RemoveUIPlugins.vue +2 -0
- package/pages/c/_cluster/uiplugins/SetupUIPlugins.vue +1 -0
- package/pages/c/_cluster/uiplugins/UninstallDialog.vue +2 -0
- package/pages/c/_cluster/uiplugins/index.vue +14 -1
- package/plugins/dashboard-store/resource-class.js +16 -1
- package/rancher-components/components/Banner/Banner.vue +1 -0
- package/store/action-menu.js +4 -3
- package/store/type-map.js +26 -0
- package/types/shell/index.d.ts +1 -0
|
@@ -40,6 +40,9 @@ import { isEmpty } from '@shell/utils/object';
|
|
|
40
40
|
import ConfigBadge from './ConfigBadge';
|
|
41
41
|
import EventsTable from './EventsTable';
|
|
42
42
|
import { fetchClusterResources } from './explorer-utils';
|
|
43
|
+
import SimpleBox from '@shell/components/SimpleBox';
|
|
44
|
+
import { ExtensionPoint, CardLocation } from '@shell/core/types';
|
|
45
|
+
import { getApplicableExtensionEnhancements } from '@shell/core/plugin-helpers';
|
|
43
46
|
|
|
44
47
|
export const RESOURCES = [NAMESPACE, INGRESS, PV, WORKLOAD_TYPES.DEPLOYMENT, WORKLOAD_TYPES.STATEFUL_SET, WORKLOAD_TYPES.JOB, WORKLOAD_TYPES.DAEMON_SET, SERVICE];
|
|
45
48
|
|
|
@@ -71,6 +74,7 @@ export default {
|
|
|
71
74
|
EmberPage,
|
|
72
75
|
ConfigBadge,
|
|
73
76
|
EventsTable,
|
|
77
|
+
SimpleBox,
|
|
74
78
|
},
|
|
75
79
|
|
|
76
80
|
mixins: [metricPoller],
|
|
@@ -126,6 +130,7 @@ export default {
|
|
|
126
130
|
ETCD_METRICS_SUMMARY_URL,
|
|
127
131
|
clusterCounts,
|
|
128
132
|
selectedTab: 'cluster-events',
|
|
133
|
+
extensionCards: getApplicableExtensionEnhancements(this, ExtensionPoint.CARD, CardLocation.CLUSTER_DASHBOARD_CARD, this.$route),
|
|
129
134
|
};
|
|
130
135
|
},
|
|
131
136
|
|
|
@@ -492,6 +497,27 @@ export default {
|
|
|
492
497
|
/>
|
|
493
498
|
</div>
|
|
494
499
|
|
|
500
|
+
<!-- extension cards -->
|
|
501
|
+
<div
|
|
502
|
+
v-if="extensionCards.length"
|
|
503
|
+
class="extension-card-container mt-20"
|
|
504
|
+
>
|
|
505
|
+
<SimpleBox
|
|
506
|
+
v-for="item, i in extensionCards"
|
|
507
|
+
:key="`extensionCards${i}`"
|
|
508
|
+
class="extension-card"
|
|
509
|
+
:style="item.style"
|
|
510
|
+
>
|
|
511
|
+
<h3>
|
|
512
|
+
{{ item.label }}
|
|
513
|
+
</h3>
|
|
514
|
+
<component
|
|
515
|
+
:is="item.component"
|
|
516
|
+
:resource="currentCluster"
|
|
517
|
+
/>
|
|
518
|
+
</SimpleBox>
|
|
519
|
+
</div>
|
|
520
|
+
|
|
495
521
|
<h3
|
|
496
522
|
v-if="!hasV1Monitoring && hasStats"
|
|
497
523
|
class="mt-40"
|
|
@@ -631,6 +657,19 @@ export default {
|
|
|
631
657
|
</template>
|
|
632
658
|
|
|
633
659
|
<style lang="scss" scoped>
|
|
660
|
+
.extension-card-container {
|
|
661
|
+
display: grid;
|
|
662
|
+
grid-template-columns: repeat(auto-fit, minmax(calc((100%/3) - 40px), 1fr));
|
|
663
|
+
grid-column-gap: 15px;
|
|
664
|
+
grid-row-gap: 20px;
|
|
665
|
+
}
|
|
666
|
+
|
|
667
|
+
@media only screen and (max-width: map-get($breakpoints, "--viewport-9")) {
|
|
668
|
+
.extension-card-container {
|
|
669
|
+
grid-template-columns: 1fr !important;
|
|
670
|
+
}
|
|
671
|
+
}
|
|
672
|
+
|
|
634
673
|
.cluster-dashboard-glance {
|
|
635
674
|
border-top: 1px solid var(--border);
|
|
636
675
|
border-bottom: 1px solid var(--border);
|
|
@@ -181,12 +181,14 @@ export default {
|
|
|
181
181
|
<div class="dialog-buttons mt-20">
|
|
182
182
|
<button
|
|
183
183
|
class="btn role-secondary"
|
|
184
|
+
data-testid="dev-install-ext-modal-cancel-btn"
|
|
184
185
|
@click="closeDialog()"
|
|
185
186
|
>
|
|
186
187
|
{{ t('generic.cancel') }}
|
|
187
188
|
</button>
|
|
188
189
|
<AsyncButton
|
|
189
190
|
mode="load"
|
|
191
|
+
data-testid="dev-install-ext-modal-install-btn"
|
|
190
192
|
@click="loadPlugin"
|
|
191
193
|
/>
|
|
192
194
|
</div>
|
|
@@ -243,6 +243,7 @@ export default {
|
|
|
243
243
|
label-key="plugins.install.version"
|
|
244
244
|
:options="versionOptions"
|
|
245
245
|
class="version-selector mt-10"
|
|
246
|
+
data-testid="install-ext-modal-select-version"
|
|
246
247
|
/>
|
|
247
248
|
<div v-else>
|
|
248
249
|
{{ t('plugins.install.version') }} {{ version }}
|
|
@@ -252,12 +253,14 @@ export default {
|
|
|
252
253
|
<button
|
|
253
254
|
:disabled="busy"
|
|
254
255
|
class="btn role-secondary"
|
|
256
|
+
data-testid="install-ext-modal-cancel-btn"
|
|
255
257
|
@click="closeDialog(false)"
|
|
256
258
|
>
|
|
257
259
|
{{ t('generic.cancel') }}
|
|
258
260
|
</button>
|
|
259
261
|
<AsyncButton
|
|
260
262
|
:mode="buttonMode"
|
|
263
|
+
data-testid="install-ext-modal-install-btn"
|
|
261
264
|
@click="install"
|
|
262
265
|
/>
|
|
263
266
|
</div>
|
|
@@ -113,10 +113,12 @@ export default {
|
|
|
113
113
|
<div
|
|
114
114
|
v-if="showSlideIn"
|
|
115
115
|
class="glass"
|
|
116
|
+
data-testid="extension-details-bg"
|
|
116
117
|
@click="hide()"
|
|
117
118
|
/>
|
|
118
119
|
<div
|
|
119
120
|
class="slideIn"
|
|
121
|
+
data-testid="extension-details"
|
|
120
122
|
:class="{'hide': false, 'slideIn__show': showSlideIn}"
|
|
121
123
|
>
|
|
122
124
|
<div
|
|
@@ -142,7 +144,10 @@ export default {
|
|
|
142
144
|
>
|
|
143
145
|
</div>
|
|
144
146
|
<div class="plugin-title">
|
|
145
|
-
<h2
|
|
147
|
+
<h2
|
|
148
|
+
class="slideIn__header"
|
|
149
|
+
data-testid="extension-details-title"
|
|
150
|
+
>
|
|
146
151
|
{{ info.name }}
|
|
147
152
|
</h2>
|
|
148
153
|
<p class="plugin-description">
|
|
@@ -153,6 +158,7 @@ export default {
|
|
|
153
158
|
<div class="slideIn__header__buttons">
|
|
154
159
|
<div
|
|
155
160
|
class="slideIn__header__button"
|
|
161
|
+
data-testid="extension-details-close"
|
|
156
162
|
@click="showSlideIn = false"
|
|
157
163
|
>
|
|
158
164
|
<i class="icon icon-close" />
|
|
@@ -236,6 +242,7 @@ export default {
|
|
|
236
242
|
position: fixed;
|
|
237
243
|
top: 0;
|
|
238
244
|
left: 0;
|
|
245
|
+
z-index: 1;
|
|
239
246
|
|
|
240
247
|
$slideout-width: 35%;
|
|
241
248
|
$title-height: 50px;
|
|
@@ -107,6 +107,7 @@ export default {
|
|
|
107
107
|
name="confirm-uiplugins-remove"
|
|
108
108
|
:title="t('plugins.setup.remove.title')"
|
|
109
109
|
mode="disable"
|
|
110
|
+
data-testid="disable-ext-modal"
|
|
110
111
|
@okay="doRemove"
|
|
111
112
|
>
|
|
112
113
|
<template>
|
|
@@ -121,6 +122,7 @@ export default {
|
|
|
121
122
|
v-model="removeRepo"
|
|
122
123
|
:primary="true"
|
|
123
124
|
label-key="plugins.setup.remove.registry.title"
|
|
125
|
+
data-testid="disable-ext-modal-remove-repo"
|
|
124
126
|
/>
|
|
125
127
|
<div class="checkbox-info">
|
|
126
128
|
{{ t('plugins.setup.remove.registry.prompt') }}
|
|
@@ -84,12 +84,14 @@ export default {
|
|
|
84
84
|
<button
|
|
85
85
|
:disabled="busy"
|
|
86
86
|
class="btn role-secondary"
|
|
87
|
+
data-testid="uninstall-ext-modal-cancel-btn"
|
|
87
88
|
@click="closeDialog(false)"
|
|
88
89
|
>
|
|
89
90
|
{{ t('generic.cancel') }}
|
|
90
91
|
</button>
|
|
91
92
|
<AsyncButton
|
|
92
93
|
mode="uninstall"
|
|
94
|
+
data-testid="uninstall-ext-modal-uninstall-btn"
|
|
93
95
|
@click="uninstall()"
|
|
94
96
|
/>
|
|
95
97
|
</div>
|
|
@@ -492,10 +492,13 @@ export default {
|
|
|
492
492
|
<template>
|
|
493
493
|
<div class="plugins">
|
|
494
494
|
<div class="plugin-header">
|
|
495
|
-
<h2
|
|
495
|
+
<h2 data-testid="extensions-page-title">
|
|
496
|
+
{{ t('plugins.title') }}
|
|
497
|
+
</h2>
|
|
496
498
|
<div
|
|
497
499
|
v-if="reloadRequired"
|
|
498
500
|
class="plugin-reload-banner mr-20"
|
|
501
|
+
data-testid="extension-reload-banner"
|
|
499
502
|
>
|
|
500
503
|
<i class="icon icon-checkmark mr-10" />
|
|
501
504
|
<span>
|
|
@@ -503,6 +506,7 @@ export default {
|
|
|
503
506
|
</span>
|
|
504
507
|
<button
|
|
505
508
|
class="ml-10 btn btn-sm role-primary"
|
|
509
|
+
data-testid="extension-reload-banner-reload-btn"
|
|
506
510
|
@click="reload()"
|
|
507
511
|
>
|
|
508
512
|
{{ t('generic.reload') }}
|
|
@@ -514,6 +518,7 @@ export default {
|
|
|
514
518
|
aria-haspopup="true"
|
|
515
519
|
type="button"
|
|
516
520
|
class="btn actions role-secondary"
|
|
521
|
+
data-testid="extensions-page-menu"
|
|
517
522
|
@click="setMenu"
|
|
518
523
|
>
|
|
519
524
|
<i class="icon icon-actions" />
|
|
@@ -555,15 +560,18 @@ export default {
|
|
|
555
560
|
<Tabbed
|
|
556
561
|
ref="tabs"
|
|
557
562
|
:tabs-only="true"
|
|
563
|
+
data-testid="extension-tabs"
|
|
558
564
|
@changed="filterChanged"
|
|
559
565
|
>
|
|
560
566
|
<Tab
|
|
561
567
|
name="installed"
|
|
568
|
+
data-testid="extension-tab-installed"
|
|
562
569
|
label-key="plugins.tabs.installed"
|
|
563
570
|
:weight="20"
|
|
564
571
|
/>
|
|
565
572
|
<Tab
|
|
566
573
|
name="available"
|
|
574
|
+
data-testid="extension-tab-available"
|
|
567
575
|
label-key="plugins.tabs.available"
|
|
568
576
|
:weight="19"
|
|
569
577
|
/>
|
|
@@ -606,6 +614,7 @@ export default {
|
|
|
606
614
|
v-for="plugin in list"
|
|
607
615
|
:key="plugin.name"
|
|
608
616
|
class="plugin"
|
|
617
|
+
:data-testid="`extension-card-${plugin.name}`"
|
|
609
618
|
@click="showPluginDetail(plugin)"
|
|
610
619
|
>
|
|
611
620
|
<div
|
|
@@ -709,6 +718,7 @@ export default {
|
|
|
709
718
|
<button
|
|
710
719
|
v-if="!plugin.builtin"
|
|
711
720
|
class="btn role-secondary"
|
|
721
|
+
:data-testid="`extension-card-uninstall-btn-${plugin.name}`"
|
|
712
722
|
@click="showUninstallDialog(plugin, $event)"
|
|
713
723
|
>
|
|
714
724
|
{{ t('plugins.uninstall.label') }}
|
|
@@ -716,6 +726,7 @@ export default {
|
|
|
716
726
|
<button
|
|
717
727
|
v-if="plugin.upgrade"
|
|
718
728
|
class="btn role-secondary"
|
|
729
|
+
:data-testid="`extension-card-update-btn-${plugin.name}`"
|
|
719
730
|
@click="showInstallDialog(plugin, 'update', $event)"
|
|
720
731
|
>
|
|
721
732
|
{{ t('plugins.update.label') }}
|
|
@@ -723,6 +734,7 @@ export default {
|
|
|
723
734
|
<button
|
|
724
735
|
v-if="!plugin.upgrade && plugin.versions.length > 1"
|
|
725
736
|
class="btn role-secondary"
|
|
737
|
+
:data-testid="`extension-card-rollback-btn-${plugin.name}`"
|
|
726
738
|
@click="showInstallDialog(plugin, 'rollback', $event)"
|
|
727
739
|
>
|
|
728
740
|
{{ t('plugins.rollback.label') }}
|
|
@@ -734,6 +746,7 @@ export default {
|
|
|
734
746
|
>
|
|
735
747
|
<button
|
|
736
748
|
class="btn role-secondary"
|
|
749
|
+
:data-testid="`extension-card-install-btn-${plugin.name}`"
|
|
737
750
|
@click="showInstallDialog(plugin, 'install', $event)"
|
|
738
751
|
>
|
|
739
752
|
{{ t('plugins.install.label') }}
|
|
@@ -37,6 +37,9 @@ import Vue from 'vue';
|
|
|
37
37
|
|
|
38
38
|
import { normalizeType } from './normalize';
|
|
39
39
|
|
|
40
|
+
import { ExtensionPoint, ActionLocation } from '@shell/core/types';
|
|
41
|
+
import { getApplicableExtensionEnhancements } from '@shell/core/plugin-helpers';
|
|
42
|
+
|
|
40
43
|
const STRING_LIKE_TYPES = [
|
|
41
44
|
'string',
|
|
42
45
|
'date',
|
|
@@ -851,7 +854,11 @@ export default class Resource {
|
|
|
851
854
|
|
|
852
855
|
// You can add custom actions by overriding your own availableActions (and probably reading super._availableActions)
|
|
853
856
|
get _availableActions() {
|
|
854
|
-
|
|
857
|
+
// get menu actions available by plugins configuration
|
|
858
|
+
const currentRoute = this.currentRouter().app._route;
|
|
859
|
+
const extensionMenuActions = getApplicableExtensionEnhancements(this.$rootState, ExtensionPoint.ACTION, ActionLocation.TABLE, currentRoute, this);
|
|
860
|
+
|
|
861
|
+
let all = [
|
|
855
862
|
{ divider: true },
|
|
856
863
|
{
|
|
857
864
|
action: this.canUpdate ? 'goToEdit' : 'goToViewConfig',
|
|
@@ -899,6 +906,13 @@ export default class Resource {
|
|
|
899
906
|
},
|
|
900
907
|
];
|
|
901
908
|
|
|
909
|
+
// Extension actions get added to the end, so add a divider if there are any
|
|
910
|
+
if (extensionMenuActions.length) {
|
|
911
|
+
// Add a divider first
|
|
912
|
+
all.push({ divider: true });
|
|
913
|
+
all = all.concat(extensionMenuActions);
|
|
914
|
+
}
|
|
915
|
+
|
|
902
916
|
return all;
|
|
903
917
|
}
|
|
904
918
|
|
|
@@ -1051,6 +1065,7 @@ export default class Resource {
|
|
|
1051
1065
|
async _save(opt = {}) {
|
|
1052
1066
|
delete this.__rehydrate;
|
|
1053
1067
|
delete this.__clone;
|
|
1068
|
+
|
|
1054
1069
|
const forNew = !this.id;
|
|
1055
1070
|
|
|
1056
1071
|
const errors = await this.validationErrors(this, opt.ignoreFields);
|
package/store/action-menu.js
CHANGED
|
@@ -22,9 +22,10 @@ export const state = function() {
|
|
|
22
22
|
};
|
|
23
23
|
|
|
24
24
|
export const getters = {
|
|
25
|
-
showing:
|
|
26
|
-
elem:
|
|
27
|
-
event:
|
|
25
|
+
showing: state => state.show,
|
|
26
|
+
elem: state => state.elem,
|
|
27
|
+
event: state => state.event,
|
|
28
|
+
resources: state => state.resources,
|
|
28
29
|
|
|
29
30
|
options(state) {
|
|
30
31
|
let selected = state.resources;
|
package/store/type-map.js
CHANGED
|
@@ -148,6 +148,8 @@ import { sortBy } from '@shell/utils/sort';
|
|
|
148
148
|
import { haveV1Monitoring, haveV2Monitoring } from '@shell/utils/monitoring';
|
|
149
149
|
import { NEU_VECTOR_NAMESPACE } from '@shell/config/product/neuvector';
|
|
150
150
|
|
|
151
|
+
import { ExtensionPoint, TableColumnLocation } from '@shell/core/types';
|
|
152
|
+
|
|
151
153
|
export const NAMESPACED = 'namespaced';
|
|
152
154
|
export const CLUSTER_LEVEL = 'cluster';
|
|
153
155
|
export const BOTH = 'both';
|
|
@@ -222,6 +224,30 @@ export function DSL(store, product, module = 'type-map') {
|
|
|
222
224
|
},
|
|
223
225
|
|
|
224
226
|
headers(type, headers) {
|
|
227
|
+
const extensionCols = store.$plugin.getUIConfig(ExtensionPoint.TABLE_COL, TableColumnLocation.RESOURCE);
|
|
228
|
+
|
|
229
|
+
// Try and insert the columns before the Age column, if that is the last column
|
|
230
|
+
let insertPosition = headers.length;
|
|
231
|
+
|
|
232
|
+
if (headers.length > 0) {
|
|
233
|
+
const lastColumn = headers[headers.length - 1];
|
|
234
|
+
|
|
235
|
+
if (lastColumn?.name === AGE.name) {
|
|
236
|
+
insertPosition--;
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
// adding extension defined cols to the correct header config
|
|
241
|
+
extensionCols.forEach((col) => {
|
|
242
|
+
if (col.locationConfig.resource) {
|
|
243
|
+
col.locationConfig.resource.forEach((resource) => {
|
|
244
|
+
if (resource && type === resource) {
|
|
245
|
+
headers.splice(insertPosition, 0, col);
|
|
246
|
+
}
|
|
247
|
+
});
|
|
248
|
+
}
|
|
249
|
+
});
|
|
250
|
+
|
|
225
251
|
headers.forEach((header) => {
|
|
226
252
|
// If on the client, then use the value getter if there is one
|
|
227
253
|
if (header.getValue) {
|
package/types/shell/index.d.ts
CHANGED