@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
|
@@ -0,0 +1,425 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import { ref, computed } from 'vue';
|
|
3
|
+
import { useStore } from 'vuex';
|
|
4
|
+
import { useI18n } from '@shell/composables/useI18n';
|
|
5
|
+
import LazyImage from '@shell/components/LazyImage.vue';
|
|
6
|
+
import { DropdownOption } from '@components/RcDropdown/types';
|
|
7
|
+
import ActionMenu from '@shell/components/ActionMenuShell.vue';
|
|
8
|
+
|
|
9
|
+
const store = useStore();
|
|
10
|
+
const { t } = useI18n(store);
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Variants available for ItemCard layout
|
|
14
|
+
*/
|
|
15
|
+
type RcItemCardVariant = 'small' | 'medium';
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* A label that can be either plain text or a translatable key.
|
|
19
|
+
*/
|
|
20
|
+
type Label = {
|
|
21
|
+
key?: string;
|
|
22
|
+
text?: string;
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Represents an image used in the card.
|
|
27
|
+
*/
|
|
28
|
+
type Image = {
|
|
29
|
+
src: string;
|
|
30
|
+
alt?: Label;
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Optional pill badge, typically used to highlight a tag or state.
|
|
35
|
+
*/
|
|
36
|
+
type Pill = {
|
|
37
|
+
label: Label;
|
|
38
|
+
tooltip?: Label;
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Represents an icon-based status indicator shown in the card header.
|
|
43
|
+
*/
|
|
44
|
+
type Status = {
|
|
45
|
+
icon: string;
|
|
46
|
+
color?: string;
|
|
47
|
+
customColor?: string;
|
|
48
|
+
tooltip?: Label;
|
|
49
|
+
handleClick?: () => void;
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* Header metadata for the card.
|
|
54
|
+
*/
|
|
55
|
+
type Header = {
|
|
56
|
+
title?: Label;
|
|
57
|
+
statuses?: Status[];
|
|
58
|
+
};
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* The generic data value passed to the card.
|
|
62
|
+
*/
|
|
63
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
64
|
+
type ItemValue = Record<string, any>;
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* Props accepted by the ItemCard component.
|
|
68
|
+
*/
|
|
69
|
+
interface RcItemCardProps {
|
|
70
|
+
/** Unique identifier for the card (used in test IDs) */
|
|
71
|
+
id: string;
|
|
72
|
+
|
|
73
|
+
/** Any object value associated with this card */
|
|
74
|
+
value: ItemValue;
|
|
75
|
+
|
|
76
|
+
/** Card title, status icons and action menu. Image will be included in the header in small variant too */
|
|
77
|
+
header: Header;
|
|
78
|
+
|
|
79
|
+
/** Optional image to show in card (position depends on variant). A slot is available for it too #item-card-image */
|
|
80
|
+
image?: Image;
|
|
81
|
+
|
|
82
|
+
/** Optional actions that will be displayed inside an action-menu */
|
|
83
|
+
actions?: DropdownOption;
|
|
84
|
+
|
|
85
|
+
/** Text content inside the card body. A slot is available for it too #item-card-content */
|
|
86
|
+
content?: Label;
|
|
87
|
+
|
|
88
|
+
/** Layout variant: 'small' or 'medium' */
|
|
89
|
+
variant?: RcItemCardVariant;
|
|
90
|
+
|
|
91
|
+
/** Optional pill shown (only if variant is not 'small'). A slot is available for it too #item-card-pill */
|
|
92
|
+
pill?: Pill;
|
|
93
|
+
|
|
94
|
+
/** Makes the card clickable and emits 'card-click' on click/enter/space */
|
|
95
|
+
clickable?: boolean;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
const props = defineProps<RcItemCardProps>();
|
|
99
|
+
|
|
100
|
+
/**
|
|
101
|
+
* Emits 'card-click' when card is clicked or activated via keyboard.
|
|
102
|
+
*/
|
|
103
|
+
const emit = defineEmits<{( e: 'card-click', value: ItemValue): void; }>();
|
|
104
|
+
|
|
105
|
+
/**
|
|
106
|
+
* Handles the card click while avoiding nested interactive elements
|
|
107
|
+
* By using RcItemCardAction.vue the 'item-card-action' attribute automatically gets added
|
|
108
|
+
* which then gets used to ignore 'card-click'
|
|
109
|
+
*/
|
|
110
|
+
function _handleCardClick(e: MouseEvent | KeyboardEvent) {
|
|
111
|
+
const interactiveSelector = '[item-card-action]';
|
|
112
|
+
|
|
113
|
+
// Prevent card click if the user clicks on an inner actionable element like repo, category, or tag
|
|
114
|
+
if ((e.target as HTMLElement).closest(interactiveSelector)) {
|
|
115
|
+
return;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
emit('card-click', props.value);
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
/**
|
|
122
|
+
* Utility to resolve localized or plain text labels.
|
|
123
|
+
*/
|
|
124
|
+
function labelText(label?: Label): string {
|
|
125
|
+
return label?.key ? t(label.key) : label?.text ?? '';
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
/** ---------------- data ------------------ */
|
|
129
|
+
const cardEl = ref<HTMLElement | null>(null);
|
|
130
|
+
|
|
131
|
+
/** ---------------- Computed ------------------ */
|
|
132
|
+
|
|
133
|
+
const headerTitle = computed(() => labelText(props.header.title));
|
|
134
|
+
const imageAlt = computed(() => labelText(props.image?.alt));
|
|
135
|
+
const pillLabel = computed(() => labelText(props.pill?.label));
|
|
136
|
+
const pillTooltip = computed(() => labelText(props.pill?.tooltip));
|
|
137
|
+
const contentText = computed(() => labelText(props.content));
|
|
138
|
+
const statusTooltips = computed(() => props.header.statuses?.map((status) => labelText(status.tooltip)) || []);
|
|
139
|
+
|
|
140
|
+
const cardMeta = computed(() => ({
|
|
141
|
+
ariaLabel: props.clickable ? t('itemCard.ariaLabel.clickable', { cardTitle: labelText(props.header.title) }) : undefined,
|
|
142
|
+
tabIndex: props.clickable ? '0' : undefined,
|
|
143
|
+
role: props.clickable ? 'button' : undefined
|
|
144
|
+
}));
|
|
145
|
+
|
|
146
|
+
</script>
|
|
147
|
+
|
|
148
|
+
<template>
|
|
149
|
+
<div
|
|
150
|
+
ref="cardEl"
|
|
151
|
+
class="item-card"
|
|
152
|
+
:role="cardMeta.role"
|
|
153
|
+
:tabindex="cardMeta.tabIndex"
|
|
154
|
+
:aria-label="cardMeta.ariaLabel"
|
|
155
|
+
:data-testid="`item-card-${id}`"
|
|
156
|
+
@click="_handleCardClick"
|
|
157
|
+
@keydown.enter="_handleCardClick"
|
|
158
|
+
@keydown.space.prevent="_handleCardClick"
|
|
159
|
+
>
|
|
160
|
+
<div :class="['item-card-body', variant]">
|
|
161
|
+
<template v-if="variant !== 'small'">
|
|
162
|
+
<div>
|
|
163
|
+
<slot name="item-card-image">
|
|
164
|
+
<div
|
|
165
|
+
v-if="image"
|
|
166
|
+
:class="['item-card-image', variant]"
|
|
167
|
+
data-testid="item-card-image"
|
|
168
|
+
>
|
|
169
|
+
<LazyImage
|
|
170
|
+
:src="image.src"
|
|
171
|
+
:alt="imageAlt"
|
|
172
|
+
:style="{'width': '40px', 'height': '40px', 'object-fit': 'contain'}"
|
|
173
|
+
/>
|
|
174
|
+
</div>
|
|
175
|
+
</slot>
|
|
176
|
+
<slot name="item-card-pill">
|
|
177
|
+
<div
|
|
178
|
+
v-if="pill"
|
|
179
|
+
v-clean-tooltip="pillTooltip"
|
|
180
|
+
class="item-card-pill"
|
|
181
|
+
data-testid="item-card-pill"
|
|
182
|
+
>
|
|
183
|
+
{{ pillLabel }}
|
|
184
|
+
</div>
|
|
185
|
+
</slot>
|
|
186
|
+
</div>
|
|
187
|
+
</template>
|
|
188
|
+
|
|
189
|
+
<div :class="['item-card-body-details', variant]">
|
|
190
|
+
<div :class="['item-card-header', variant]">
|
|
191
|
+
<div class="item-card-header-left">
|
|
192
|
+
<template v-if="variant === 'small'">
|
|
193
|
+
<slot name="item-card-image">
|
|
194
|
+
<div
|
|
195
|
+
v-if="image"
|
|
196
|
+
:class="['item-card-image', variant]"
|
|
197
|
+
data-testid="item-card-image"
|
|
198
|
+
>
|
|
199
|
+
<LazyImage
|
|
200
|
+
:src="image.src"
|
|
201
|
+
:alt="imageAlt"
|
|
202
|
+
:style="{'width': '24px', 'height': '24px', 'object-fit': 'contain'}"
|
|
203
|
+
/>
|
|
204
|
+
</div>
|
|
205
|
+
</slot>
|
|
206
|
+
</template>
|
|
207
|
+
<slot name="item-card-header-title">
|
|
208
|
+
<h3
|
|
209
|
+
v-if="header.title"
|
|
210
|
+
v-clean-tooltip="headerTitle"
|
|
211
|
+
:class="['item-card-header-title', variant]"
|
|
212
|
+
data-testid="item-card-header-title"
|
|
213
|
+
>
|
|
214
|
+
{{ headerTitle }}
|
|
215
|
+
</h3>
|
|
216
|
+
</slot>
|
|
217
|
+
</div>
|
|
218
|
+
<div class="item-card-header-right">
|
|
219
|
+
<div
|
|
220
|
+
v-if="header.statuses?.length"
|
|
221
|
+
class="item-card-header-statuses"
|
|
222
|
+
>
|
|
223
|
+
<div
|
|
224
|
+
v-for="(status, i) in header.statuses"
|
|
225
|
+
:key="i"
|
|
226
|
+
class="item-card-header-statuses-status"
|
|
227
|
+
data-testid="item-card-header-statuses-status"
|
|
228
|
+
>
|
|
229
|
+
<i
|
|
230
|
+
v-clean-tooltip="statusTooltips[i]"
|
|
231
|
+
:class="['icon', status.icon, status.color]"
|
|
232
|
+
:style="{color: status.customColor}"
|
|
233
|
+
:data-testid="`item-card-header-status-${i}`"
|
|
234
|
+
/>
|
|
235
|
+
</div>
|
|
236
|
+
</div>
|
|
237
|
+
|
|
238
|
+
<template v-if="$slots['item-card-actions']">
|
|
239
|
+
<div class="item-card-header-action-menu">
|
|
240
|
+
<slot name="item-card-actions" />
|
|
241
|
+
</div>
|
|
242
|
+
</template>
|
|
243
|
+
<template v-else-if="actions">
|
|
244
|
+
<div class="item-card-header-action-menu">
|
|
245
|
+
<ActionMenu
|
|
246
|
+
data-testid="item-card-header-action-menu"
|
|
247
|
+
:custom-actions="actions"
|
|
248
|
+
/>
|
|
249
|
+
</div>
|
|
250
|
+
</template>
|
|
251
|
+
</div>
|
|
252
|
+
</div>
|
|
253
|
+
|
|
254
|
+
<slot name="item-card-sub-header" />
|
|
255
|
+
|
|
256
|
+
<template v-if="$slots['item-card-content']">
|
|
257
|
+
<slot name="item-card-content">
|
|
258
|
+
<div
|
|
259
|
+
class="item-card-content"
|
|
260
|
+
data-testid="item-card-content"
|
|
261
|
+
/>
|
|
262
|
+
</slot>
|
|
263
|
+
</template>
|
|
264
|
+
<template v-else-if="content">
|
|
265
|
+
<div
|
|
266
|
+
class="item-card-content"
|
|
267
|
+
data-testid="item-card-content"
|
|
268
|
+
>
|
|
269
|
+
<p>{{ contentText }}</p>
|
|
270
|
+
</div>
|
|
271
|
+
</template>
|
|
272
|
+
|
|
273
|
+
<slot name="item-card-footer" />
|
|
274
|
+
</div>
|
|
275
|
+
</div>
|
|
276
|
+
</div>
|
|
277
|
+
</template>
|
|
278
|
+
|
|
279
|
+
<style scoped lang="scss">
|
|
280
|
+
$image-medium-box-width: 48px;
|
|
281
|
+
|
|
282
|
+
.item-card {
|
|
283
|
+
display: flex;
|
|
284
|
+
padding: 16px;
|
|
285
|
+
align-items: flex-start;
|
|
286
|
+
gap: var(--gap-lg);
|
|
287
|
+
border-radius: var(--border-radius-md);
|
|
288
|
+
border: 1px solid var(--border);
|
|
289
|
+
background: var(--body-bg);
|
|
290
|
+
|
|
291
|
+
&:hover {
|
|
292
|
+
border-color: var(--primary);
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
&:focus-visible {
|
|
296
|
+
@include focus-outline;
|
|
297
|
+
outline-offset: -2px;
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
&-image {
|
|
301
|
+
width: $image-medium-box-width;
|
|
302
|
+
height: $image-medium-box-width;
|
|
303
|
+
display: flex;
|
|
304
|
+
align-items: center;
|
|
305
|
+
justify-content: center;
|
|
306
|
+
background: #fff;
|
|
307
|
+
border-radius: var(--border-radius);
|
|
308
|
+
|
|
309
|
+
&.small {
|
|
310
|
+
width: 32px;
|
|
311
|
+
height: 32px;
|
|
312
|
+
margin-right: 12px;
|
|
313
|
+
}
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
&-header {
|
|
317
|
+
display: flex;
|
|
318
|
+
align-items: center;
|
|
319
|
+
justify-content: space-between;
|
|
320
|
+
width: 100%;
|
|
321
|
+
height: 24px;
|
|
322
|
+
color: var(--body-text);
|
|
323
|
+
|
|
324
|
+
&-left,
|
|
325
|
+
&-right {
|
|
326
|
+
display: flex;
|
|
327
|
+
align-items: center;
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
&-left {
|
|
331
|
+
flex-grow: 1;
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
&-title {
|
|
335
|
+
max-width: 60%;
|
|
336
|
+
font-size: 18px;
|
|
337
|
+
font-weight: 600;
|
|
338
|
+
margin-bottom: 0px;
|
|
339
|
+
line-height: 24px;
|
|
340
|
+
text-overflow: ellipsis;
|
|
341
|
+
white-space: nowrap;
|
|
342
|
+
overflow: hidden;
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
&-statuses {
|
|
346
|
+
display: flex;
|
|
347
|
+
align-items: flex-start;
|
|
348
|
+
gap: 12px;
|
|
349
|
+
|
|
350
|
+
&-status {
|
|
351
|
+
width: 24px;
|
|
352
|
+
height: 24px;
|
|
353
|
+
display: flex;
|
|
354
|
+
align-items: center;
|
|
355
|
+
justify-content: center;
|
|
356
|
+
|
|
357
|
+
.icon {
|
|
358
|
+
font-size: 23px;
|
|
359
|
+
|
|
360
|
+
&.error { color: var(--error); }
|
|
361
|
+
&.info { color: var(--info); }
|
|
362
|
+
&.success { color: var(--success); }
|
|
363
|
+
}
|
|
364
|
+
}
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
&-action-menu {
|
|
368
|
+
margin-left: 12px;
|
|
369
|
+
}
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
&-content {
|
|
373
|
+
display: -webkit-box;
|
|
374
|
+
-webkit-line-clamp: 3;
|
|
375
|
+
-webkit-box-orient: vertical;
|
|
376
|
+
overflow: hidden;
|
|
377
|
+
text-overflow: ellipsis;
|
|
378
|
+
line-height: 21px;
|
|
379
|
+
word-break: break-word;
|
|
380
|
+
}
|
|
381
|
+
|
|
382
|
+
&-pill {
|
|
383
|
+
display: flex;
|
|
384
|
+
width: $image-medium-box-width;
|
|
385
|
+
padding: 4px 8px;
|
|
386
|
+
margin-top: 16px;
|
|
387
|
+
justify-content: center;
|
|
388
|
+
align-items: center;
|
|
389
|
+
border-radius: var(--border-radius);
|
|
390
|
+
background: var(--default);
|
|
391
|
+
text-transform: uppercase;
|
|
392
|
+
color: var(--disabled-text);
|
|
393
|
+
font-size: 10px;
|
|
394
|
+
font-weight: 600;
|
|
395
|
+
}
|
|
396
|
+
|
|
397
|
+
&-body {
|
|
398
|
+
display: flex;
|
|
399
|
+
flex-direction: row;
|
|
400
|
+
width: 100%;
|
|
401
|
+
gap: var(--gap-lg);
|
|
402
|
+
|
|
403
|
+
&.small {
|
|
404
|
+
flex-direction: column;
|
|
405
|
+
align-items: flex-start;
|
|
406
|
+
gap: var(--gap);
|
|
407
|
+
flex: 1;
|
|
408
|
+
}
|
|
409
|
+
|
|
410
|
+
&-details {
|
|
411
|
+
display: flex;
|
|
412
|
+
flex-direction: column;
|
|
413
|
+
align-items: flex-start;
|
|
414
|
+
width: calc(100% - var(--gap-lg) - $image-medium-box-width);
|
|
415
|
+
gap: var(--gap);
|
|
416
|
+
flex: 1;
|
|
417
|
+
|
|
418
|
+
&.small {
|
|
419
|
+
width: 100%;
|
|
420
|
+
}
|
|
421
|
+
}
|
|
422
|
+
}
|
|
423
|
+
}
|
|
424
|
+
|
|
425
|
+
</style>
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
/**
|
|
3
|
+
* RcItemCardAction
|
|
4
|
+
*
|
|
5
|
+
* This component is used to wrap any interactive elements (like buttons, links)
|
|
6
|
+
* inside an RcItemCard so they don't trigger the card-click event.
|
|
7
|
+
*
|
|
8
|
+
* Usage:
|
|
9
|
+
*
|
|
10
|
+
* <rc-item-card-action @click="doSomething">
|
|
11
|
+
* <a href="#">Click me</a>
|
|
12
|
+
* </rc-item-card-action>
|
|
13
|
+
*
|
|
14
|
+
*/
|
|
15
|
+
</script>
|
|
16
|
+
|
|
17
|
+
<template>
|
|
18
|
+
<div
|
|
19
|
+
item-card-action
|
|
20
|
+
data-testid="rc-item-card-action"
|
|
21
|
+
>
|
|
22
|
+
<slot />
|
|
23
|
+
</div>
|
|
24
|
+
</template>
|
package/store/auth.js
CHANGED
package/store/catalog.js
CHANGED
|
@@ -31,6 +31,12 @@ const CERTIFIED_SORTS = {
|
|
|
31
31
|
other: 3,
|
|
32
32
|
};
|
|
33
33
|
|
|
34
|
+
export const APP_STATUS = {
|
|
35
|
+
INSTALLED: 'installed',
|
|
36
|
+
DEPRECATED: 'deprecated',
|
|
37
|
+
UPGRADEABLE: 'upgradeable'
|
|
38
|
+
};
|
|
39
|
+
|
|
34
40
|
export const APP_UPGRADE_STATUS = {
|
|
35
41
|
NOT_APPLICABLE: 'not_applicable', // managed by fleet
|
|
36
42
|
NO_UPGRADE: 'no_upgrade', // no upgrade found
|
|
@@ -498,35 +504,51 @@ function addChart(ctx, map, chart, repo) {
|
|
|
498
504
|
|
|
499
505
|
if ( !obj ) {
|
|
500
506
|
if ( ctx ) { }
|
|
507
|
+
const experimental = !!chart.annotations?.[CATALOG_ANNOTATIONS.EXPERIMENTAL];
|
|
508
|
+
const windowsIncompatible = !(chart.annotations?.[CATALOG_ANNOTATIONS.PERMITTED_OS] || '').includes('windows');
|
|
509
|
+
const deploysOnWindows = (chart.annotations?.[CATALOG_ANNOTATIONS.DEPLOYED_OS] || '').includes('windows');
|
|
510
|
+
const tags = [];
|
|
511
|
+
|
|
512
|
+
if (experimental) {
|
|
513
|
+
tags.push(ctx.rootGetters['i18n/withFallback']('generic.experimental'));
|
|
514
|
+
}
|
|
515
|
+
if (windowsIncompatible) {
|
|
516
|
+
tags.push(ctx.rootGetters['i18n/withFallback']('catalog.charts.windowsIncompatible'));
|
|
517
|
+
}
|
|
518
|
+
if (deploysOnWindows) {
|
|
519
|
+
tags.push(ctx.rootGetters['i18n/withFallback']('catalog.charts.deploysOnWindows'));
|
|
520
|
+
}
|
|
521
|
+
|
|
501
522
|
obj = classify(ctx, {
|
|
502
523
|
key,
|
|
503
|
-
type:
|
|
504
|
-
id:
|
|
524
|
+
type: 'chart',
|
|
525
|
+
id: key,
|
|
505
526
|
certified,
|
|
506
527
|
sideLabel,
|
|
507
528
|
repoType,
|
|
508
529
|
repoName,
|
|
509
|
-
repoNameDisplay:
|
|
510
|
-
certifiedSort:
|
|
511
|
-
icon:
|
|
512
|
-
color:
|
|
513
|
-
chartType:
|
|
514
|
-
chartName:
|
|
515
|
-
chartNameDisplay:
|
|
516
|
-
chartDescription:
|
|
517
|
-
featured:
|
|
518
|
-
repoKey:
|
|
519
|
-
versions:
|
|
520
|
-
categories:
|
|
521
|
-
deprecated:
|
|
522
|
-
experimental
|
|
523
|
-
hidden:
|
|
524
|
-
targetNamespace:
|
|
525
|
-
targetName:
|
|
526
|
-
scope:
|
|
527
|
-
provides:
|
|
528
|
-
windowsIncompatible
|
|
529
|
-
deploysOnWindows
|
|
530
|
+
repoNameDisplay: ctx.rootGetters['i18n/withFallback'](`catalog.repo.name."${ repoName }"`, null, repoName),
|
|
531
|
+
certifiedSort: CERTIFIED_SORTS[certified] || 99,
|
|
532
|
+
icon: chart.icon,
|
|
533
|
+
color: repo.color,
|
|
534
|
+
chartType: chart.annotations?.[CATALOG_ANNOTATIONS.TYPE] || CATALOG_ANNOTATIONS._APP,
|
|
535
|
+
chartName: chart.name,
|
|
536
|
+
chartNameDisplay: chart.annotations?.[CATALOG_ANNOTATIONS.DISPLAY_NAME] || chart.name,
|
|
537
|
+
chartDescription: chart.description,
|
|
538
|
+
featured: chart.annotations?.[CATALOG_ANNOTATIONS.FEATURED],
|
|
539
|
+
repoKey: repo._key,
|
|
540
|
+
versions: [],
|
|
541
|
+
categories: filterCategories(chart.keywords),
|
|
542
|
+
deprecated: !!chart.deprecated,
|
|
543
|
+
experimental,
|
|
544
|
+
hidden: !!chart.annotations?.[CATALOG_ANNOTATIONS.HIDDEN],
|
|
545
|
+
targetNamespace: chart.annotations?.[CATALOG_ANNOTATIONS.NAMESPACE],
|
|
546
|
+
targetName: chart.annotations?.[CATALOG_ANNOTATIONS.RELEASE_NAME],
|
|
547
|
+
scope: chart.annotations?.[CATALOG_ANNOTATIONS.SCOPE],
|
|
548
|
+
provides: [],
|
|
549
|
+
windowsIncompatible,
|
|
550
|
+
deploysOnWindows,
|
|
551
|
+
tags
|
|
530
552
|
});
|
|
531
553
|
|
|
532
554
|
map[key] = obj;
|
|
@@ -582,6 +604,16 @@ function normalizeCategory(c) {
|
|
|
582
604
|
return c.replace(/\s+/g, '').toLowerCase();
|
|
583
605
|
}
|
|
584
606
|
|
|
607
|
+
export function normalizeFilterQuery(value) {
|
|
608
|
+
if (Array.isArray(value)) {
|
|
609
|
+
return value.map((v) => v.toLowerCase());
|
|
610
|
+
} else if (value) {
|
|
611
|
+
return [value.toLowerCase()];
|
|
612
|
+
}
|
|
613
|
+
|
|
614
|
+
return undefined;
|
|
615
|
+
}
|
|
616
|
+
|
|
585
617
|
/*
|
|
586
618
|
catalog.cattle.io/deplys-on-os: OS -> requires global.cattle.OS.enabled: true
|
|
587
619
|
default: nothing
|
|
@@ -614,6 +646,7 @@ export function filterAndArrangeCharts(charts, {
|
|
|
614
646
|
clusterProvider = '',
|
|
615
647
|
operatingSystems,
|
|
616
648
|
category,
|
|
649
|
+
tag,
|
|
617
650
|
searchQuery,
|
|
618
651
|
showDeprecated = false,
|
|
619
652
|
showHidden = false,
|
|
@@ -641,11 +674,16 @@ export function filterAndArrangeCharts(charts, {
|
|
|
641
674
|
return false;
|
|
642
675
|
}
|
|
643
676
|
|
|
644
|
-
if (
|
|
677
|
+
if (category?.length && !c.categories.some((cat) => category.includes(cat.toLowerCase()))) {
|
|
645
678
|
// The category filter doesn't match
|
|
646
679
|
return false;
|
|
647
680
|
}
|
|
648
681
|
|
|
682
|
+
if (tag?.length && !c.tags.some((t) => tag.includes(t.toLowerCase()))) {
|
|
683
|
+
// The tag filter doesn't match
|
|
684
|
+
return false;
|
|
685
|
+
}
|
|
686
|
+
|
|
649
687
|
if ( searchQuery ) {
|
|
650
688
|
// The search filter doesn't match
|
|
651
689
|
const searchTokens = searchQuery.split(/\s*[, ]\s*/).map((x) => ensureRegex(x, false));
|