@rancher/shell 3.0.5-rc.3 → 3.0.5-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/images/icons/document.svg +3 -0
- package/assets/images/vendor/cognito.svg +1 -0
- package/assets/styles/app.scss +1 -0
- package/assets/styles/base/_basic.scss +10 -0
- package/assets/styles/base/_spacing.scss +29 -0
- package/assets/styles/global/_layout.scss +1 -1
- package/assets/styles/themes/_dark.scss +25 -0
- package/assets/styles/themes/_light.scss +65 -0
- package/assets/translations/en-us.yaml +322 -24
- package/assets/translations/zh-hans.yaml +8 -5
- package/components/Certificates.vue +5 -0
- package/components/FilterPanel.vue +156 -0
- package/components/{fleet/ForceDirectedTreeChart/index.vue → ForceDirectedTreeChart.vue} +47 -41
- package/components/IconOrSvg.vue +14 -35
- package/components/PromptRemove.vue +5 -1
- package/components/Resource/Detail/Card/PodsCard/Bubble.vue +13 -0
- package/components/Resource/Detail/Card/PodsCard/composable.ts +30 -0
- package/components/Resource/Detail/Card/PodsCard/index.vue +118 -0
- package/components/Resource/Detail/Card/ResourceUsageCard/composable.ts +51 -0
- package/components/Resource/Detail/Card/ResourceUsageCard/index.vue +79 -0
- package/components/Resource/Detail/Card/Scaler.vue +89 -0
- package/components/Resource/Detail/Card/StateCard/composables.ts +112 -0
- package/components/Resource/Detail/Card/StateCard/index.vue +39 -0
- package/components/Resource/Detail/Card/VerticalGap.vue +11 -0
- package/components/Resource/Detail/Card/__tests__/Card.test.ts +36 -0
- package/components/Resource/Detail/Card/__tests__/PodsCard.test.ts +84 -0
- package/components/Resource/Detail/Card/__tests__/ResourceUsageCard.test.ts +72 -0
- package/components/Resource/Detail/Card/__tests__/Scaler.test.ts +87 -0
- package/components/Resource/Detail/Card/__tests__/StateCard.test.ts +53 -0
- package/components/Resource/Detail/Card/__tests__/VerticalGap.test.ts +14 -0
- package/components/Resource/Detail/Card/__tests__/index.test.ts +36 -0
- package/components/Resource/Detail/Card/index.vue +56 -0
- package/components/Resource/Detail/Metadata/Annotations/__tests__/index.test.ts +19 -0
- package/components/Resource/Detail/Metadata/Annotations/composable.ts +12 -0
- package/components/Resource/Detail/Metadata/Annotations/index.vue +26 -0
- package/components/Resource/Detail/Metadata/IdentifyingInformation/__tests__/index.test.ts +103 -0
- package/components/Resource/Detail/Metadata/IdentifyingInformation/composable.ts +281 -0
- package/components/Resource/Detail/Metadata/IdentifyingInformation/index.vue +111 -0
- package/components/Resource/Detail/Metadata/KeyValue.vue +130 -0
- package/components/Resource/Detail/Metadata/Labels/__tests__/index.test.ts +18 -0
- package/components/Resource/Detail/Metadata/Labels/composable.ts +12 -0
- package/components/Resource/Detail/Metadata/Labels/index.vue +27 -0
- package/components/Resource/Detail/Metadata/Rectangle.vue +32 -0
- package/components/Resource/Detail/Metadata/__tests__/KeyValue.test.ts +107 -0
- package/components/Resource/Detail/Metadata/__tests__/Rectangle.test.ts +24 -0
- package/components/Resource/Detail/Metadata/__tests__/index.test.ts +91 -0
- package/components/Resource/Detail/Metadata/composables.ts +29 -0
- package/components/Resource/Detail/Metadata/index.vue +66 -0
- package/components/Resource/Detail/Page.vue +22 -0
- package/components/Resource/Detail/PercentageBar.vue +40 -0
- package/components/Resource/Detail/ResourceRow.vue +119 -0
- package/components/Resource/Detail/SpacedRow.vue +14 -0
- package/components/Resource/Detail/StatusBar.vue +59 -0
- package/components/Resource/Detail/StatusRow.vue +61 -0
- package/components/Resource/Detail/TitleBar/Title.vue +13 -0
- package/components/Resource/Detail/TitleBar/Top.vue +14 -0
- package/components/Resource/Detail/TitleBar/__tests__/Title.test.ts +17 -0
- package/components/Resource/Detail/TitleBar/__tests__/Top.test.ts +17 -0
- package/components/Resource/Detail/TitleBar/__tests__/index.test.ts +142 -0
- package/components/Resource/Detail/TitleBar/composable.ts +31 -0
- package/components/Resource/Detail/TitleBar/index.vue +124 -0
- package/components/Resource/Detail/Top/index.vue +34 -0
- package/components/Resource/Detail/__tests__/Page.test.ts +32 -0
- package/components/ResourceDetail/__tests__/index.test.ts +114 -0
- package/components/ResourceDetail/index.vue +64 -562
- package/components/ResourceDetail/legacy.vue +545 -0
- package/components/ResourceTable.vue +41 -7
- package/components/SlideInPanelManager.vue +76 -8
- package/components/SortableTable/index.vue +13 -2
- package/components/SortableTable/selection.js +21 -8
- package/components/StatusBadge.vue +6 -4
- package/components/SubtleLink.vue +25 -0
- package/components/Wizard.vue +12 -1
- package/components/YamlEditor.vue +1 -1
- package/components/__tests__/FilterPanel.test.ts +81 -0
- package/components/auth/AuthBanner.vue +2 -3
- package/components/auth/RoleDetailEdit.vue +45 -3
- package/components/auth/login/oidc.vue +6 -1
- package/components/fleet/FleetApplications.vue +181 -0
- package/components/fleet/FleetHelmOps.vue +115 -0
- package/components/fleet/FleetIntro.vue +58 -28
- package/components/fleet/FleetNoWorkspaces.vue +5 -1
- package/components/fleet/FleetOCIStorageSecret.vue +171 -0
- package/components/fleet/FleetRepos.vue +38 -76
- package/components/fleet/FleetResources.vue +50 -22
- package/components/fleet/FleetSummary.vue +26 -51
- package/components/fleet/__tests__/FleetOCIStorageSecret.test.ts +213 -0
- package/components/fleet/__tests__/FleetSummary.test.ts +39 -39
- package/components/fleet/dashboard/Empty.vue +73 -0
- package/components/fleet/dashboard/ResourceCard.vue +183 -0
- package/components/fleet/dashboard/ResourceCardSummary.vue +199 -0
- package/components/fleet/dashboard/ResourceDetails.vue +196 -0
- package/components/fleet/dashboard/ResourcePanel.vue +376 -0
- package/components/form/ArrayList.vue +6 -0
- package/components/form/SimpleSecretSelector.vue +8 -2
- package/components/form/ValueFromResource.vue +31 -19
- package/components/formatter/FleetApplicationClustersReady.vue +77 -0
- package/components/formatter/FleetApplicationSource.vue +71 -0
- package/components/formatter/FleetSummaryGraph.vue +7 -0
- package/components/nav/Header.vue +8 -7
- package/components/nav/TopLevelMenu.helper.ts +55 -34
- package/components/nav/TopLevelMenu.vue +11 -0
- package/components/nav/Type.vue +4 -1
- package/composables/useI18n.ts +12 -11
- package/config/labels-annotations.js +14 -11
- package/config/product/auth.js +1 -0
- package/config/product/fleet.js +70 -17
- package/config/query-params.js +3 -1
- package/config/roles.ts +1 -0
- package/config/router/routes.js +20 -2
- package/config/secret.ts +15 -0
- package/config/settings.ts +3 -2
- package/config/table-headers.js +52 -22
- package/config/types.js +2 -0
- package/core/plugin-helpers.ts +3 -2
- package/detail/fleet.cattle.io.cluster.vue +28 -15
- package/detail/fleet.cattle.io.gitrepo.vue +10 -1
- package/detail/fleet.cattle.io.helmop.vue +157 -0
- package/dialog/HelmOpForceUpdateDialog.vue +132 -0
- package/dialog/RedeployWorkloadDialog.vue +164 -0
- package/edit/__tests__/fleet.cattle.io.gitrepo.test.ts +56 -67
- package/edit/auth/oidc.vue +159 -93
- package/edit/fleet.cattle.io.gitrepo.vue +26 -33
- package/edit/fleet.cattle.io.helmop.vue +997 -0
- package/edit/management.cattle.io.fleetworkspace.vue +43 -10
- package/list/fleet.cattle.io.gitrepo.vue +1 -1
- package/list/fleet.cattle.io.helmop.vue +108 -0
- package/list/namespace.vue +5 -2
- package/mixins/auth-config.js +8 -1
- package/mixins/preset.js +100 -0
- package/mixins/resource-fetch-api-pagination.js +2 -0
- package/mixins/resource-fetch.js +1 -1
- package/mixins/resource-table-watch.js +45 -0
- package/models/__tests__/chart.test.ts +273 -0
- package/models/__tests__/fleet.cattle.io.gitrepo.test.ts +1 -1
- package/models/chart.js +144 -2
- package/models/fleet-application.js +385 -0
- package/models/fleet.cattle.io.bundle.js +9 -8
- package/models/fleet.cattle.io.gitrepo.js +41 -365
- package/models/fleet.cattle.io.helmop.js +228 -0
- package/models/management.cattle.io.authconfig.js +1 -0
- package/models/management.cattle.io.fleetworkspace.js +12 -0
- package/models/workload.js +14 -18
- package/package.json +2 -1
- package/pages/auth/verify.vue +13 -1
- package/pages/c/_cluster/apps/charts/AddRepoLink.vue +37 -0
- package/pages/c/_cluster/apps/charts/AppChartCardFooter.vue +80 -0
- package/pages/c/_cluster/apps/charts/AppChartCardSubHeader.vue +54 -0
- package/pages/c/_cluster/apps/charts/StatusLabel.vue +33 -0
- package/pages/c/_cluster/apps/charts/index.vue +302 -484
- package/pages/c/_cluster/explorer/EventsTable.vue +1 -1
- package/pages/c/_cluster/fleet/__tests__/index.test.ts +426 -0
- package/pages/c/_cluster/fleet/application/_resource/_id.vue +14 -0
- package/pages/c/_cluster/fleet/application/_resource/create.vue +14 -0
- package/pages/c/_cluster/fleet/application/create.vue +340 -0
- package/pages/c/_cluster/fleet/application/index.vue +139 -0
- package/pages/c/_cluster/fleet/graph/config.js +277 -0
- package/pages/c/_cluster/fleet/index.vue +772 -330
- package/pages/explorer/resource/detail/configmap.vue +19 -0
- package/plugins/dashboard-store/actions.js +31 -9
- package/plugins/dashboard-store/getters.js +34 -21
- package/plugins/dashboard-store/mutations.js +51 -7
- package/plugins/dashboard-store/resource-class.js +14 -2
- package/plugins/steve/__tests__/subscribe.spec.ts +66 -1
- package/plugins/steve/actions.js +3 -0
- package/plugins/steve/steve-pagination-utils.ts +14 -13
- package/plugins/steve/subscribe.js +229 -42
- package/rancher-components/BadgeState/BadgeState.vue +3 -1
- package/rancher-components/Form/Checkbox/Checkbox.vue +2 -2
- package/rancher-components/RcItemCard/RcItemCard.test.ts +189 -0
- package/rancher-components/RcItemCard/RcItemCard.vue +425 -0
- package/rancher-components/RcItemCard/RcItemCardAction.vue +24 -0
- package/rancher-components/RcItemCard/index.ts +2 -0
- package/store/auth.js +1 -0
- package/store/catalog.js +62 -24
- package/store/index.js +33 -14
- package/store/slideInPanel.ts +6 -0
- package/store/type-map.js +1 -0
- package/types/fleet.d.ts +35 -0
- package/types/resources/settings.d.ts +19 -1
- package/types/shell/index.d.ts +339 -272
- package/types/store/dashboard-store.types.ts +17 -3
- package/types/store/pagination.types.ts +6 -1
- package/types/store/subscribe.types.ts +50 -0
- package/utils/auth.js +32 -3
- package/utils/fleet-types.ts +0 -0
- package/utils/fleet.ts +200 -1
- package/utils/pagination-utils.ts +26 -1
- package/utils/pagination-wrapper.ts +132 -50
- package/utils/settings.ts +4 -1
- package/utils/style.ts +39 -0
- package/utils/validators/formRules/__tests__/index.test.ts +36 -3
- package/utils/validators/formRules/index.ts +10 -3
- package/utils/window.js +11 -7
- package/components/__tests__/ApplicationCard.test.ts +0 -27
- package/components/cards/ApplicationCard.vue +0 -145
- package/components/fleet/ForceDirectedTreeChart/chartIcons.js +0 -17
- package/config/secret.js +0 -14
- package/pages/c/_cluster/fleet/GitRepoGraphConfig.js +0 -249
- /package/{components/form/SSHKnownHosts → dialog}/__tests__/KnownHostsEditDialog.test.ts +0 -0
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { PaginationArgs } from '@shell/types/store/pagination.types';
|
|
1
|
+
import { PaginationArgs, StorePagination } from '@shell/types/store/pagination.types';
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
4
|
* Properties on all findX actions
|
|
@@ -47,6 +47,11 @@ export interface ActionFindAllArgs extends ActionCoreFindArgs {
|
|
|
47
47
|
depaginate?: boolean,
|
|
48
48
|
}
|
|
49
49
|
|
|
50
|
+
export interface ActionFindPageTransientResult<T> {
|
|
51
|
+
pagination: StorePagination,
|
|
52
|
+
data: T[],
|
|
53
|
+
}
|
|
54
|
+
|
|
50
55
|
/**
|
|
51
56
|
* Args used for findPage action
|
|
52
57
|
*/
|
|
@@ -62,8 +67,17 @@ export interface ActionFindPageArgs extends ActionCoreFindArgs {
|
|
|
62
67
|
*/
|
|
63
68
|
namespaced?: string,
|
|
64
69
|
/**
|
|
65
|
-
*
|
|
70
|
+
* Watch for changes
|
|
71
|
+
*
|
|
72
|
+
* false = no, all other values = yes
|
|
73
|
+
*/
|
|
74
|
+
watch?: boolean,
|
|
75
|
+
/**
|
|
76
|
+
* Does this request stem from a list with manual refresh?
|
|
66
77
|
*/
|
|
67
|
-
transient?: boolean,
|
|
68
78
|
hasManualRefresh?: boolean,
|
|
79
|
+
/**
|
|
80
|
+
* If true don't persist the http response to the store, just pass it back
|
|
81
|
+
*/
|
|
82
|
+
transient?: boolean,
|
|
69
83
|
}
|
|
@@ -451,7 +451,12 @@ export interface StorePaginationRequest {
|
|
|
451
451
|
/**
|
|
452
452
|
* The set of pagination args used to create the request
|
|
453
453
|
*/
|
|
454
|
-
pagination: PaginationArgs
|
|
454
|
+
pagination: PaginationArgs,
|
|
455
|
+
|
|
456
|
+
/**
|
|
457
|
+
* Does this request stem from a list with manual refresh?
|
|
458
|
+
*/
|
|
459
|
+
hasManualRefresh?: boolean,
|
|
455
460
|
}
|
|
456
461
|
|
|
457
462
|
/**
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
/* eslint-disable no-unused-vars */
|
|
2
|
+
export enum STEVE_WATCH_MODE {
|
|
3
|
+
DEFAULT = '',
|
|
4
|
+
RESOURCE_CHANGES = 'resource.changes'
|
|
5
|
+
}
|
|
6
|
+
/* eslint-enable no-unused-vars */
|
|
7
|
+
|
|
8
|
+
/* eslint-disable no-unused-vars */
|
|
9
|
+
export enum STEVE_WATCH_EVENT {
|
|
10
|
+
START = 'resource.start',
|
|
11
|
+
CREATE = 'resource.create',
|
|
12
|
+
CHANGE = 'resource.change',
|
|
13
|
+
CHANGES = 'resource.changes',
|
|
14
|
+
REMOVE = 'resource.resource.remove',
|
|
15
|
+
ERROR = 'resource.error',
|
|
16
|
+
STOP = 'resource.stop',
|
|
17
|
+
}
|
|
18
|
+
/* eslint-enable no-unused-vars */
|
|
19
|
+
|
|
20
|
+
export interface STEVE_WATCH_PARAMS {
|
|
21
|
+
type: string,
|
|
22
|
+
selector?: string,
|
|
23
|
+
id?: string,
|
|
24
|
+
revision?: string,
|
|
25
|
+
namespace?: string,
|
|
26
|
+
stop?: boolean,
|
|
27
|
+
force?: boolean,
|
|
28
|
+
mode?: STEVE_WATCH_MODE
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export type STEVE_WATCH_EVENT_LISTENER_CALLBACK = () => void
|
|
32
|
+
export interface STEVE_WATCH_EVENT_LISTENER {
|
|
33
|
+
params: STEVE_WATCH_PARAMS,
|
|
34
|
+
callbacks: { [id: string]: STEVE_WATCH_EVENT_LISTENER_CALLBACK},
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export interface STEVE_WATCH_EVENT_PARAMS_COMMON {
|
|
38
|
+
event: STEVE_WATCH_EVENT,
|
|
39
|
+
id: string,
|
|
40
|
+
/**
|
|
41
|
+
* of type @STEVE_WATCH_PARAMS
|
|
42
|
+
*/
|
|
43
|
+
params: STEVE_WATCH_PARAMS,
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
export interface STEVE_WATCH_EVENT_PARAMS extends STEVE_WATCH_EVENT_PARAMS_COMMON {
|
|
47
|
+
callback: STEVE_WATCH_EVENT_LISTENER_CALLBACK,
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
export type STEVE_UNWATCH_EVENT_PARAMS = STEVE_WATCH_EVENT_PARAMS_COMMON
|
package/utils/auth.js
CHANGED
|
@@ -9,6 +9,8 @@ import { getProductFromRoute, getResourceFromRoute } from '@shell/utils/router';
|
|
|
9
9
|
import { NAME as EXPLORER } from '@shell/config/product/explorer';
|
|
10
10
|
import { findBy } from '@shell/utils/array';
|
|
11
11
|
|
|
12
|
+
export const AUTH_BROADCAST_CHANNEL_NAME = 'rancher-auth-test-callback';
|
|
13
|
+
|
|
12
14
|
export function openAuthPopup(url, provider) {
|
|
13
15
|
const popup = new Popup(() => {
|
|
14
16
|
popup.promise = new Promise((resolve, reject) => {
|
|
@@ -16,19 +18,46 @@ export function openAuthPopup(url, provider) {
|
|
|
16
18
|
popup.reject = reject;
|
|
17
19
|
});
|
|
18
20
|
|
|
21
|
+
const bc = new BroadcastChannel(AUTH_BROADCAST_CHANNEL_NAME);
|
|
22
|
+
|
|
19
23
|
window.onAuthTest = (error, code) => {
|
|
20
24
|
if (error) {
|
|
21
25
|
popup.reject(error);
|
|
22
26
|
}
|
|
23
27
|
|
|
28
|
+
bc.close();
|
|
24
29
|
delete window.onAuthTest;
|
|
25
30
|
popup.resolve(code);
|
|
26
31
|
};
|
|
27
|
-
|
|
28
|
-
|
|
32
|
+
|
|
33
|
+
// Broadcast message listener for when the window can not invoke a method on the opener
|
|
34
|
+
bc.onmessage = (msgEvent) => {
|
|
35
|
+
try {
|
|
36
|
+
const obj = JSON.parse(msgEvent.data);
|
|
37
|
+
const { error, code } = obj;
|
|
38
|
+
|
|
39
|
+
window.onAuthTest(error, code);
|
|
40
|
+
} catch (e) {
|
|
41
|
+
window.onAuthTest(new Error(`Access was not authorized (invalid callback metadata)`));
|
|
42
|
+
|
|
43
|
+
console.error('Unable to process message from auth broadcast channel', e); // eslint-disable-line no-console
|
|
44
|
+
}
|
|
45
|
+
};
|
|
46
|
+
}, (e) => {
|
|
47
|
+
let detail = '';
|
|
48
|
+
|
|
49
|
+
// If there was an error and it has a message, add that to the message we send back via the promise
|
|
50
|
+
if (e?.type === 'error' && e?.message) {
|
|
51
|
+
detail = ` (${ e.message })`;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
popup.reject(new Error(`Access was not authorized${ detail }`));
|
|
29
55
|
});
|
|
30
56
|
|
|
31
|
-
|
|
57
|
+
// So far, only Amazon Cognito sets the origin policy that prevents us from detecting when the popup is closed
|
|
58
|
+
const doNotPollForClosure = provider === 'cognito';
|
|
59
|
+
|
|
60
|
+
popup.open(url, 'auth-test', popupWindowOptions(), doNotPollForClosure);
|
|
32
61
|
|
|
33
62
|
return popup.promise;
|
|
34
63
|
}
|
|
File without changes
|
package/utils/fleet.ts
CHANGED
|
@@ -5,9 +5,11 @@ import {
|
|
|
5
5
|
BundleDeploymentStatus,
|
|
6
6
|
Condition,
|
|
7
7
|
} from '@shell/types/resources/fleet';
|
|
8
|
-
import { mapStateToEnum, STATES_ENUM } from '@shell/plugins/dashboard-store/resource-class';
|
|
8
|
+
import { mapStateToEnum, STATES_ENUM, STATES } from '@shell/plugins/dashboard-store/resource-class';
|
|
9
9
|
import { FLEET as FLEET_LABELS } from '@shell/config/labels-annotations';
|
|
10
10
|
import { NAME as EXPLORER_NAME } from '@shell/config/product/explorer';
|
|
11
|
+
import { FleetDashboardState, FleetResourceState } from '@shell/types/fleet';
|
|
12
|
+
import { FLEET } from '@shell/config/types';
|
|
11
13
|
|
|
12
14
|
interface Resource extends BundleDeploymentResource {
|
|
13
15
|
state: string,
|
|
@@ -17,6 +19,17 @@ type Labels = {
|
|
|
17
19
|
[key: string]: string,
|
|
18
20
|
}
|
|
19
21
|
|
|
22
|
+
interface KeyRef {
|
|
23
|
+
key: string;
|
|
24
|
+
name: string;
|
|
25
|
+
namespace?: string;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
interface ValueFrom {
|
|
29
|
+
configMapKeyRef?: KeyRef;
|
|
30
|
+
secretKeyRef?: KeyRef;
|
|
31
|
+
}
|
|
32
|
+
|
|
20
33
|
function resourceKey(r: BundleResourceKey): string {
|
|
21
34
|
return `${ r.kind }/${ r.namespace }/${ r.name }`;
|
|
22
35
|
}
|
|
@@ -29,7 +42,140 @@ function conditionIsTrue(conditions: Condition[] | undefined, type: string): boo
|
|
|
29
42
|
return !!conditions.find((c) => c.type === type && c.status.toLowerCase() === 'true');
|
|
30
43
|
}
|
|
31
44
|
|
|
45
|
+
class HelmOp {
|
|
46
|
+
fromValuesFrom(data: ValueFrom[]): { valueFrom: ValueFrom }[] {
|
|
47
|
+
return (data || []).map((elem) => {
|
|
48
|
+
const out = {} as any;
|
|
49
|
+
|
|
50
|
+
const cm = elem.configMapKeyRef;
|
|
51
|
+
|
|
52
|
+
if (cm) {
|
|
53
|
+
out.valueFrom = {
|
|
54
|
+
configMapKeyRef: {
|
|
55
|
+
key: cm.key || '',
|
|
56
|
+
name: cm.name || '',
|
|
57
|
+
}
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
const sc = elem.secretKeyRef;
|
|
62
|
+
|
|
63
|
+
if (sc) {
|
|
64
|
+
out.valueFrom = {
|
|
65
|
+
secretKeyRef: {
|
|
66
|
+
key: sc.key || '',
|
|
67
|
+
name: sc.name || '',
|
|
68
|
+
}
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
return out;
|
|
73
|
+
});
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
toValuesFrom(data: { valueFrom: ValueFrom }[], namespace: string): ValueFrom[] {
|
|
77
|
+
return (data || [])
|
|
78
|
+
.filter((f) => f.valueFrom?.configMapKeyRef || f.valueFrom?.secretKeyRef)
|
|
79
|
+
.map(({ valueFrom }) => {
|
|
80
|
+
const cm = valueFrom.configMapKeyRef;
|
|
81
|
+
const sc = valueFrom.secretKeyRef;
|
|
82
|
+
|
|
83
|
+
const out = {} as ValueFrom;
|
|
84
|
+
|
|
85
|
+
if (cm?.name) {
|
|
86
|
+
out.configMapKeyRef = {
|
|
87
|
+
key: cm.key,
|
|
88
|
+
name: cm.name,
|
|
89
|
+
namespace
|
|
90
|
+
};
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
if (sc?.name) {
|
|
94
|
+
out.secretKeyRef = {
|
|
95
|
+
key: sc.key,
|
|
96
|
+
name: sc.name,
|
|
97
|
+
namespace
|
|
98
|
+
};
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
return out;
|
|
102
|
+
});
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
|
|
32
106
|
class Fleet {
|
|
107
|
+
resourceIcons = {
|
|
108
|
+
[FLEET.GIT_REPO]: 'icon icon-github',
|
|
109
|
+
[FLEET.HELM_OP]: 'icon icon-helm',
|
|
110
|
+
};
|
|
111
|
+
|
|
112
|
+
dashboardIcons = {
|
|
113
|
+
[FLEET.GIT_REPO]: 'icon icon-git',
|
|
114
|
+
[FLEET.HELM_OP]: 'icon icon-helm',
|
|
115
|
+
};
|
|
116
|
+
|
|
117
|
+
dashboardStates: FleetDashboardState[] = [
|
|
118
|
+
{
|
|
119
|
+
index: 0,
|
|
120
|
+
id: 'error',
|
|
121
|
+
label: 'Error',
|
|
122
|
+
color: '#F64747',
|
|
123
|
+
icon: 'icon icon-error',
|
|
124
|
+
stateBackground: 'bg-error'
|
|
125
|
+
},
|
|
126
|
+
{
|
|
127
|
+
index: 1,
|
|
128
|
+
id: 'warning',
|
|
129
|
+
label: 'Warning',
|
|
130
|
+
color: '#DAC342',
|
|
131
|
+
icon: 'icon icon-warning',
|
|
132
|
+
stateBackground: 'bg-warning'
|
|
133
|
+
},
|
|
134
|
+
{
|
|
135
|
+
index: 2,
|
|
136
|
+
id: 'success',
|
|
137
|
+
label: 'Active',
|
|
138
|
+
color: '#5D995D',
|
|
139
|
+
icon: 'icon icon-checkmark',
|
|
140
|
+
stateBackground: 'bg-success'
|
|
141
|
+
},
|
|
142
|
+
{
|
|
143
|
+
index: 3,
|
|
144
|
+
id: 'info',
|
|
145
|
+
label: 'InProgress',
|
|
146
|
+
color: '#3d98d3',
|
|
147
|
+
icon: 'icon icon-warning',
|
|
148
|
+
stateBackground: 'bg-info'
|
|
149
|
+
},
|
|
150
|
+
];
|
|
151
|
+
|
|
152
|
+
HelmOp = new HelmOp();
|
|
153
|
+
|
|
154
|
+
GIT_HTTPS_REGEX = /^https?:\/\/github\.com\/(.*?)(\.git)?\/*$/;
|
|
155
|
+
GIT_SSH_REGEX = /^git@github\.com:.*\.git$/;
|
|
156
|
+
HTTP_REGEX = /^(https?:\/\/[^\s]+)$/;
|
|
157
|
+
OCI_REGEX = /^oci:\/\//;
|
|
158
|
+
|
|
159
|
+
quacksLikeAHash(str: string) {
|
|
160
|
+
if (str.match(/^[a-f0-9]{40,}$/i)) {
|
|
161
|
+
return true;
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
return false;
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
parseSSHUrl(url: string) {
|
|
168
|
+
const parts = (url || '').split(':');
|
|
169
|
+
|
|
170
|
+
const sshUserAndHost = parts[0];
|
|
171
|
+
const repoPath = parts[1]?.replace('.git', '');
|
|
172
|
+
|
|
173
|
+
return {
|
|
174
|
+
sshUserAndHost,
|
|
175
|
+
repoPath
|
|
176
|
+
};
|
|
177
|
+
}
|
|
178
|
+
|
|
33
179
|
resourceId(r: BundleResourceKey): string {
|
|
34
180
|
return r.namespace ? `${ r.namespace }/${ r.name }` : r.name;
|
|
35
181
|
}
|
|
@@ -126,6 +272,59 @@ class Fleet {
|
|
|
126
272
|
return STATES_ENUM.READY;
|
|
127
273
|
}
|
|
128
274
|
}
|
|
275
|
+
|
|
276
|
+
getResourcesDefaultState(labelGetter: (key: string, args: any, fallback: any) => Record<string, any>, stateKey: string): Record<string, FleetResourceState> {
|
|
277
|
+
return [
|
|
278
|
+
STATES_ENUM.READY,
|
|
279
|
+
STATES_ENUM.NOT_READY,
|
|
280
|
+
STATES_ENUM.WAIT_APPLIED,
|
|
281
|
+
STATES_ENUM.MODIFIED,
|
|
282
|
+
STATES_ENUM.MISSING,
|
|
283
|
+
STATES_ENUM.ORPHANED,
|
|
284
|
+
STATES_ENUM.UNKNOWN,
|
|
285
|
+
].reduce((acc: Record<string, any>, state) => {
|
|
286
|
+
acc[state] = {
|
|
287
|
+
count: 0,
|
|
288
|
+
color: STATES[state].color,
|
|
289
|
+
label: labelGetter(`${ stateKey }.${ state }`, null, STATES[state].label ),
|
|
290
|
+
status: state
|
|
291
|
+
};
|
|
292
|
+
|
|
293
|
+
return acc;
|
|
294
|
+
}, {});
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
getBundlesDefaultState(labelGetter: (key: string, args: any, fallback: any) => Record<string, any>, stateKey: string): Record<string, FleetResourceState> {
|
|
298
|
+
return [
|
|
299
|
+
STATES_ENUM.READY,
|
|
300
|
+
STATES_ENUM.INFO,
|
|
301
|
+
STATES_ENUM.WARNING,
|
|
302
|
+
STATES_ENUM.NOT_READY,
|
|
303
|
+
STATES_ENUM.ERROR,
|
|
304
|
+
STATES_ENUM.ERR_APPLIED,
|
|
305
|
+
STATES_ENUM.WAIT_APPLIED,
|
|
306
|
+
STATES_ENUM.UNKNOWN,
|
|
307
|
+
].reduce((acc: Record<string, any>, state) => {
|
|
308
|
+
acc[state] = {
|
|
309
|
+
count: 0,
|
|
310
|
+
color: STATES[state].color,
|
|
311
|
+
label: labelGetter(`${ stateKey }.${ state }`, null, STATES[state].label ),
|
|
312
|
+
status: state
|
|
313
|
+
};
|
|
314
|
+
|
|
315
|
+
return acc;
|
|
316
|
+
}, {});
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
getDashboardStateId(resource: { stateColor: string }): string {
|
|
320
|
+
return resource?.stateColor?.replace('text-', '') || 'warning';
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
getDashboardState(resource: { stateColor: string }): FleetDashboardState | {} {
|
|
324
|
+
const stateId = this.getDashboardStateId(resource);
|
|
325
|
+
|
|
326
|
+
return this.dashboardStates.find(({ id }) => stateId === id) || {};
|
|
327
|
+
}
|
|
129
328
|
}
|
|
130
329
|
|
|
131
330
|
const instance = new Fleet();
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { PaginationSettings, PaginationSettingsStore } from '@shell/types/resources/settings';
|
|
1
|
+
import { PaginationFeature, PaginationSettings, PaginationSettingsStore } from '@shell/types/resources/settings';
|
|
2
2
|
import {
|
|
3
3
|
NAMESPACE_FILTER_ALL_USER as ALL_USER,
|
|
4
4
|
NAMESPACE_FILTER_ALL as ALL,
|
|
@@ -128,6 +128,31 @@ class PaginationUtils {
|
|
|
128
128
|
return false;
|
|
129
129
|
}
|
|
130
130
|
|
|
131
|
+
listAutoRefreshToggleEnabled({ rootGetters }: any): boolean {
|
|
132
|
+
return this.isFeatureEnabled({ rootGetters }, 'listAutoRefreshToggle');
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
isListManualRefreshEnabled({ rootGetters }: any): boolean {
|
|
136
|
+
return this.isFeatureEnabled({ rootGetters }, 'listManualRefresh');
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
private isFeatureEnabled({ rootGetters }: any, featureName: PaginationFeature): boolean {
|
|
140
|
+
// Cache must be enabled to support pagination api
|
|
141
|
+
if (!this.isSteveCacheEnabled({ rootGetters })) {
|
|
142
|
+
return false;
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
const settings = this.getSettings({ rootGetters });
|
|
146
|
+
|
|
147
|
+
return !!settings.features?.[featureName]?.enabled;
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
resourceChangesDebounceMs({ rootGetters }: any): number | undefined {
|
|
151
|
+
const settings = this.getSettings({ rootGetters });
|
|
152
|
+
|
|
153
|
+
return settings.resourceChangesDebounceMs;
|
|
154
|
+
}
|
|
155
|
+
|
|
131
156
|
validateNsProjectFilters(nsProjectFilters: string[]) {
|
|
132
157
|
return nsProjectFilters?.every((f) => this.validateNsProjectFilter(f));
|
|
133
158
|
}
|
|
@@ -1,70 +1,152 @@
|
|
|
1
1
|
import paginationUtils from '@shell/utils/pagination-utils';
|
|
2
|
-
import { PaginationArgs, PaginationResourceContext
|
|
2
|
+
import { PaginationArgs, PaginationResourceContext } from '@shell/types/store/pagination.types';
|
|
3
3
|
import { VuexStore } from '@shell/types/store/vuex';
|
|
4
|
-
import { ActionFindPageArgs } from '@shell/types/store/dashboard-store.types';
|
|
4
|
+
import { ActionFindPageArgs, ActionFindPageTransientResult } from '@shell/types/store/dashboard-store.types';
|
|
5
|
+
import {
|
|
6
|
+
STEVE_WATCH_EVENT_LISTENER_CALLBACK, STEVE_UNWATCH_EVENT_PARAMS, STEVE_WATCH_EVENT, STEVE_WATCH_EVENT_PARAMS, STEVE_WATCH_EVENT_PARAMS_COMMON, STEVE_WATCH_MODE
|
|
7
|
+
} from '@shell/types/store/subscribe.types';
|
|
8
|
+
import { Reactive, reactive } from 'vue';
|
|
5
9
|
|
|
6
|
-
interface
|
|
7
|
-
|
|
8
|
-
|
|
10
|
+
interface Args {
|
|
11
|
+
$store: VuexStore,
|
|
12
|
+
/**
|
|
13
|
+
* Unique ID for this request. Used for watch purposes
|
|
14
|
+
*/
|
|
15
|
+
id: string,
|
|
16
|
+
/**
|
|
17
|
+
* Args used when determining if this resource type supports SSP
|
|
18
|
+
*/
|
|
19
|
+
enabledFor: PaginationResourceContext,
|
|
20
|
+
/**
|
|
21
|
+
* Callback called when the resource is changed (notified by socket)
|
|
22
|
+
*/
|
|
23
|
+
onChange?: () => void,
|
|
24
|
+
|
|
25
|
+
formatResponse?: {
|
|
26
|
+
/**
|
|
27
|
+
* Convert the response into a model class instance
|
|
28
|
+
*/
|
|
29
|
+
classify?: boolean,
|
|
30
|
+
reactive?: boolean,
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
interface Result<T> extends Omit<ActionFindPageTransientResult<T>, 'data'> {
|
|
35
|
+
data: Reactive<T[]>
|
|
9
36
|
}
|
|
10
37
|
|
|
11
38
|
/**
|
|
12
|
-
* This is a helper class that will assist in fetching a resource
|
|
13
|
-
* - Handle if the resource can be fetched by the new pagination api
|
|
14
|
-
* - Make a request to get a page (including classify)
|
|
15
|
-
* - Provide updates when the resource changes
|
|
39
|
+
* This is a helper class that will assist in fetching a resource via the new Server-Side Pagination API
|
|
16
40
|
*
|
|
17
41
|
* This is designed to work in places where we don't/can't store the resource in the store
|
|
18
42
|
* - There already exists a resource we don't want to overwrite
|
|
19
|
-
* - We're transient and want something nicer than just cluster/request
|
|
43
|
+
* - We're transient and want something nicer than just `cluster/request` + all the trimmings
|
|
44
|
+
*
|
|
45
|
+
* It ...
|
|
46
|
+
* - Handles if the resource can be fetched by the new pagination api
|
|
47
|
+
* - Makes a request to get a page (including optional classify & reactive)
|
|
48
|
+
* - Provide updates when the resource changes
|
|
20
49
|
*/
|
|
21
|
-
class PaginationWrapper<T
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
50
|
+
class PaginationWrapper<T extends object> {
|
|
51
|
+
private $store: VuexStore;
|
|
52
|
+
private enabledFor: PaginationResourceContext;
|
|
53
|
+
private onChange?: STEVE_WATCH_EVENT_LISTENER_CALLBACK;
|
|
54
|
+
private id: string;
|
|
55
|
+
private classify: boolean;
|
|
56
|
+
private reactive: boolean;
|
|
57
|
+
|
|
58
|
+
public isEnabled: boolean;
|
|
59
|
+
private steveWatchParams: STEVE_WATCH_EVENT_PARAMS_COMMON | undefined;
|
|
60
|
+
|
|
61
|
+
constructor(args: Args) {
|
|
62
|
+
const {
|
|
63
|
+
$store, id, enabledFor, onChange, formatResponse
|
|
64
|
+
} = args;
|
|
65
|
+
|
|
66
|
+
this.$store = $store;
|
|
67
|
+
this.id = id;
|
|
68
|
+
this.enabledFor = enabledFor;
|
|
69
|
+
this.onChange = onChange;
|
|
70
|
+
this.classify = formatResponse?.classify || false;
|
|
71
|
+
this.reactive = formatResponse?.reactive || false;
|
|
72
|
+
|
|
73
|
+
this.isEnabled = paginationUtils.isEnabled({ rootGetters: $store.getters }, enabledFor);
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
async request(args: {
|
|
77
|
+
pagination: PaginationArgs,
|
|
78
|
+
}): Promise<Result<T>> {
|
|
79
|
+
if (!this.isEnabled) {
|
|
80
|
+
throw new Error(`Wrapper for type '${ this.enabledFor.store }/${ this.enabledFor.resource?.id }' in context '${ this.enabledFor.resource?.context }' not supported`);
|
|
81
|
+
}
|
|
82
|
+
const { pagination } = args;
|
|
83
|
+
const opt: ActionFindPageArgs = {
|
|
84
|
+
watch: false,
|
|
85
|
+
pagination,
|
|
86
|
+
transient: true,
|
|
87
|
+
};
|
|
88
|
+
|
|
89
|
+
// Fetch
|
|
90
|
+
const out: ActionFindPageTransientResult<T> = await this.$store.dispatch(`${ this.enabledFor.store }/findPage`, { opt, type: this.enabledFor.resource?.id });
|
|
91
|
+
|
|
92
|
+
// Watch
|
|
93
|
+
if (this.onChange && !this.steveWatchParams) {
|
|
94
|
+
this.steveWatchParams = {
|
|
95
|
+
event: STEVE_WATCH_EVENT.CHANGES,
|
|
96
|
+
id: this.id,
|
|
97
|
+
params: {
|
|
98
|
+
type: this.enabledFor.resource?.id as string,
|
|
99
|
+
mode: STEVE_WATCH_MODE.RESOURCE_CHANGES,
|
|
100
|
+
}
|
|
101
|
+
};
|
|
102
|
+
|
|
103
|
+
this.watch();
|
|
43
104
|
}
|
|
44
105
|
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
transient: true,
|
|
55
|
-
pagination
|
|
106
|
+
// Convert Response
|
|
107
|
+
if (this.classify) {
|
|
108
|
+
out.data = await this.$store.dispatch(`${ this.enabledFor.store }/createMany`, out.data);
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
if (this.reactive) {
|
|
112
|
+
return {
|
|
113
|
+
...out,
|
|
114
|
+
data: reactive(out.data)
|
|
56
115
|
};
|
|
116
|
+
}
|
|
57
117
|
|
|
58
|
-
|
|
118
|
+
return out;
|
|
119
|
+
}
|
|
59
120
|
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
}
|
|
64
|
-
}
|
|
121
|
+
private async watch() {
|
|
122
|
+
if (!this.steveWatchParams) {
|
|
123
|
+
console.error('Calling watch but no watch params created'); // eslint-disable-line no-console
|
|
65
124
|
|
|
66
|
-
return
|
|
125
|
+
return;
|
|
67
126
|
}
|
|
127
|
+
const watchParams: STEVE_WATCH_EVENT_PARAMS = {
|
|
128
|
+
...this.steveWatchParams,
|
|
129
|
+
callback: this.onChange as STEVE_WATCH_EVENT_LISTENER_CALLBACK, // we must have it by now
|
|
130
|
+
};
|
|
131
|
+
|
|
132
|
+
await this.$store.dispatch(`${ this.enabledFor.store }/watchEvent`, watchParams);
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
private async unWatch() {
|
|
136
|
+
if (!this.steveWatchParams) {
|
|
137
|
+
console.error('Calling unWatch but no watch params created'); // eslint-disable-line no-console
|
|
138
|
+
|
|
139
|
+
return;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
const unWatchParams: STEVE_UNWATCH_EVENT_PARAMS = { ...this.steveWatchParams };
|
|
143
|
+
|
|
144
|
+
await this.$store.dispatch(`${ this.enabledFor.store }/unwatchEvent`, unWatchParams);
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
async onDestroy() {
|
|
148
|
+
await this.unWatch();
|
|
149
|
+
}
|
|
68
150
|
}
|
|
69
151
|
|
|
70
152
|
export default PaginationWrapper;
|
package/utils/settings.ts
CHANGED
|
@@ -59,7 +59,10 @@ export const fetchInitialSettings = async(store: Store<any>): Promise<any> => {
|
|
|
59
59
|
// We're authed, we will always get the full list
|
|
60
60
|
return await store.dispatch('management/findAll', {
|
|
61
61
|
type: MANAGEMENT.SETTING,
|
|
62
|
-
opt: {
|
|
62
|
+
opt: {
|
|
63
|
+
url: `/v1/${ pluralize(MANAGEMENT.SETTING) }`,
|
|
64
|
+
watch: false, // Watch requires FF and Settings, see `loadManagement` to see how this is handled
|
|
65
|
+
}
|
|
63
66
|
} );
|
|
64
67
|
}
|
|
65
68
|
|
package/utils/style.ts
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
export type StateColor = 'success' | 'warning' | 'error' | 'info' | 'disabled';
|
|
2
|
+
export const ALL_STATE_COLORS: StateColor[] = ['success', 'warning', 'error', 'info', 'disabled'];
|
|
3
|
+
|
|
4
|
+
export function stateColorCssVar(color: StateColor) {
|
|
5
|
+
return `var(--${ color })`;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
export function toBgColor(color?: StateColor) {
|
|
9
|
+
const withDefaultColor = color || 'info';
|
|
10
|
+
|
|
11
|
+
return `bg-${ withDefaultColor }`;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Checks if 'a' is considered a higher alert than 'b'
|
|
16
|
+
* @param a target
|
|
17
|
+
* @param b comparison
|
|
18
|
+
* @returns true if 'a' is a higher alert than 'b' and false otherwise.
|
|
19
|
+
*/
|
|
20
|
+
export function isHigherAlert(a: StateColor, b: StateColor) {
|
|
21
|
+
const order: StateColor[] = ['info', 'success', 'warning', 'error'];
|
|
22
|
+
|
|
23
|
+
const aIndex = order.indexOf(a);
|
|
24
|
+
const bIndex = order.indexOf(b);
|
|
25
|
+
|
|
26
|
+
return aIndex > bIndex;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export function getHighestAlertColor(colors: StateColor[]) {
|
|
30
|
+
let highestAlert: StateColor = 'info';
|
|
31
|
+
|
|
32
|
+
for (const color of colors) {
|
|
33
|
+
if (isHigherAlert(color, highestAlert)) {
|
|
34
|
+
highestAlert = color;
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
return highestAlert;
|
|
39
|
+
}
|