@rancher/shell 0.3.4 → 0.3.5
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/app.scss +1 -1
- package/assets/styles/fonts/_fontstack.scss +11 -11
- package/assets/styles/vendor/vue-js-modal.scss +3 -3
- package/assets/translations/en-us.yaml +92 -22
- package/assets/translations/zh-hans.yaml +84 -15
- package/babel.config.js +13 -0
- package/chart/gatekeeper.vue +77 -0
- package/chart/istio.vue +108 -111
- package/chart/logging/index.vue +13 -4
- package/chart/monitoring/index.vue +15 -5
- package/chart/monitoring/steps/uninstall-v1.vue +2 -2
- package/chart/rancher-backup/index.vue +10 -3
- package/cloud-credential/aws.vue +1 -1
- package/cloud-credential/digitalocean.vue +1 -1
- package/cloud-credential/gcp.vue +1 -1
- package/cloud-credential/generic.vue +2 -2
- package/cloud-credential/linode.vue +1 -1
- package/cloud-credential/pnap.vue +1 -1
- package/components/ActionMenu.vue +3 -4
- package/components/AssignTo.vue +1 -1
- package/components/AsyncButton.vue +1 -1
- package/components/BannerGraphic.vue +1 -1
- package/components/ButtonDropdown.vue +2 -3
- package/components/ChartPsp.vue +76 -0
- package/components/CruResource.vue +6 -2
- package/components/DashboardMetrics.vue +12 -10
- package/components/DetailText.vue +1 -1
- package/components/DisableAuthProviderModal.vue +1 -1
- package/components/EmberPage.vue +1 -1
- package/components/EtcdInfoBanner.vue +5 -4
- package/components/ExplorerMembers.vue +1 -1
- package/components/ExplorerProjectsNamespaces.vue +14 -1
- package/components/FileDiff.vue +6 -7
- package/components/GrafanaDashboard.vue +18 -21
- package/components/LazyImage.vue +10 -12
- package/components/LogItem.vue +1 -1
- package/components/Markdown.vue +1 -1
- package/components/PromptRemove.vue +2 -2
- package/components/PromptRestore.vue +1 -1
- package/components/ResourceDetail/Masthead.vue +16 -0
- package/components/ResourceDetail/index.vue +21 -4
- package/components/ResourceList/index.vue +1 -1
- package/components/ResourceTable.vue +4 -1
- package/components/SingleClusterInfo.vue +2 -2
- package/components/SortableTable/THead.vue +1 -1
- package/components/SortableTable/index.vue +5 -2
- package/components/__tests__/AsyncButton.test.ts +3 -1
- package/components/__tests__/ChartPsp.test.ts +75 -0
- package/components/__tests__/CruResource.test.ts +3 -1
- package/components/auth/Principal.vue +1 -1
- package/components/fleet/FleetBundles.vue +3 -1
- package/components/fleet/FleetClusters.vue +1 -2
- package/components/fleet/FleetIntro.vue +9 -1
- package/components/fleet/FleetNoWorkspaces.vue +62 -0
- package/components/fleet/FleetSummary.vue +7 -1
- package/components/form/LabeledSelect.vue +14 -11
- package/components/form/MatchExpressions.vue +17 -2
- package/components/form/NameNsDescription.vue +31 -45
- package/components/form/ResourceSelector.vue +1 -1
- package/components/form/SecretSelector.vue +5 -1
- package/components/form/ServiceNameSelect.vue +1 -1
- package/components/form/SimpleSecretSelector.vue +9 -9
- package/components/form/__tests__/LabeledSelect.test.ts +138 -0
- package/components/form/__tests__/NameNsDescription.ts +32 -0
- package/components/formatter/InternalExternalIP.vue +6 -0
- package/components/formatter/InvolvedObjectLink.vue +54 -0
- package/components/formatter/Link.vue +20 -4
- package/components/formatter/LinkName.vue +6 -1
- package/components/formatter/ServiceTargets.vue +1 -1
- package/components/nav/Group.vue +2 -2
- package/components/nav/NamespaceFilter.vue +15 -11
- package/components/nav/TopLevelMenu.vue +2 -4
- package/components/nav/Type.vue +1 -1
- package/components/nav/WorkspaceSwitcher.vue +46 -5
- package/config/labels-annotations.js +17 -0
- package/config/product/auth.js +3 -2
- package/config/product/explorer.js +11 -4
- package/config/product/fleet.js +2 -0
- package/config/router.js +414 -0
- package/config/table-headers.js +10 -2
- package/config/types.js +11 -8
- package/config/uiplugins.js +30 -0
- package/content/docs/en-us/whats-new.md +10 -0
- package/content/docs/zh-hans/whats-new.md +11 -1
- package/core/plugin-routes.ts +23 -0
- package/creators/app/app.package.json +2 -1
- package/creators/app/files/.eslintrc.js +1 -1
- package/creators/app/files/babel.config.js +1 -18
- package/creators/app/files/vue.config.js +7 -0
- package/creators/app/init +5 -5
- package/creators/pkg/files/.github/workflows/build-extension.yml +111 -0
- package/creators/pkg/init +35 -4
- package/creators/update/init +1 -1
- package/detail/constraints.gatekeeper.sh.constraint.vue +20 -10
- package/detail/fleet.cattle.io.gitrepo.vue +19 -11
- package/detail/harvesterhci.io.management.cluster.vue +3 -3
- package/detail/provisioning.cattle.io.cluster.vue +54 -12
- package/detail/workload/index.vue +3 -3
- package/dialog/AddClusterMemberDialog.vue +1 -1
- package/dialog/AddProjectMemberDialog.vue +2 -2
- package/dialog/AddonConfigConfirmationDialog.vue +27 -15
- package/dialog/DiagnosticTimingsDialog.vue +1 -1
- package/dialog/ForceMachineRemoveDialog.vue +1 -1
- package/dialog/GenericPrompt.vue +18 -6
- package/dialog/RotateEncryptionKeyDialog.vue +1 -1
- package/dialog/SaveAsRKETemplateDialog.vue +1 -1
- package/dialog/ScaleMachineDownDialog.vue +1 -1
- package/edit/auth/github.vue +8 -8
- package/edit/auth/googleoauth.vue +5 -5
- package/edit/auth/ldap/index.vue +1 -1
- package/edit/auth/oidc.vue +1 -1
- package/edit/auth/saml.vue +1 -1
- package/edit/cis.cattle.io.clusterscan.vue +1 -1
- package/edit/fleet.cattle.io.clustergroup.vue +6 -4
- package/edit/fleet.cattle.io.gitrepo.vue +16 -3
- package/edit/helm.cattle.io.projecthelmchart.vue +5 -1
- package/edit/management.cattle.io.fleetworkspace.vue +141 -6
- package/edit/management.cattle.io.podsecurityadmissionconfigurationtemplate.vue +4 -1
- package/edit/management.cattle.io.setting.vue +1 -1
- package/edit/monitoring.coreos.com.alertmanagerconfig/types/webhook.vue +2 -2
- package/edit/monitoring.coreos.com.receiver/tls.vue +18 -18
- package/edit/monitoring.coreos.com.receiver/types/webhook.banner.vue +4 -4
- package/edit/monitoring.coreos.com.receiver/types/webhook.vue +1 -1
- package/edit/namespace.vue +2 -2
- package/edit/networking.k8s.io.networkpolicy/PolicyRuleTarget.vue +126 -45
- package/edit/networking.k8s.io.networkpolicy/index.vue +1 -1
- package/edit/provisioning.cattle.io.cluster/MachinePool.vue +10 -0
- package/edit/provisioning.cattle.io.cluster/RegistryConfigs.vue +1 -0
- package/edit/provisioning.cattle.io.cluster/__tests__/rke2.test.ts +202 -2
- package/edit/provisioning.cattle.io.cluster/rke2.vue +248 -84
- package/edit/resources.cattle.io.backup.vue +1 -1
- package/edit/service.vue +1 -1
- package/edit/storage.k8s.io.storageclass/provisioners/driver.harvesterhci.io.vue +2 -2
- package/edit/workload/__tests__/Job.test.ts +3 -1
- package/edit/workload/index.vue +8 -3
- package/edit/workload/mixins/workload.js +16 -0
- package/layouts/default.vue +7 -3
- package/list/fleet.cattle.io.bundle.vue +6 -3
- package/list/fleet.cattle.io.clusterregistrationtoken.vue +3 -1
- package/list/fleet.cattle.io.gitrepo.vue +44 -5
- package/list/management.cattle.io.fleetworkspace.vue +45 -0
- package/list/node.vue +69 -16
- package/list/provisioning.cattle.io.cluster.vue +30 -1
- package/machine-config/azure.vue +97 -38
- package/middleware/authenticated.js +34 -0
- package/mixins/chart.js +73 -2
- package/mixins/resource-fetch.js +2 -2
- package/models/apps.statefulset.js +28 -0
- package/models/cluster/node.js +23 -2
- package/models/cluster.x-k8s.io.machine.js +4 -2
- package/models/clusterroletemplatebinding.js +7 -0
- package/models/constraints.gatekeeper.sh.constraint.js +9 -0
- package/models/fleet.cattle.io.cluster.js +19 -10
- package/models/fleet.cattle.io.gitrepo.js +7 -2
- package/models/management.cattle.io.cluster.js +1 -1
- package/models/management.cattle.io.fleetworkspace.js +12 -0
- package/models/management.cattle.io.gitreporestriction.js +5 -0
- package/models/management.cattle.io.podsecurityadmissionconfigurationtemplate.js +3 -0
- package/models/provisioning.cattle.io.cluster.js +7 -5
- package/nuxt/App.js +210 -0
- package/nuxt/axios.js +186 -0
- package/nuxt/client.js +817 -0
- package/nuxt/components/nuxt-build-indicator.vue +143 -0
- package/nuxt/components/nuxt-child.js +122 -0
- package/nuxt/components/nuxt-error.vue +98 -0
- package/nuxt/components/nuxt-link.client.js +98 -0
- package/nuxt/components/nuxt-link.server.js +16 -0
- package/nuxt/components/nuxt-loading.vue +154 -0
- package/nuxt/components/nuxt.js +101 -0
- package/nuxt/cookie-universal-nuxt.js +9 -0
- package/nuxt/empty.js +1 -0
- package/nuxt/index.js +365 -0
- package/nuxt/jsonp.js +82 -0
- package/nuxt/loading.html +39 -0
- package/nuxt/middleware.js +12 -0
- package/nuxt/mixins/fetch.client.js +90 -0
- package/nuxt/mixins/fetch.server.js +69 -0
- package/nuxt/portal-vue.js +4 -0
- package/nuxt/server.js +312 -0
- package/nuxt/store.js +178 -0
- package/nuxt/utils.js +630 -0
- package/nuxt/views/app.template.html +9 -0
- package/nuxt/views/error.html +23 -0
- package/package.json +5 -9
- package/pages/auth/setup.vue +2 -2
- package/pages/c/_cluster/apps/charts/__tests__/install.helper.test.ts +33 -0
- package/pages/c/_cluster/apps/charts/chart.vue +4 -4
- package/pages/c/_cluster/apps/charts/install.helpers.js +26 -0
- package/pages/c/_cluster/apps/charts/install.vue +40 -66
- package/pages/c/_cluster/explorer/EventsTable.vue +5 -19
- package/pages/c/_cluster/explorer/index.vue +29 -25
- package/pages/c/_cluster/explorer/tools/index.vue +8 -8
- package/pages/c/_cluster/fleet/index.vue +95 -34
- package/pages/c/_cluster/gatekeeper/index.vue +1 -1
- package/pages/c/_cluster/istio/index.vue +5 -5
- package/pages/c/_cluster/manager/cloudCredential/index.vue +1 -1
- package/pages/c/_cluster/monitoring/index.vue +7 -0
- package/pages/c/_cluster/uiplugins/InstallDialog.vue +8 -8
- package/pages/c/_cluster/uiplugins/PluginInfoPanel.vue +20 -7
- package/pages/c/_cluster/uiplugins/index.vue +49 -17
- package/pages/home.vue +9 -4
- package/pages/index.vue +10 -1
- package/plugins/clean-html-directive.js +31 -0
- package/plugins/dashboard-store/actions.js +32 -9
- package/plugins/dashboard-store/mutations.js +5 -2
- package/plugins/dashboard-store/resource-class.js +8 -1
- package/plugins/steve/mutations.js +3 -2
- package/plugins/steve/steve-description-class.js +5 -1
- package/plugins/steve/subscribe.js +63 -54
- package/plugins/steve-create-worker.js +14 -0
- package/promptRemove/management.cattle.io.globalrole.vue +2 -2
- package/promptRemove/management.cattle.io.project.vue +2 -2
- package/promptRemove/management.cattle.io.roletemplate.vue +2 -2
- package/promptRemove/pod.vue +1 -1
- package/public/index.html +65 -0
- package/rancher-components/components/Banner/Banner.test.ts +9 -1
- package/rancher-components/components/Banner/Banner.vue +1 -1
- package/rancher-components/components/Form/Checkbox/Checkbox.vue +2 -0
- package/rancher-components/components/Form/Radio/RadioButton.vue +1 -1
- package/scripts/build-pkg.sh +1 -0
- package/scripts/clean +6 -0
- package/scripts/extension/bundle +58 -0
- package/scripts/extension/helmpatch +89 -0
- package/scripts/extension/publish +314 -0
- package/scripts/test-plugins-build.sh +4 -0
- package/store/__tests__/index.test.ts +110 -0
- package/store/index.js +145 -58
- package/store/type-map.js +5 -1
- package/tsconfig.default.json +36 -0
- package/tsconfig.json +24 -0
- package/types/shell/index.d.ts +420 -343
- package/utils/__tests__/string.test.ts +12 -0
- package/utils/auth.js +65 -0
- package/utils/monitoring.js +2 -1
- package/utils/position.js +5 -8
- package/utils/router.scrollBehavior.js +80 -0
- package/utils/select.js +1 -3
- package/utils/socket.js +1 -0
- package/utils/string.js +13 -0
- package/utils/time.js +9 -0
- package/vue.config.js +679 -0
- package/chart/rancher-alerting-drivers.vue +0 -53
- package/chart/rancher-gatekeeper.vue +0 -37
- package/creators/app/files/nuxt.config.js +0 -6
- package/models/management.cattle.io.podsecurityadmissionconfigurationtemplate.ts +0 -4
- package/nuxt.config.js +0 -798
|
@@ -53,8 +53,9 @@ export async function loadSchemas(ctx, watch = true) {
|
|
|
53
53
|
|
|
54
54
|
commit('loadAll', {
|
|
55
55
|
ctx,
|
|
56
|
-
type:
|
|
57
|
-
data:
|
|
56
|
+
type: SCHEMA,
|
|
57
|
+
data: res.data,
|
|
58
|
+
revision: res.revision
|
|
58
59
|
});
|
|
59
60
|
|
|
60
61
|
if ( watch !== false ) {
|
|
@@ -148,11 +149,14 @@ export default {
|
|
|
148
149
|
commit('registerType', type);
|
|
149
150
|
}
|
|
150
151
|
|
|
152
|
+
// No need to request the resources if we have them already
|
|
151
153
|
if ( opt.force !== true && (getters['haveAll'](type) || getters['haveAllNamespace'](type, opt.namespaced))) {
|
|
152
154
|
const args = {
|
|
153
155
|
type,
|
|
154
156
|
revision: '',
|
|
155
|
-
|
|
157
|
+
// watchNamespace - used sometimes when we haven't fetched the results of a single namespace
|
|
158
|
+
// namespaced - used when we have fetched the result of a single namespace (see https://github.com/rancher/dashboard/pull/7329/files)
|
|
159
|
+
namespace: opt.watchNamespace || opt.namespaced
|
|
156
160
|
};
|
|
157
161
|
|
|
158
162
|
if (opt.watch !== false ) {
|
|
@@ -304,17 +308,21 @@ export default {
|
|
|
304
308
|
ctx,
|
|
305
309
|
type,
|
|
306
310
|
data: out.data,
|
|
311
|
+
revision: out.revision,
|
|
307
312
|
skipHaveAll,
|
|
308
313
|
namespace: opt.namespaced,
|
|
309
314
|
});
|
|
310
315
|
}
|
|
311
316
|
}
|
|
312
317
|
|
|
318
|
+
// ToDo: SM if we start a "bigger" watch (such as watch without a namespace vs a watch with a namespace), we should stop the stop the "smaller" watch so we don't have duplicate events coming back
|
|
313
319
|
if ( opt.watch !== false ) {
|
|
314
320
|
dispatch('watch', {
|
|
315
321
|
type,
|
|
316
322
|
revision: out.revision,
|
|
317
|
-
namespace: opt.watchNamespace
|
|
323
|
+
namespace: opt.watchNamespace || opt.namespaced, // it could be either apparently
|
|
324
|
+
// ToDo: SM namespaced is sometimes a boolean and sometimes a string, I don't see it as especially broken but we should refactor that in the future
|
|
325
|
+
force: opt.forceWatch === true,
|
|
318
326
|
});
|
|
319
327
|
}
|
|
320
328
|
|
|
@@ -369,15 +377,17 @@ export default {
|
|
|
369
377
|
commit('loadSelector', {
|
|
370
378
|
ctx,
|
|
371
379
|
type,
|
|
372
|
-
entries:
|
|
373
|
-
selector
|
|
380
|
+
entries: res.data,
|
|
381
|
+
selector,
|
|
382
|
+
revision: res.revision,
|
|
374
383
|
});
|
|
375
384
|
|
|
376
385
|
if ( opt.watch !== false ) {
|
|
377
386
|
dispatch('watch', {
|
|
378
387
|
type,
|
|
379
388
|
selector,
|
|
380
|
-
revision: res.revision
|
|
389
|
+
revision: res.revision,
|
|
390
|
+
force: opt.forceWatch === true,
|
|
381
391
|
});
|
|
382
392
|
}
|
|
383
393
|
|
|
@@ -394,6 +404,12 @@ export default {
|
|
|
394
404
|
// url: Use this specific URL instead of looking up the URL for the type/id. This should only be used for bootstrapping schemas on startup.
|
|
395
405
|
// @TODO depaginate: If the response is paginated, retrieve all the pages. (default: true)
|
|
396
406
|
async find(ctx, { type, id, opt }) {
|
|
407
|
+
if (!id) {
|
|
408
|
+
console.error('Attempting to find a resource with no id', type, id); // eslint-disable-line no-console
|
|
409
|
+
|
|
410
|
+
return;
|
|
411
|
+
}
|
|
412
|
+
|
|
397
413
|
const { getters, dispatch } = ctx;
|
|
398
414
|
|
|
399
415
|
opt = opt || {};
|
|
@@ -459,6 +475,11 @@ export default {
|
|
|
459
475
|
commit('registerType', type);
|
|
460
476
|
}
|
|
461
477
|
}
|
|
478
|
+
// Inject special fields for indexing schemas
|
|
479
|
+
if ( type === SCHEMA ) {
|
|
480
|
+
addSchemaIndexFields(data);
|
|
481
|
+
}
|
|
482
|
+
|
|
462
483
|
const keyField = getters.keyFieldForType(type);
|
|
463
484
|
const id = data?.[keyField] || existing?.[keyField];
|
|
464
485
|
|
|
@@ -531,8 +552,10 @@ export default {
|
|
|
531
552
|
|
|
532
553
|
// Forget a type in the store
|
|
533
554
|
// Remove all entries for that type and stop watching it
|
|
534
|
-
forgetType({ commit,
|
|
535
|
-
|
|
555
|
+
forgetType({ commit, dispatch, state }, type) {
|
|
556
|
+
state.started
|
|
557
|
+
.filter(entry => entry.type === type)
|
|
558
|
+
.forEach(entry => dispatch('unwatch', entry));
|
|
536
559
|
|
|
537
560
|
commit('forgetType', type);
|
|
538
561
|
},
|
|
@@ -261,7 +261,8 @@ export function loadAll(state, {
|
|
|
261
261
|
data,
|
|
262
262
|
ctx,
|
|
263
263
|
skipHaveAll,
|
|
264
|
-
namespace
|
|
264
|
+
namespace,
|
|
265
|
+
revision
|
|
265
266
|
}) {
|
|
266
267
|
const { getters } = ctx;
|
|
267
268
|
|
|
@@ -283,6 +284,7 @@ export function loadAll(state, {
|
|
|
283
284
|
|
|
284
285
|
clear(cache.list);
|
|
285
286
|
cache.map.clear();
|
|
287
|
+
cache.revision = revision || 0;
|
|
286
288
|
cache.generation++;
|
|
287
289
|
|
|
288
290
|
addObjects(cache.list, proxies);
|
|
@@ -320,7 +322,7 @@ export default {
|
|
|
320
322
|
},
|
|
321
323
|
|
|
322
324
|
loadSelector(state, {
|
|
323
|
-
type, entries, ctx, selector
|
|
325
|
+
type, entries, ctx, selector, revision
|
|
324
326
|
}) {
|
|
325
327
|
const cache = registerType(state, type);
|
|
326
328
|
|
|
@@ -329,6 +331,7 @@ export default {
|
|
|
329
331
|
}
|
|
330
332
|
|
|
331
333
|
cache.haveSelector[selector] = true;
|
|
334
|
+
cache.revision = revision || 0;
|
|
332
335
|
},
|
|
333
336
|
|
|
334
337
|
loadAll,
|
|
@@ -1110,7 +1110,7 @@ export default class Resource {
|
|
|
1110
1110
|
}
|
|
1111
1111
|
|
|
1112
1112
|
// @TODO remove this once the API maps steve _type <-> k8s type in both directions
|
|
1113
|
-
opt.data = { ...this };
|
|
1113
|
+
opt.data = this.toSave() || { ...this };
|
|
1114
1114
|
|
|
1115
1115
|
if (opt?.data._type) {
|
|
1116
1116
|
opt.data.type = opt.data._type;
|
|
@@ -1884,6 +1884,13 @@ export default class Resource {
|
|
|
1884
1884
|
return out;
|
|
1885
1885
|
}
|
|
1886
1886
|
|
|
1887
|
+
/**
|
|
1888
|
+
* Allow models to override the object that is sent when saving this resource
|
|
1889
|
+
*/
|
|
1890
|
+
toSave() {
|
|
1891
|
+
return undefined;
|
|
1892
|
+
}
|
|
1893
|
+
|
|
1887
1894
|
get creationTimestamp() {
|
|
1888
1895
|
return this.metadata?.creationTimestamp;
|
|
1889
1896
|
}
|
|
@@ -121,7 +121,8 @@ export default {
|
|
|
121
121
|
data,
|
|
122
122
|
ctx,
|
|
123
123
|
skipHaveAll,
|
|
124
|
-
namespace
|
|
124
|
+
namespace,
|
|
125
|
+
revision
|
|
125
126
|
}) {
|
|
126
127
|
// Performance testing in dev and when env var is set
|
|
127
128
|
if (process.env.dev && !!process.env.perfTest) {
|
|
@@ -129,7 +130,7 @@ export default {
|
|
|
129
130
|
}
|
|
130
131
|
|
|
131
132
|
const proxies = loadAll(state, {
|
|
132
|
-
type, data, ctx, skipHaveAll, namespace
|
|
133
|
+
type, data, ctx, skipHaveAll, namespace, revision
|
|
133
134
|
});
|
|
134
135
|
|
|
135
136
|
// If we loaded a set of pods, then update the podsByNamespace cache
|
|
@@ -20,7 +20,7 @@ export default class SteveDescriptionModel extends SteveModel {
|
|
|
20
20
|
this._description = value;
|
|
21
21
|
}
|
|
22
22
|
|
|
23
|
-
// Ensure when we clone that we preserve the
|
|
23
|
+
// Ensure when we clone that we preserve the description
|
|
24
24
|
toJSON() {
|
|
25
25
|
const data = super.toJSON();
|
|
26
26
|
|
|
@@ -29,4 +29,8 @@ export default class SteveDescriptionModel extends SteveModel {
|
|
|
29
29
|
|
|
30
30
|
return data;
|
|
31
31
|
}
|
|
32
|
+
|
|
33
|
+
toSave() {
|
|
34
|
+
return this.toJSON();
|
|
35
|
+
}
|
|
32
36
|
}
|
|
@@ -21,6 +21,7 @@ import Socket, {
|
|
|
21
21
|
EVENT_DISCONNECT_ERROR,
|
|
22
22
|
NO_WATCH,
|
|
23
23
|
NO_SCHEMA,
|
|
24
|
+
REVISION_TOO_OLD
|
|
24
25
|
} from '@shell/utils/socket';
|
|
25
26
|
import { normalizeType } from '@shell/plugins/dashboard-store/normalize';
|
|
26
27
|
import day from 'dayjs';
|
|
@@ -29,8 +30,6 @@ import { escapeHtml } from '@shell/utils/string';
|
|
|
29
30
|
import { keyForSubscribe } from '@shell/plugins/steve/resourceWatcher';
|
|
30
31
|
import { waitFor } from '@shell/utils/async';
|
|
31
32
|
|
|
32
|
-
// eslint-disable-next-line
|
|
33
|
-
import storeWorker from './worker/index.js';
|
|
34
33
|
import { BLANK_CLUSTER } from '@shell/store/index.js';
|
|
35
34
|
|
|
36
35
|
// minimum length of time a disconnect notification is shown
|
|
@@ -97,7 +96,7 @@ export async function createWorker(store, ctx) {
|
|
|
97
96
|
|
|
98
97
|
if (!store.$workers[storeName]) {
|
|
99
98
|
const workerMode = advancedWorker ? 'advanced' : 'basic';
|
|
100
|
-
const worker =
|
|
99
|
+
const worker = store.steveCreateWorker(workerMode);
|
|
101
100
|
|
|
102
101
|
store.$workers[storeName] = worker;
|
|
103
102
|
|
|
@@ -307,8 +306,13 @@ const sharedActions = {
|
|
|
307
306
|
}
|
|
308
307
|
|
|
309
308
|
// If socket is in error don't try to watch.... unless we `force` it
|
|
310
|
-
|
|
311
|
-
|
|
309
|
+
const inError = getters.inError(params);
|
|
310
|
+
|
|
311
|
+
if ( !stop && !force && inError ) {
|
|
312
|
+
// REVISION_TOO_OLD is a temporary state and will be handled when `resyncWatch` completes
|
|
313
|
+
if (inError !== REVISION_TOO_OLD) {
|
|
314
|
+
console.error(`Aborting Watch Request [${ getters.storeName }]. Watcher in error (${ inError })`, JSON.stringify(params)); // eslint-disable-line no-console
|
|
315
|
+
}
|
|
312
316
|
|
|
313
317
|
return;
|
|
314
318
|
}
|
|
@@ -316,7 +320,10 @@ const sharedActions = {
|
|
|
316
320
|
if ( !stop && getters.watchStarted({
|
|
317
321
|
type, id, selector, namespace
|
|
318
322
|
}) ) {
|
|
319
|
-
|
|
323
|
+
// eslint-disable-next-line no-console
|
|
324
|
+
state.debugSocket && console.debug(`Already Watching [${ getters.storeName }]`, {
|
|
325
|
+
type, id, selector, namespace
|
|
326
|
+
});
|
|
320
327
|
|
|
321
328
|
return;
|
|
322
329
|
}
|
|
@@ -347,7 +354,7 @@ const sharedActions = {
|
|
|
347
354
|
msg.selector = selector;
|
|
348
355
|
}
|
|
349
356
|
|
|
350
|
-
const worker = this.$workers[getters.storeName] || {};
|
|
357
|
+
const worker = this.$workers?.[getters.storeName] || {};
|
|
351
358
|
|
|
352
359
|
if (worker.mode === 'advanced') {
|
|
353
360
|
if ( force ) {
|
|
@@ -362,12 +369,17 @@ const sharedActions = {
|
|
|
362
369
|
return dispatch('send', msg);
|
|
363
370
|
},
|
|
364
371
|
|
|
365
|
-
unwatch(ctx,
|
|
372
|
+
unwatch(ctx, {
|
|
373
|
+
type, id, namespace, selector
|
|
374
|
+
}) {
|
|
366
375
|
const { commit, getters, dispatch } = ctx;
|
|
367
376
|
|
|
368
377
|
if (getters['schemaFor'](type)) {
|
|
369
378
|
const obj = {
|
|
370
379
|
type,
|
|
380
|
+
id,
|
|
381
|
+
namespace,
|
|
382
|
+
selector,
|
|
371
383
|
stop: true, // Stops the watch on a type
|
|
372
384
|
};
|
|
373
385
|
|
|
@@ -675,14 +687,30 @@ const defaultActions = {
|
|
|
675
687
|
/**
|
|
676
688
|
* Steve only event
|
|
677
689
|
*/
|
|
678
|
-
'ws.resource.start'({
|
|
690
|
+
'ws.resource.start'({
|
|
691
|
+
state, getters, commit, dispatch
|
|
692
|
+
}, msg) {
|
|
679
693
|
state.debugSocket && console.info(`Resource start: [${ getters.storeName }]`, msg); // eslint-disable-line no-console
|
|
680
|
-
|
|
694
|
+
|
|
695
|
+
const newWatch = {
|
|
681
696
|
type: msg.resourceType,
|
|
682
697
|
namespace: msg.namespace,
|
|
683
698
|
id: msg.id,
|
|
684
699
|
selector: msg.selector
|
|
700
|
+
};
|
|
701
|
+
|
|
702
|
+
state.started.filter((entry) => {
|
|
703
|
+
if (
|
|
704
|
+
entry.type === newWatch.type &&
|
|
705
|
+
entry.namespace !== newWatch.namespace
|
|
706
|
+
) {
|
|
707
|
+
return true;
|
|
708
|
+
}
|
|
709
|
+
}).forEach((entry) => {
|
|
710
|
+
dispatch('unwatch', entry);
|
|
685
711
|
});
|
|
712
|
+
|
|
713
|
+
commit('setWatchStarted', newWatch);
|
|
686
714
|
},
|
|
687
715
|
|
|
688
716
|
'ws.resource.error'({ getters, commit, dispatch }, msg) {
|
|
@@ -695,6 +723,10 @@ const defaultActions = {
|
|
|
695
723
|
} else if ( err.includes('failed to find schema') ) {
|
|
696
724
|
commit('setInError', { type: msg.resourceType, reason: NO_SCHEMA });
|
|
697
725
|
} else if ( err.includes('too old') ) {
|
|
726
|
+
// Set an error for (all) subs of this type. This..
|
|
727
|
+
// 1) blocks attempts by resource.stop to resub (as type is in error)
|
|
728
|
+
// 2) will be cleared when resyncWatch --> watch (with force) --> resource.start completes
|
|
729
|
+
commit('setInError', { type: msg.resourceType, reason: REVISION_TOO_OLD });
|
|
698
730
|
dispatch('resyncWatch', msg);
|
|
699
731
|
}
|
|
700
732
|
},
|
|
@@ -702,12 +734,15 @@ const defaultActions = {
|
|
|
702
734
|
/**
|
|
703
735
|
* Steve only event
|
|
704
736
|
*
|
|
705
|
-
* Steve
|
|
706
|
-
* - We have requested that the resource watch should be stopped and we receive this event as confirmation
|
|
707
|
-
* - Steve tells us that the resource
|
|
708
|
-
*
|
|
737
|
+
* Steve has stopped watching this resource. This happens for a couple of reasons
|
|
738
|
+
* - We have requested that the resource watch should be stopped (and we receive this event as confirmation)
|
|
739
|
+
* - Steve tells us that the resource watch has been stopped. Possible reasons
|
|
740
|
+
* - The rancher <--> k8s socket closed (happens every ~30 mins on mgmt socket)
|
|
741
|
+
* - Permissions has changed for the subscribed resource, so rancher closes socket
|
|
709
742
|
*/
|
|
710
|
-
'ws.resource.stop'({
|
|
743
|
+
'ws.resource.stop'({
|
|
744
|
+
state, getters, commit, dispatch
|
|
745
|
+
}, msg) {
|
|
711
746
|
const type = msg.resourceType;
|
|
712
747
|
const obj = {
|
|
713
748
|
type,
|
|
@@ -716,51 +751,23 @@ const defaultActions = {
|
|
|
716
751
|
selector: msg.selector
|
|
717
752
|
};
|
|
718
753
|
|
|
719
|
-
|
|
754
|
+
state.debugSocket && console.info(`Resource Stop [${ getters.storeName }]`, type, msg); // eslint-disable-line no-console
|
|
755
|
+
|
|
756
|
+
if (!type) {
|
|
757
|
+
console.error(`Resource Stop [${ getters.storeName }]. Received resource.stop with an empty resourceType, aborting`, msg); // eslint-disable-line no-console
|
|
758
|
+
|
|
759
|
+
return;
|
|
760
|
+
}
|
|
720
761
|
|
|
721
762
|
// If we're trying to watch this event, attempt to re-watch
|
|
722
763
|
if ( getters['schemaFor'](type) && getters['watchStarted'](obj) ) {
|
|
723
764
|
commit('setWatchStopped', obj);
|
|
724
|
-
|
|
725
|
-
// In summary, we need to re-watch but with a reliable `revision` (to avoid `too old` message kicking off a full re-fetch of all
|
|
726
|
-
// resources). To get a reliable `revision` go out and fetch the latest for that resource type, in theory our local cache should be
|
|
727
|
-
// up to date with that revision.
|
|
728
|
-
|
|
729
|
-
const revisionExisting = getters.nextResourceVersion(type, obj.id);
|
|
730
|
-
|
|
731
|
-
let revisionLatest;
|
|
732
|
-
|
|
733
|
-
if (revisionExisting) {
|
|
734
|
-
// Attempt to fetch the latest revision at the time the resource watch was stopped, in theory our local cache should be up to
|
|
735
|
-
// date with this
|
|
736
|
-
// Ideally we shouldn't need to fetch here and supply `0`, `-1` or `null` to start watching from the latest revision, however steve
|
|
737
|
-
// will send the current state of each resource via a `resource.created` event.
|
|
738
|
-
const opt = { limit: 1 };
|
|
739
|
-
|
|
740
|
-
opt.url = getters.urlFor(type, null, opt);
|
|
741
|
-
revisionLatest = dispatch('request', { opt, type } )
|
|
742
|
-
.then(res => res.revision)
|
|
743
|
-
.catch((err) => {
|
|
744
|
-
// For some reason we can't fetch a reasonable revision, so force a re-fetch
|
|
745
|
-
console.warn(`Resource error retrieving resourceVersion, forcing re-fetch`, type, ':', err); // eslint-disable-line no-console
|
|
746
|
-
dispatch('resyncWatch', msg);
|
|
747
|
-
throw err;
|
|
748
|
-
});
|
|
749
|
-
} else {
|
|
750
|
-
// Some v1 resource types don't have revisions (either at the collection or resource level), so we avoided making an API request
|
|
751
|
-
// for them
|
|
752
|
-
revisionLatest = Promise.resolve(null); // Null to ensure we don't go through `nextResourceVersion` again
|
|
753
|
-
}
|
|
754
|
-
|
|
755
|
-
setTimeout(() => {
|
|
756
|
-
// Delay a bit so that immediate start/error/stop causes
|
|
757
|
-
// only a slow infinite loop instead of a tight one.
|
|
758
|
-
revisionLatest.then(revision => dispatch('watch', { ...obj, revision }));
|
|
759
|
-
}, 5000);
|
|
765
|
+
dispatch('watch', obj);
|
|
760
766
|
}
|
|
761
767
|
},
|
|
762
768
|
|
|
763
769
|
'ws.resource.create'(ctx, msg) {
|
|
770
|
+
ctx.state.debugSocket && console.info(`Resource Create [${ ctx.getters.storeName }]`, msg.resourceType, msg); // eslint-disable-line no-console
|
|
764
771
|
queueChange(ctx, msg, true, 'Create');
|
|
765
772
|
},
|
|
766
773
|
|
|
@@ -811,6 +818,8 @@ const defaultActions = {
|
|
|
811
818
|
const data = msg.data;
|
|
812
819
|
const type = data.type;
|
|
813
820
|
|
|
821
|
+
ctx.state.debugSocket && console.info(`Resource Remove [${ ctx.getters.storeName }]`, type, msg); // eslint-disable-line no-console
|
|
822
|
+
|
|
814
823
|
if (type === SCHEMA) {
|
|
815
824
|
const worker = (this.$workers || {})[ctx.getters.storeName];
|
|
816
825
|
|
|
@@ -914,8 +923,8 @@ const defaultMutations = {
|
|
|
914
923
|
* Getters that cover cases 1 & 2 (see file description)
|
|
915
924
|
*/
|
|
916
925
|
const defaultGetters = {
|
|
917
|
-
|
|
918
|
-
return
|
|
926
|
+
inError: state => (obj) => {
|
|
927
|
+
return state.inError[keyForSubscribe(obj)];
|
|
919
928
|
},
|
|
920
929
|
|
|
921
930
|
watchStarted: state => (obj) => {
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import createWorker from './steve/worker/index.js';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Link the steve worker creator to the store
|
|
5
|
+
*
|
|
6
|
+
* This is done to allow disassociate (no import chain) access to the steve worker file.
|
|
7
|
+
* Without this third party plugins (in given scenarios / harvester) will fail to build
|
|
8
|
+
* due to missing web worker specific build config
|
|
9
|
+
*
|
|
10
|
+
* Note - When rancher/steve store is spun out in to a extension this also needs to move out
|
|
11
|
+
*/
|
|
12
|
+
export default function({ store }) {
|
|
13
|
+
store.steveCreateWorker = createWorker;
|
|
14
|
+
}
|
|
@@ -23,14 +23,14 @@ export default {
|
|
|
23
23
|
<div>
|
|
24
24
|
<template>
|
|
25
25
|
{{ t('promptRemove.attemptingToRemove', { type }) }} <span
|
|
26
|
-
v-html="resourceNames(names, plusMore, t)"
|
|
26
|
+
v-clean-html="resourceNames(names, plusMore, t)"
|
|
27
27
|
/>
|
|
28
28
|
</template>
|
|
29
29
|
<div
|
|
30
30
|
v-if="info"
|
|
31
31
|
class="text info mb-10 mt-20"
|
|
32
32
|
>
|
|
33
|
-
<span v-html="info" />
|
|
33
|
+
<span v-clean-html="info" />
|
|
34
34
|
</div>
|
|
35
35
|
<div
|
|
36
36
|
v-if="warning"
|
|
@@ -100,8 +100,8 @@ export default {
|
|
|
100
100
|
<template v-if="!canSeeProjectlessNamespaces">
|
|
101
101
|
<span class="delete-warning"> {{ t('promptRemove.willDeleteAssociatedNamespaces') }}</span> <br>
|
|
102
102
|
<div
|
|
103
|
+
v-clean-html="resourceNames(names, plusMore, t)"
|
|
103
104
|
class="mt-10"
|
|
104
|
-
v-html="resourceNames(names, plusMore, t)"
|
|
105
105
|
/>
|
|
106
106
|
</template>
|
|
107
107
|
</div>
|
|
@@ -114,7 +114,7 @@ export default {
|
|
|
114
114
|
:label="t('promptRemove.deleteAssociatedNamespaces')"
|
|
115
115
|
/>
|
|
116
116
|
<div class="mt-10 ml-20">
|
|
117
|
-
<span v-html="resourceNames(names, plusMore, t)" />
|
|
117
|
+
<span v-clean-html="resourceNames(names, plusMore, t)" />
|
|
118
118
|
</div>
|
|
119
119
|
</div>
|
|
120
120
|
</div>
|
|
@@ -23,14 +23,14 @@ export default {
|
|
|
23
23
|
<div>
|
|
24
24
|
<template>
|
|
25
25
|
{{ t('promptRemove.attemptingToRemove', { type }) }} <span
|
|
26
|
-
v-html="resourceNames(names, plusMore, t)"
|
|
26
|
+
v-clean-html="resourceNames(names, plusMore, t)"
|
|
27
27
|
/>
|
|
28
28
|
</template>
|
|
29
29
|
<div
|
|
30
30
|
v-if="info"
|
|
31
31
|
class="text info mb-10 mt-20"
|
|
32
32
|
>
|
|
33
|
-
<span v-html="info" />
|
|
33
|
+
<span v-clean-html="info" />
|
|
34
34
|
</div>
|
|
35
35
|
<div
|
|
36
36
|
v-if="warning"
|
package/promptRemove/pod.vue
CHANGED
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html lang="">
|
|
3
|
+
|
|
4
|
+
<head>
|
|
5
|
+
<meta charset="utf-8">
|
|
6
|
+
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
|
7
|
+
<meta name="viewport" content="width=device-width,initial-scale=1.0">
|
|
8
|
+
<link rel="shortcut icon" type="image/x-icon" href="/public/favicon.png">
|
|
9
|
+
<title>Rancher</title>
|
|
10
|
+
</head>
|
|
11
|
+
|
|
12
|
+
<body>
|
|
13
|
+
<div id="app">
|
|
14
|
+
<script>
|
|
15
|
+
(() => {
|
|
16
|
+
const isDark = document.cookie.includes('R_PCS=dark');
|
|
17
|
+
const color = isDark ? '#1b1c21' : '#FFF';
|
|
18
|
+
const style = document.createElement('style');
|
|
19
|
+
style.innerHTML = ':root { --loading-bg-color: ' + color + ';}';
|
|
20
|
+
document.getElementsByTagName('head')[0].prepend(style);
|
|
21
|
+
})();
|
|
22
|
+
</script>
|
|
23
|
+
<style>
|
|
24
|
+
.initial-load-spinner-container {
|
|
25
|
+
align-items: center;
|
|
26
|
+
background-color: var(--loading-bg-color);
|
|
27
|
+
display: flex;
|
|
28
|
+
justify-content: center;
|
|
29
|
+
height: 100vh;
|
|
30
|
+
left: 0;
|
|
31
|
+
position: absolute;
|
|
32
|
+
top: 0;
|
|
33
|
+
width: 100vw;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
.initial-load-spinner {
|
|
37
|
+
animation: initial-load-animate 1s infinite linear;
|
|
38
|
+
background-color: var(--loading-bg-color);
|
|
39
|
+
box-sizing: border-box;
|
|
40
|
+
border: 5px solid #008ACF;
|
|
41
|
+
border-radius: 50%;
|
|
42
|
+
border-top-color: #00B2E2;
|
|
43
|
+
display: inline-block;
|
|
44
|
+
height: 80px;
|
|
45
|
+
margin: 0 auto;
|
|
46
|
+
width: 80px;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
@keyframes initial-load-animate {
|
|
50
|
+
0% {
|
|
51
|
+
transform: rotate(0deg);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
100% {
|
|
55
|
+
transform: rotate(359deg);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
</style>
|
|
59
|
+
<div class="initial-load-spinner-container">
|
|
60
|
+
<i class="initial-load-spinner"></i>
|
|
61
|
+
</div>
|
|
62
|
+
</div>
|
|
63
|
+
</body>
|
|
64
|
+
|
|
65
|
+
</html>
|
|
@@ -1,10 +1,18 @@
|
|
|
1
1
|
import { mount } from '@vue/test-utils';
|
|
2
2
|
import { Banner } from './index';
|
|
3
|
+
import { cleanHtmlDirective } from '@shell/plugins/clean-html-directive'
|
|
3
4
|
|
|
4
5
|
describe('component: Banner', () => {
|
|
5
6
|
it('should display text based on label', () => {
|
|
6
7
|
const label = 'test';
|
|
7
|
-
const wrapper = mount(
|
|
8
|
+
const wrapper = mount(
|
|
9
|
+
Banner,
|
|
10
|
+
{
|
|
11
|
+
directives: {
|
|
12
|
+
cleanHtmlDirective
|
|
13
|
+
},
|
|
14
|
+
propsData: { label }
|
|
15
|
+
});
|
|
8
16
|
|
|
9
17
|
const element = wrapper.find('span').element;
|
|
10
18
|
|
package/scripts/build-pkg.sh
CHANGED