@rancher/shell 3.0.9-rc.3 → 3.0.9-rc.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/brand/suse/metadata.json +2 -1
- package/assets/translations/en-us.yaml +105 -5
- package/components/ActionMenuShell.vue +1 -1
- package/components/Inactivity.vue +2 -2
- package/components/Resource/Detail/Card/ExtrasCard.vue +49 -15
- package/components/Resource/Detail/Card/__tests__/ExtrasCard.test.ts +111 -0
- package/components/Resource/Detail/Masthead/__tests__/index.test.ts +0 -17
- package/components/Resource/Detail/Masthead/index.vue +11 -4
- package/components/Resource/Detail/Metadata/IdentifyingInformation/index.vue +3 -1
- package/components/Resource/Detail/Metadata/index.vue +1 -1
- package/components/Resource/Detail/ResourceRow.vue +1 -1
- package/components/ResourceDetail/Masthead/latest.vue +12 -2
- package/components/ResourceList/index.vue +9 -0
- package/components/ResourceTable.vue +38 -4
- package/components/Tabbed/Tab.vue +4 -0
- package/components/Tabbed/index.vue +4 -1
- package/components/__tests__/ProjectRow.test.ts +60 -0
- package/components/form/ChangePassword.vue +41 -35
- package/components/form/ResourceQuota/Project.vue +42 -1
- package/components/form/ResourceQuota/ProjectRow.vue +71 -4
- package/components/form/ResourceQuota/__tests__/Project.test.ts +63 -0
- package/components/form/SelectOrCreateAuthSecret.vue +6 -1
- package/components/form/__tests__/SelectOrCreateAuthSecret.test.ts +35 -0
- package/components/formatter/KubeconfigClusters.vue +74 -0
- package/components/formatter/MachineSummaryGraph.vue +10 -2
- package/components/formatter/__tests__/KubeconfigClusters.test.ts +125 -0
- package/components/nav/TopLevelMenu.helper.ts +50 -2
- package/components/nav/TopLevelMenu.vue +14 -0
- package/components/nav/Type.vue +5 -0
- package/components/nav/__tests__/TopLevelMenu.test.ts +3 -3
- package/components/nav/__tests__/Type.test.ts +6 -4
- package/config/product/explorer.js +4 -3
- package/config/product/manager.js +47 -3
- package/config/router/navigation-guards/authentication.js +8 -9
- package/config/router/routes.js +4 -1
- package/config/types.js +10 -2
- package/detail/auditlog.cattle.io.auditpolicy.vue +19 -0
- package/detail/management.cattle.io.user.vue +1 -2
- package/detail/node.vue +0 -1
- package/detail/provisioning.cattle.io.cluster.vue +2 -1
- package/dialog/ChangePasswordDialog.vue +8 -0
- package/dialog/GenericPrompt.vue +20 -3
- package/dialog/ScaleMachineDownDialog.vue +65 -15
- package/dialog/SearchDialog.vue +10 -2
- package/dialog/__tests__/ScaleMachineDownDialog.test.ts +184 -0
- package/edit/__tests__/fleet.cattle.io.gitrepo.test.ts +89 -0
- package/edit/__tests__/management.cattle.io.project.test.js +56 -1
- package/edit/auditlog.cattle.io.auditpolicy/AdditionalRedactions.vue +114 -0
- package/edit/auditlog.cattle.io.auditpolicy/Filters.vue +119 -0
- package/edit/auditlog.cattle.io.auditpolicy/General.vue +180 -0
- package/edit/auditlog.cattle.io.auditpolicy/__tests__/AdditionalRedactions.test.ts +327 -0
- package/edit/auditlog.cattle.io.auditpolicy/__tests__/Filters.test.ts +449 -0
- package/edit/auditlog.cattle.io.auditpolicy/__tests__/General.test.ts +472 -0
- package/edit/auditlog.cattle.io.auditpolicy/__tests__/__snapshots__/AdditionalRedactions.test.ts.snap +27 -0
- package/edit/auditlog.cattle.io.auditpolicy/__tests__/__snapshots__/Filters.test.ts.snap +39 -0
- package/edit/auditlog.cattle.io.auditpolicy/__tests__/__snapshots__/General.test.ts.snap +174 -0
- package/edit/auditlog.cattle.io.auditpolicy/__tests__/__snapshots__/index.test.ts.snap +29 -0
- package/edit/auditlog.cattle.io.auditpolicy/__tests__/index.test.ts +215 -0
- package/edit/auditlog.cattle.io.auditpolicy/index.vue +104 -0
- package/edit/auditlog.cattle.io.auditpolicy/types.ts +28 -0
- package/edit/fleet.cattle.io.gitrepo.vue +16 -1
- package/edit/management.cattle.io.project.vue +8 -2
- package/edit/management.cattle.io.user.vue +29 -34
- package/edit/provisioning.cattle.io.cluster/__tests__/rke2.test.ts +178 -0
- package/edit/provisioning.cattle.io.cluster/rke2.vue +22 -2
- package/edit/provisioning.cattle.io.cluster/shared.ts +4 -0
- package/edit/provisioning.cattle.io.cluster/tabs/Basics.vue +1 -0
- package/edit/provisioning.cattle.io.cluster/tabs/etcd/S3Config.vue +57 -2
- package/edit/provisioning.cattle.io.cluster/tabs/etcd/__tests__/S3Config.test.ts +109 -0
- package/edit/provisioning.cattle.io.cluster/tabs/etcd/index.vue +1 -0
- package/list/auditlog.cattle.io.auditpolicy.vue +63 -0
- package/list/ext.cattle.io.kubeconfig.vue +118 -0
- package/list/group.principal.vue +11 -15
- package/list/management.cattle.io.user.vue +11 -21
- package/machine-config/azure.vue +14 -0
- package/mixins/__tests__/chart.test.ts +147 -0
- package/mixins/browser-tab-visibility.js +5 -4
- package/mixins/chart.js +10 -8
- package/mixins/fetch.client.js +6 -0
- package/models/__tests__/auditlog.cattle.io.auditpolicy.test.ts +117 -0
- package/models/__tests__/ext.cattle.io.kubeconfig.test.ts +364 -0
- package/models/__tests__/secret.test.ts +55 -0
- package/models/__tests__/workload.test.ts +49 -6
- package/models/auditlog.cattle.io.auditpolicy.js +46 -0
- package/models/cluster.x-k8s.io.machine.js +1 -1
- package/models/cluster.x-k8s.io.machinedeployment.js +5 -5
- package/models/event.js +5 -0
- package/models/ext.cattle.io.groupmembershiprefreshrequest.js +15 -0
- package/models/ext.cattle.io.kubeconfig.ts +97 -0
- package/models/ext.cattle.io.passwordchangerequest.js +15 -0
- package/models/ext.cattle.io.selfuser.js +15 -0
- package/models/fleet-application.js +17 -7
- package/models/management.cattle.io.user.js +28 -31
- package/models/schema.js +18 -0
- package/models/secret.js +28 -25
- package/models/steve-schema.ts +39 -2
- package/models/workload.js +3 -2
- package/package.json +2 -2
- package/pages/about.vue +3 -2
- package/pages/account/index.vue +23 -16
- package/pages/auth/login.vue +15 -8
- package/pages/auth/setup.vue +52 -15
- package/pages/c/_cluster/apps/charts/AppChartCardFooter.vue +38 -14
- package/pages/c/_cluster/apps/charts/index.vue +1 -0
- package/pages/home.vue +9 -3
- package/plugins/dashboard-store/__tests__/resource-class.test.ts +1 -3
- package/plugins/dashboard-store/actions.js +7 -0
- package/plugins/dashboard-store/getters.js +23 -1
- package/plugins/dashboard-store/index.js +3 -2
- package/plugins/dashboard-store/mutations.js +4 -0
- package/plugins/dashboard-store/resource-class.js +12 -5
- package/plugins/steve/__tests__/steve-class.test.ts +167 -0
- package/plugins/steve/schema.d.ts +5 -0
- package/plugins/steve/steve-class.js +19 -0
- package/plugins/steve/steve-pagination-utils.ts +2 -1
- package/rancher-components/RcItemCard/RcItemCard.test.ts +4 -2
- package/rancher-components/RcItemCard/RcItemCard.vue +27 -10
- package/store/auth.js +57 -19
- package/store/notifications.ts +1 -1
- package/store/type-map.js +12 -1
- package/types/shell/index.d.ts +24 -15
- package/types/store/dashboard-store.types.ts +7 -0
- package/utils/__tests__/chart.test.ts +96 -0
- package/utils/__tests__/version.test.ts +1 -19
- package/utils/chart.js +64 -0
- package/utils/pagination-wrapper.ts +11 -3
- package/utils/version.js +5 -17
- package/vue.config.js +26 -13
|
@@ -163,6 +163,9 @@ generic:
|
|
|
163
163
|
externalIps: External IPs
|
|
164
164
|
internalIps: Internal IPs
|
|
165
165
|
opensInNewTab: Opens in a new tab
|
|
166
|
+
autogeneratedCreated:
|
|
167
|
+
title: "{resource} created"
|
|
168
|
+
message: "{id} has been created."
|
|
166
169
|
|
|
167
170
|
tabs:
|
|
168
171
|
addItem: Add a new tab item
|
|
@@ -307,6 +310,7 @@ nav:
|
|
|
307
310
|
clusterNotFound: Cluster { clusterId } not found
|
|
308
311
|
productNotFound: Product { productNotFound } not found
|
|
309
312
|
resourceNotFound: Resource type { resource } not found
|
|
313
|
+
resourceListNotListable: Resource type { resource } cannot be listed
|
|
310
314
|
resourceListNotFound: Resource type { resource } not found, unable to display list
|
|
311
315
|
resourceIdNotFound: Resource { resource } with id { fqid } not found, unable to display resource details
|
|
312
316
|
reload: Reload
|
|
@@ -1183,7 +1187,7 @@ catalog:
|
|
|
1183
1187
|
subHeaderItem:
|
|
1184
1188
|
missingVersionDate: Last updated date is not available for this chart
|
|
1185
1189
|
footerItem:
|
|
1186
|
-
ariaLabel: Apply filter
|
|
1190
|
+
ariaLabel: 'Apply {filter} filter'
|
|
1187
1191
|
statusFilterCautions:
|
|
1188
1192
|
installation: Installation status cannot be determined with 100% accuracy
|
|
1189
1193
|
upgradeable: Upgradeable status cannot be determined with 100% accuracy
|
|
@@ -1447,6 +1451,8 @@ changePassword:
|
|
|
1447
1451
|
failedToChange: Failed to change password
|
|
1448
1452
|
failedDeleteKey: Failed to delete key
|
|
1449
1453
|
failedDeleteKeys: Failed to delete keys
|
|
1454
|
+
cannotChange: This user does not have permissions to change their password
|
|
1455
|
+
cannotFetchSelf: This user does not have permissions to get their user information
|
|
1450
1456
|
|
|
1451
1457
|
chartHeading:
|
|
1452
1458
|
overview: Overview
|
|
@@ -1859,7 +1865,7 @@ cluster:
|
|
|
1859
1865
|
acceleratedNetworking:
|
|
1860
1866
|
label: Accelerated Networking
|
|
1861
1867
|
availabilitySet:
|
|
1862
|
-
label: Availability Set
|
|
1868
|
+
label: Availability Set
|
|
1863
1869
|
description: Availability sets are used to protect applications from hardware failures within an Azure data center.
|
|
1864
1870
|
availabilityZone:
|
|
1865
1871
|
label: Availability Zone
|
|
@@ -1884,6 +1890,7 @@ cluster:
|
|
|
1884
1890
|
label: Location
|
|
1885
1891
|
managedDisks:
|
|
1886
1892
|
label: Use Managed Disks
|
|
1893
|
+
deprecationWarning: 'Azure is retiring unmanaged disk support on March 31, 2026. After this date, VMs using unmanaged disks will be stopped and deallocated. Enable "Use Managed Disks" to avoid service disruption.'
|
|
1887
1894
|
managedDisksSize:
|
|
1888
1895
|
label: Managed Disk Size
|
|
1889
1896
|
nsg:
|
|
@@ -2543,7 +2550,7 @@ cluster:
|
|
|
2543
2550
|
snapshotScheduleCron:
|
|
2544
2551
|
label: Cron Schedule
|
|
2545
2552
|
snapshotRetention:
|
|
2546
|
-
label:
|
|
2553
|
+
label: Local snapshot retention count
|
|
2547
2554
|
tooltip: Each backup records 1 snapshot per etcd node. If you specify 3 snapshots and you have 3 etcd nodes you will only retain 1 full backup.
|
|
2548
2555
|
exportMetric:
|
|
2549
2556
|
label: Metrics
|
|
@@ -2552,6 +2559,13 @@ cluster:
|
|
|
2552
2559
|
s3backups:
|
|
2553
2560
|
label: Save Backups to S3
|
|
2554
2561
|
s3config:
|
|
2562
|
+
snapshotRetention:
|
|
2563
|
+
title: S3 Snapshot Retention
|
|
2564
|
+
label: S3 Snapshot Retention Count
|
|
2565
|
+
options:
|
|
2566
|
+
manual: Set manually
|
|
2567
|
+
localDefined: Same as local ({count} Snaphots)
|
|
2568
|
+
localUndefined: Same as local
|
|
2555
2569
|
bucket:
|
|
2556
2570
|
label: Bucket
|
|
2557
2571
|
folder:
|
|
@@ -3105,6 +3119,7 @@ fleet:
|
|
|
3105
3119
|
label: Authentication
|
|
3106
3120
|
git: Git Authentication
|
|
3107
3121
|
helm: Helm Authentication
|
|
3122
|
+
githubdotcomPasswordBanner: 'GitHub no longer supports password authentication for repositories. Please enter a personal access token with the required permissions instead of your GitHub password.'
|
|
3108
3123
|
caBundle:
|
|
3109
3124
|
label: Certificates
|
|
3110
3125
|
placeholder: "Paste in one or more certificates, starting with -----BEGIN CERTIFICATE----"
|
|
@@ -3629,6 +3644,71 @@ import:
|
|
|
3629
3644
|
other {# Resources}
|
|
3630
3645
|
}
|
|
3631
3646
|
|
|
3647
|
+
auditPolicy:
|
|
3648
|
+
active: Active
|
|
3649
|
+
inactive: Inactive
|
|
3650
|
+
reasons:
|
|
3651
|
+
PolicyNotYetActivated: Not yet activated
|
|
3652
|
+
PolicyIsActive: Active
|
|
3653
|
+
PolicyIsInvalid: Invalid
|
|
3654
|
+
PolicyWasDisabled: Disabled
|
|
3655
|
+
general:
|
|
3656
|
+
title: General
|
|
3657
|
+
enabled:
|
|
3658
|
+
label: Enabled
|
|
3659
|
+
title: Enabled
|
|
3660
|
+
checkbox: Enables this audit policy
|
|
3661
|
+
verbosity:
|
|
3662
|
+
label: Log Verbosity
|
|
3663
|
+
title: Log Verbosity
|
|
3664
|
+
banner: Audit Log Verbosity and install time Audit Log settings are additive.
|
|
3665
|
+
level:
|
|
3666
|
+
0: 0 - Log request and response metadata
|
|
3667
|
+
1: 1 - Log request and response headers
|
|
3668
|
+
2: 2 - Log request body
|
|
3669
|
+
3: 3 - Log response body
|
|
3670
|
+
title: Log Levels
|
|
3671
|
+
label: Level
|
|
3672
|
+
tooltip: Each log level is cumulative, higher log levels include the data from lower levels. Each log entry contains both request and response information.
|
|
3673
|
+
requestResponse:
|
|
3674
|
+
tooltip: Override the Log Level and explicitly include Headers / Body
|
|
3675
|
+
request:
|
|
3676
|
+
title: Request
|
|
3677
|
+
requestHeaders: Request Headers
|
|
3678
|
+
requestBody: Request Body
|
|
3679
|
+
response:
|
|
3680
|
+
title: Response
|
|
3681
|
+
responseHeaders: Response Headers
|
|
3682
|
+
responseBody: Response Body
|
|
3683
|
+
filters:
|
|
3684
|
+
add: Add Filter
|
|
3685
|
+
title: Filters
|
|
3686
|
+
action:
|
|
3687
|
+
title: Action
|
|
3688
|
+
label: Action
|
|
3689
|
+
allow: Allow
|
|
3690
|
+
deny: Deny
|
|
3691
|
+
placeholder: Allow/Deny
|
|
3692
|
+
requestURI:
|
|
3693
|
+
title: Request URI
|
|
3694
|
+
label: Request URI
|
|
3695
|
+
placeholder: e.g. /foo/.*
|
|
3696
|
+
additionalRedactions:
|
|
3697
|
+
title: Additional Redactions
|
|
3698
|
+
headers:
|
|
3699
|
+
title: Headers
|
|
3700
|
+
label: Headers
|
|
3701
|
+
placeholder: e.g. Cache.*
|
|
3702
|
+
add: Add Header
|
|
3703
|
+
paths:
|
|
3704
|
+
title: Paths
|
|
3705
|
+
label: Paths
|
|
3706
|
+
tooltip: Paths redacts information from request and response bodies based on json path expressions
|
|
3707
|
+
placeholder: e.g. $.gitCommit
|
|
3708
|
+
add: Add Path
|
|
3709
|
+
error:
|
|
3710
|
+
enableOrDisable: "{flag, select, enable {Error when enabling - {id}} disable {Error when disabling - {id}} other {Error - {id}}}"
|
|
3711
|
+
|
|
3632
3712
|
ingress:
|
|
3633
3713
|
description: Ingresses route incoming traffic from the internet to Services within the cluster based on the hostname and path specified in the request. You can expose multiple Services on the same external IP address and port.
|
|
3634
3714
|
certificates:
|
|
@@ -5707,7 +5787,11 @@ promptScaleMachineDown:
|
|
|
5707
5787
|
attemptingToRemove: "You are attempting to delete {count} {type}"
|
|
5708
5788
|
retainedMachine1: At least one Machine must exist for roles Control Plane and Etcd.
|
|
5709
5789
|
retainedMachine2: <b>{ name }</b> will remain
|
|
5710
|
-
|
|
5790
|
+
scaling: |-
|
|
5791
|
+
{count, plural,
|
|
5792
|
+
=1 {This machine pool is still reconciling. A different node may be deleted instead of the one you selected. It’s best to wait until reconciliation finishes.<br> Do you still want to mark this node for deletion?}
|
|
5793
|
+
other {At least one of these machine pools is still reconciling. Different nodes may be deleted instead of the ones you selected. It’s best to wait until reconciliation finishes.<br> Do you still want to mark these nodes for deletion?}
|
|
5794
|
+
}
|
|
5711
5795
|
promptSlo:
|
|
5712
5796
|
title: "Log out"
|
|
5713
5797
|
text: "Log out of only Rancher, or all {name} applications."
|
|
@@ -5925,6 +6009,9 @@ rbac:
|
|
|
5925
6009
|
label: Login Access
|
|
5926
6010
|
clustertemplaterevisions-create:
|
|
5927
6011
|
label: Create RKE Template Revisions
|
|
6012
|
+
proxy-endpoints-manage:
|
|
6013
|
+
label: Manage Rancher Proxy
|
|
6014
|
+
description: Allows the user to manage settings for proxying HTTP requests via Rancher
|
|
5928
6015
|
errors:
|
|
5929
6016
|
escalation: You cannot assign Global Permissions that are higher than your own. Please verify the permissions you are attempting to assign.
|
|
5930
6017
|
|
|
@@ -6171,6 +6258,7 @@ selectOrCreateAuthSecret:
|
|
|
6171
6258
|
basic:
|
|
6172
6259
|
username: Username
|
|
6173
6260
|
password: Password
|
|
6261
|
+
passwordPersonalAccessToken: Password/Personal Access Token
|
|
6174
6262
|
rke:
|
|
6175
6263
|
info: "An RKE Auth Config secret contains the username and password concatenated and base64 encoded into the secret's 'auth' key"
|
|
6176
6264
|
namespaceGroup: "Namespace: {name}"
|
|
@@ -6325,6 +6413,7 @@ setup:
|
|
|
6325
6413
|
useRandom: Use a randomly generated password
|
|
6326
6414
|
copyRandom: Copy random password to clipboard
|
|
6327
6415
|
welcome: Welcome to {vendor}!
|
|
6416
|
+
setup: Setup
|
|
6328
6417
|
|
|
6329
6418
|
sortableTable:
|
|
6330
6419
|
ariaLabel:
|
|
@@ -6888,6 +6977,7 @@ tableHeaders:
|
|
|
6888
6977
|
targetPort: Target
|
|
6889
6978
|
template: Template
|
|
6890
6979
|
totalSnapshotQuota: Total Snapshot Quota
|
|
6980
|
+
ttl: TTL
|
|
6891
6981
|
type: Type
|
|
6892
6982
|
updated: Updated
|
|
6893
6983
|
up-to-date: Up To Date
|
|
@@ -7873,6 +7963,7 @@ typeDescription:
|
|
|
7873
7963
|
logging.banzaicloud.io.output: An output defines which logging providers that logs can be sent to. The output needs to be in the same namespace as the flow that is using it.
|
|
7874
7964
|
group.principal: Assigning global roles to a group only works with external auth providers that support groups. Local authorization does not support groups.
|
|
7875
7965
|
management.cattle.io.oidcclient: Here you can add applications to Rancher's single sign-on identity provider
|
|
7966
|
+
auditlog.cattle.io.auditpolicy: Define rules that determine which Rancher API events are logged and the level of detail they contain.
|
|
7876
7967
|
|
|
7877
7968
|
typeLabel:
|
|
7878
7969
|
management.cattle.io.oidcclient: |-
|
|
@@ -8025,6 +8116,11 @@ typeLabel:
|
|
|
8025
8116
|
one { Resource Quota }
|
|
8026
8117
|
other { Resource Quotas }
|
|
8027
8118
|
}
|
|
8119
|
+
auditlog.cattle.io.auditpolicy: |-
|
|
8120
|
+
{count, plural,
|
|
8121
|
+
one { Audit Log Policy }
|
|
8122
|
+
other { Audit Log Policies }
|
|
8123
|
+
}
|
|
8028
8124
|
# pruh-mee-thee-eyes https://www.prometheus.io/docs/introduction/faq/#what-is-the-plural-of-prometheus
|
|
8029
8125
|
monitoring.coreos.com.prometheus: |-
|
|
8030
8126
|
{count, plural,
|
|
@@ -9174,7 +9270,7 @@ component:
|
|
|
9174
9270
|
events: Events
|
|
9175
9271
|
extrasCard:
|
|
9176
9272
|
title: Extras
|
|
9177
|
-
message: 'Consider installing additional <
|
|
9273
|
+
message: 'Consider installing additional <extensionsLink>extensions</extensionsLink> and / or <clusterToolsLink>cluster tools</clusterToolsLink> to enrich your Rancher experience.'
|
|
9178
9274
|
scaler:
|
|
9179
9275
|
ariaLabel:
|
|
9180
9276
|
increase: Increase {resourceName}
|
|
@@ -9308,3 +9404,7 @@ autoscaler:
|
|
|
9308
9404
|
unavailable: Unavailable
|
|
9309
9405
|
tab:
|
|
9310
9406
|
title: Autoscaler
|
|
9407
|
+
|
|
9408
|
+
ext.cattle.io.kubeconfig:
|
|
9409
|
+
deleted: "{name} (deleted)"
|
|
9410
|
+
moreClusterCount: " + {remainingCount} more"
|
|
@@ -97,7 +97,7 @@ const menuOptions = () => {
|
|
|
97
97
|
<template>
|
|
98
98
|
<rc-dropdown-menu
|
|
99
99
|
:button-variant="buttonVariant || 'link'"
|
|
100
|
-
:button-size="buttonSize || '
|
|
100
|
+
:button-size="buttonSize || 'medium'"
|
|
101
101
|
:button-aria-label="buttonAriaLabel"
|
|
102
102
|
:dropdown-aria-label="dropdownAriaLabel"
|
|
103
103
|
:options="menuOptions()"
|
|
@@ -120,10 +120,10 @@ export default {
|
|
|
120
120
|
|
|
121
121
|
methods: {
|
|
122
122
|
async initializeInactivityData() {
|
|
123
|
-
const
|
|
123
|
+
const canGetUserAct = this.$store.getters[`management/canGet`](EXT.USER_ACTIVITY);
|
|
124
124
|
const canListTokens = this.$store.getters[`rancher/canList`](NORMAN.TOKEN);
|
|
125
125
|
|
|
126
|
-
if (
|
|
126
|
+
if (canGetUserAct && canListTokens) {
|
|
127
127
|
const tokens = await this.$store.dispatch('rancher/findAll', { type: NORMAN.TOKEN, opt: { watch: false } });
|
|
128
128
|
|
|
129
129
|
this.tokens = tokens;
|
|
@@ -3,37 +3,71 @@ import Card from '@shell/components/Resource/Detail/Card/index.vue';
|
|
|
3
3
|
import { useI18n } from '@shell/composables/useI18n';
|
|
4
4
|
import { useStore } from 'vuex';
|
|
5
5
|
import { BLANK_CLUSTER } from '@shell/store/store-types';
|
|
6
|
+
import { isAdminUser } from '@shell/store/type-map';
|
|
7
|
+
import { DOCS_BASE } from '@shell/config/private-label';
|
|
6
8
|
</script>
|
|
7
9
|
<script setup lang="ts">
|
|
8
|
-
import
|
|
10
|
+
import RichTranslation from '@shell/components/RichTranslation.vue';
|
|
11
|
+
import { computed } from 'vue';
|
|
9
12
|
|
|
10
13
|
const store = useStore();
|
|
11
|
-
const router = useRouter();
|
|
12
14
|
const i18n = useI18n(store);
|
|
15
|
+
const isAdmin = computed(() => isAdminUser(store.getters));
|
|
13
16
|
|
|
14
|
-
const
|
|
15
|
-
|
|
16
|
-
params: { cluster: BLANK_CLUSTER }
|
|
17
|
-
}).href;
|
|
17
|
+
const extensionsRoute = { name: 'c-cluster-uiplugins', params: { cluster: BLANK_CLUSTER } };
|
|
18
|
+
const extensionsDocsUrl = `${ DOCS_BASE }/integrations-in-rancher/rancher-extensions`;
|
|
18
19
|
|
|
19
|
-
const
|
|
20
|
-
|
|
21
|
-
params: { cluster: BLANK_CLUSTER }
|
|
22
|
-
}).href;
|
|
20
|
+
const clusterToolsRoute = { name: 'c-cluster-explorer-tools' };
|
|
21
|
+
const clusterToolsDocsUrl = `${ DOCS_BASE }/reference-guides/rancher-cluster-tools`;
|
|
23
22
|
</script>
|
|
24
23
|
|
|
25
24
|
<template>
|
|
26
25
|
<Card :title="i18n.t('component.resource.detail.card.extrasCard.title')">
|
|
27
|
-
<p
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
26
|
+
<p class="message text-deemphasized">
|
|
27
|
+
<RichTranslation k="component.resource.detail.card.extrasCard.message">
|
|
28
|
+
<template #extensionsLink="{ content }">
|
|
29
|
+
<router-link
|
|
30
|
+
v-if="isAdmin"
|
|
31
|
+
class="secondary text-deemphasized"
|
|
32
|
+
:to="extensionsRoute"
|
|
33
|
+
>
|
|
34
|
+
{{ content }}
|
|
35
|
+
</router-link>
|
|
36
|
+
<a
|
|
37
|
+
v-else
|
|
38
|
+
class="secondary text-deemphasized"
|
|
39
|
+
:href="extensionsDocsUrl"
|
|
40
|
+
target="_blank"
|
|
41
|
+
>
|
|
42
|
+
{{ content }}
|
|
43
|
+
</a>
|
|
44
|
+
</template>
|
|
45
|
+
<template #clusterToolsLink="{ content }">
|
|
46
|
+
<router-link
|
|
47
|
+
v-if="isAdmin"
|
|
48
|
+
class="secondary-text-link"
|
|
49
|
+
:to="clusterToolsRoute"
|
|
50
|
+
>
|
|
51
|
+
{{ content }}
|
|
52
|
+
</router-link>
|
|
53
|
+
<a
|
|
54
|
+
v-else
|
|
55
|
+
class="secondary-text-link"
|
|
56
|
+
:href="clusterToolsDocsUrl"
|
|
57
|
+
target="_blank"
|
|
58
|
+
>
|
|
59
|
+
{{ content }}
|
|
60
|
+
</a>
|
|
61
|
+
</template>
|
|
62
|
+
</RichTranslation>
|
|
63
|
+
</p>
|
|
31
64
|
</Card>
|
|
32
65
|
</template>
|
|
33
66
|
|
|
34
67
|
<style lang="scss" scoped>
|
|
35
68
|
.message {
|
|
36
69
|
margin: 0;
|
|
37
|
-
|
|
70
|
+
margin-top: -2px;
|
|
71
|
+
line-height: 20px;
|
|
38
72
|
}
|
|
39
73
|
</style>
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
import { mount } from '@vue/test-utils';
|
|
2
|
+
import { createStore } from 'vuex';
|
|
3
|
+
import ExtrasCard from '@shell/components/Resource/Detail/Card/ExtrasCard.vue';
|
|
4
|
+
import Card from '@shell/components/Resource/Detail/Card/index.vue';
|
|
5
|
+
import RichTranslation from '@shell/components/RichTranslation.vue';
|
|
6
|
+
|
|
7
|
+
const TRANSLATION_KEY = 'component.resource.detail.card.extrasCard.message';
|
|
8
|
+
const TRANSLATION_VALUE = 'Consider installing additional <extensionsLink>extensions</extensionsLink> and / or <clusterToolsLink>cluster tools</clusterToolsLink> to enrich your Rancher experience.';
|
|
9
|
+
|
|
10
|
+
jest.mock('@shell/store/type-map', () => ({ isAdminUser: jest.fn() }));
|
|
11
|
+
jest.mock('@shell/config/private-label', () => ({ DOCS_BASE: 'https://docs.example.com' }));
|
|
12
|
+
|
|
13
|
+
const { isAdminUser } = require('@shell/store/type-map');
|
|
14
|
+
|
|
15
|
+
function createMockStore() {
|
|
16
|
+
return createStore({
|
|
17
|
+
getters: {
|
|
18
|
+
'i18n/t': () => (key: string) => {
|
|
19
|
+
if (key === TRANSLATION_KEY) {
|
|
20
|
+
return TRANSLATION_VALUE;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
return key;
|
|
24
|
+
},
|
|
25
|
+
},
|
|
26
|
+
});
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
function mountExtrasCard({ admin = false } = {}) {
|
|
30
|
+
isAdminUser.mockReturnValue(admin);
|
|
31
|
+
|
|
32
|
+
const store = createMockStore();
|
|
33
|
+
|
|
34
|
+
return mount(ExtrasCard, {
|
|
35
|
+
global: {
|
|
36
|
+
plugins: [store],
|
|
37
|
+
stubs: { 'router-link': { template: '<a :href="JSON.stringify(to)" :class="$attrs.class"><slot /></a>', props: ['to'] } },
|
|
38
|
+
},
|
|
39
|
+
});
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
describe('component: ExtrasCard', () => {
|
|
43
|
+
it('should render the Card component with the correct title', () => {
|
|
44
|
+
const wrapper = mountExtrasCard();
|
|
45
|
+
const card = wrapper.findComponent(Card);
|
|
46
|
+
|
|
47
|
+
expect(card.exists()).toBe(true);
|
|
48
|
+
expect(card.props('title')).toStrictEqual('component.resource.detail.card.extrasCard.title');
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
it('should render the RichTranslation component with the correct key', () => {
|
|
52
|
+
const wrapper = mountExtrasCard();
|
|
53
|
+
const richTranslation = wrapper.findComponent(RichTranslation);
|
|
54
|
+
|
|
55
|
+
expect(richTranslation.exists()).toBe(true);
|
|
56
|
+
expect(richTranslation.props('k')).toStrictEqual(TRANSLATION_KEY);
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
describe('when user is admin', () => {
|
|
60
|
+
it('should render router-link for extensions', () => {
|
|
61
|
+
const wrapper = mountExtrasCard({ admin: true });
|
|
62
|
+
const links = wrapper.findAll('a');
|
|
63
|
+
const extensionsLink = links.find((l) => l.text() === 'extensions');
|
|
64
|
+
|
|
65
|
+
expect(extensionsLink).toBeDefined();
|
|
66
|
+
expect(extensionsLink!.classes()).toContain('secondary');
|
|
67
|
+
expect(extensionsLink!.classes()).toContain('text-deemphasized');
|
|
68
|
+
expect(extensionsLink!.attributes('href')).toContain('c-cluster-uiplugins');
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
it('should render router-link for cluster tools', () => {
|
|
72
|
+
const wrapper = mountExtrasCard({ admin: true });
|
|
73
|
+
const links = wrapper.findAll('a');
|
|
74
|
+
const clusterToolsLink = links.find((l) => l.text() === 'cluster tools');
|
|
75
|
+
|
|
76
|
+
expect(clusterToolsLink).toBeDefined();
|
|
77
|
+
expect(clusterToolsLink!.classes()).toContain('secondary-text-link');
|
|
78
|
+
expect(clusterToolsLink!.attributes('href')).toContain('c-cluster-explorer-tools');
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
it('should not render external anchor tags', () => {
|
|
82
|
+
const wrapper = mountExtrasCard({ admin: true });
|
|
83
|
+
const anchors = wrapper.findAll('a[target="_blank"]');
|
|
84
|
+
|
|
85
|
+
expect(anchors).toHaveLength(0);
|
|
86
|
+
});
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
describe('when user is not admin', () => {
|
|
90
|
+
it('should render an external link for extensions', () => {
|
|
91
|
+
const wrapper = mountExtrasCard({ admin: false });
|
|
92
|
+
const links = wrapper.findAll('a[target="_blank"]');
|
|
93
|
+
const extensionsLink = links.find((l) => l.text() === 'extensions');
|
|
94
|
+
|
|
95
|
+
expect(extensionsLink).toBeDefined();
|
|
96
|
+
expect(extensionsLink!.attributes('href')).toStrictEqual('https://docs.example.com/integrations-in-rancher/rancher-extensions');
|
|
97
|
+
expect(extensionsLink!.classes()).toContain('secondary');
|
|
98
|
+
expect(extensionsLink!.classes()).toContain('text-deemphasized');
|
|
99
|
+
});
|
|
100
|
+
|
|
101
|
+
it('should render an external link for cluster tools', () => {
|
|
102
|
+
const wrapper = mountExtrasCard({ admin: false });
|
|
103
|
+
const links = wrapper.findAll('a[target="_blank"]');
|
|
104
|
+
const clusterToolsLink = links.find((l) => l.text() === 'cluster tools');
|
|
105
|
+
|
|
106
|
+
expect(clusterToolsLink).toBeDefined();
|
|
107
|
+
expect(clusterToolsLink!.attributes('href')).toStrictEqual('https://docs.example.com/reference-guides/rancher-cluster-tools');
|
|
108
|
+
expect(clusterToolsLink!.classes()).toContain('secondary-text-link');
|
|
109
|
+
});
|
|
110
|
+
});
|
|
111
|
+
});
|
|
@@ -50,21 +50,4 @@ describe('component: Masthead/index', () => {
|
|
|
50
50
|
|
|
51
51
|
expect(cardsComponent.props('resource')).toStrictEqual(mockResource);
|
|
52
52
|
});
|
|
53
|
-
|
|
54
|
-
it('should render Cards with mb-20 class', () => {
|
|
55
|
-
const wrapper = mount(Masthead, {
|
|
56
|
-
props: defaultProps,
|
|
57
|
-
global: {
|
|
58
|
-
stubs: {
|
|
59
|
-
TitleBar: true,
|
|
60
|
-
Metadata: true,
|
|
61
|
-
Cards: true
|
|
62
|
-
}
|
|
63
|
-
}
|
|
64
|
-
});
|
|
65
|
-
|
|
66
|
-
const cardsComponent = wrapper.findComponent(Cards);
|
|
67
|
-
|
|
68
|
-
expect(cardsComponent.classes()).toContain('mb-20');
|
|
69
|
-
});
|
|
70
53
|
});
|
|
@@ -24,10 +24,11 @@ const props = defineProps<MastheadProps>();
|
|
|
24
24
|
</template>
|
|
25
25
|
</TitleBar>
|
|
26
26
|
<Metadata
|
|
27
|
+
class="metadata-section"
|
|
27
28
|
v-bind="props.metadataProps"
|
|
28
29
|
/>
|
|
29
30
|
<Cards
|
|
30
|
-
class="
|
|
31
|
+
class="cards-section"
|
|
31
32
|
:resource="props.titleBarProps.resource"
|
|
32
33
|
/>
|
|
33
34
|
</div>
|
|
@@ -35,8 +36,14 @@ const props = defineProps<MastheadProps>();
|
|
|
35
36
|
|
|
36
37
|
<style lang='scss' scoped>
|
|
37
38
|
.masthead {
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
39
|
+
:deep() .metadata-section {
|
|
40
|
+
margin-top: 16px;
|
|
41
|
+
margin-bottom: 24px;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
.cards-section {
|
|
45
|
+
margin: 0;
|
|
46
|
+
margin-bottom: 24px;
|
|
47
|
+
}
|
|
41
48
|
}
|
|
42
49
|
</style>
|
|
@@ -64,11 +64,11 @@ const store = useStore();
|
|
|
64
64
|
/>
|
|
65
65
|
<Metadata
|
|
66
66
|
v-bind="metadataProps"
|
|
67
|
-
class="
|
|
67
|
+
class="metadata-section"
|
|
68
68
|
/>
|
|
69
69
|
<Cards
|
|
70
70
|
v-if="props.isCustomDetailOrEdit"
|
|
71
|
-
class="
|
|
71
|
+
class="cards-section"
|
|
72
72
|
:resource="props.value"
|
|
73
73
|
/>
|
|
74
74
|
</div>
|
|
@@ -79,4 +79,14 @@ const store = useStore();
|
|
|
79
79
|
margin: 0;
|
|
80
80
|
margin-top: 16px;
|
|
81
81
|
}
|
|
82
|
+
|
|
83
|
+
:deep() .metadata-section {
|
|
84
|
+
margin-top: 16px;
|
|
85
|
+
margin-bottom: 24px;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
.cards-section {
|
|
89
|
+
margin: 0;
|
|
90
|
+
margin-bottom: 24px;
|
|
91
|
+
}
|
|
82
92
|
</style>
|
|
@@ -86,6 +86,15 @@ export default {
|
|
|
86
86
|
}
|
|
87
87
|
},
|
|
88
88
|
|
|
89
|
+
beforeMount() {
|
|
90
|
+
const inStore = this.$store.getters['currentStore'](this.resource);
|
|
91
|
+
const canList = this.$store.getters[`${ inStore }/canList`](this.resource);
|
|
92
|
+
|
|
93
|
+
if (!canList) {
|
|
94
|
+
this.$store.dispatch('loadingError', new Error(this.t('nav.failWhale.resourceListNotListable', { resource: this.schema.id }, true)));
|
|
95
|
+
}
|
|
96
|
+
},
|
|
97
|
+
|
|
89
98
|
data() {
|
|
90
99
|
const getters = this.$store.getters;
|
|
91
100
|
const params = { ...this.$route.params };
|
|
@@ -5,6 +5,7 @@ import { mapPref, GROUP_RESOURCES } from '@shell/store/prefs';
|
|
|
5
5
|
import ButtonGroup from '@shell/components/ButtonGroup';
|
|
6
6
|
import SortableTable from '@shell/components/SortableTable';
|
|
7
7
|
import { NAMESPACE, AGE } from '@shell/config/table-headers';
|
|
8
|
+
import { COUNT } from '@shell/config/types';
|
|
8
9
|
import { findBy } from '@shell/utils/array';
|
|
9
10
|
import { ExtensionPoint, TableColumnLocation, TableLocation } from '@shell/core/types';
|
|
10
11
|
import { getApplicableExtensionEnhancements } from '@shell/core/plugin-helpers';
|
|
@@ -238,6 +239,7 @@ export default {
|
|
|
238
239
|
*/
|
|
239
240
|
sortGeneration: undefined,
|
|
240
241
|
listAutoRefreshToggleEnabled: paginationUtils.listAutoRefreshToggleEnabled({ rootGetters: this.$store.getters }),
|
|
242
|
+
hasSearchFilter: false,
|
|
241
243
|
};
|
|
242
244
|
},
|
|
243
245
|
|
|
@@ -600,6 +602,26 @@ export default {
|
|
|
600
602
|
pluralLabel: this.$store.getters['type-map/labelFor'](this.schema, 99),
|
|
601
603
|
};
|
|
602
604
|
},
|
|
605
|
+
|
|
606
|
+
/**
|
|
607
|
+
* Get the counts data by namespace for the current resource type
|
|
608
|
+
*/
|
|
609
|
+
namespaceCounts() {
|
|
610
|
+
if (!this.inStore || !this.schema?.id) {
|
|
611
|
+
return {};
|
|
612
|
+
}
|
|
613
|
+
|
|
614
|
+
const counts = this.$store.getters[`${ this.inStore }/all`](COUNT)?.[0]?.counts || {};
|
|
615
|
+
|
|
616
|
+
return counts[this.schema.id]?.namespaces || {};
|
|
617
|
+
},
|
|
618
|
+
|
|
619
|
+
/**
|
|
620
|
+
* Whether we should show namespace counts in group tabs
|
|
621
|
+
*/
|
|
622
|
+
showNamespaceCounts() {
|
|
623
|
+
return (this.group === 'namespace' || this.group === 'metadata.namespace') && this.isNamespaced && !this.hasSearchFilter;
|
|
624
|
+
},
|
|
603
625
|
},
|
|
604
626
|
|
|
605
627
|
methods: {
|
|
@@ -671,6 +693,8 @@ export default {
|
|
|
671
693
|
}
|
|
672
694
|
});
|
|
673
695
|
}
|
|
696
|
+
|
|
697
|
+
this.hasSearchFilter = !!arg?.filtering?.searchQuery;
|
|
674
698
|
}
|
|
675
699
|
}
|
|
676
700
|
};
|
|
@@ -750,10 +774,15 @@ export default {
|
|
|
750
774
|
</template>
|
|
751
775
|
|
|
752
776
|
<template #group-by="{group: thisGroup}">
|
|
753
|
-
<div
|
|
754
|
-
v-clean-html="thisGroup.ref"
|
|
755
|
-
|
|
756
|
-
|
|
777
|
+
<div class="group-tab">
|
|
778
|
+
<span v-clean-html="thisGroup.ref" />
|
|
779
|
+
<span
|
|
780
|
+
v-if="showNamespaceCounts && Number.isInteger(namespaceCounts[thisGroup.rows?.[0]?.metadata?.namespace]?.count)"
|
|
781
|
+
class="count"
|
|
782
|
+
>
|
|
783
|
+
({{ namespaceCounts[thisGroup.rows?.[0]?.metadata?.namespace]?.count }})
|
|
784
|
+
</span>
|
|
785
|
+
</div>
|
|
757
786
|
</template>
|
|
758
787
|
|
|
759
788
|
<!-- Pass down templates provided by the caller -->
|
|
@@ -799,4 +828,9 @@ export default {
|
|
|
799
828
|
.auto-update {
|
|
800
829
|
min-width: 150px; height: 40px
|
|
801
830
|
}
|
|
831
|
+
|
|
832
|
+
.group-tab .count {
|
|
833
|
+
opacity: 0.7;
|
|
834
|
+
margin-left: 2px;
|
|
835
|
+
}
|
|
802
836
|
</style>
|