diff --git a/pkg/harvester/assets/images/dark/suse-virtualization.svg b/pkg/harvester/assets/images/dark/suse-virtualization.svg new file mode 100644 index 00000000..3d6b2784 --- /dev/null +++ b/pkg/harvester/assets/images/dark/suse-virtualization.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/pkg/harvester/assets/images/suse-virtualization.svg b/pkg/harvester/assets/images/suse-virtualization.svg new file mode 100644 index 00000000..a1565a6f --- /dev/null +++ b/pkg/harvester/assets/images/suse-virtualization.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/pkg/harvester/components/SettingList.vue b/pkg/harvester/components/SettingList.vue index cf8713a5..85f10a78 100644 --- a/pkg/harvester/components/SettingList.vue +++ b/pkg/harvester/components/SettingList.vue @@ -10,6 +10,7 @@ import { docLink } from '../utils/feature-flags'; const CATEGORY = { ui: [ 'branding', + HCI_SETTING.SERVER_FLAVOR, 'ui-source', 'ui-index', ] @@ -53,7 +54,7 @@ export default { }; }, - computed: { ...mapGetters({ t: 'i18n/t' }) }, + computed: { ...mapGetters({ t: 'i18n/t', isHarvesterPrime: 'harvester-common/isHarvesterPrime' }) }, watch: { settings: { @@ -269,7 +270,8 @@ export default { v-if="!setting.hide" class="settings-value" > -
{{ setting.json }}
+ {{ $store.getters['harvester-common/privateLabel'] }}
+ {{ setting.json }}
{{ setting.data.value || setting.data.default }}
{{ t(setting.enum) }}
{{ setting.custom }}
diff --git a/pkg/harvester/config/harvester-cluster.js b/pkg/harvester/config/harvester-cluster.js
index 53eb6ddd..7aa32da9 100644
--- a/pkg/harvester/config/harvester-cluster.js
+++ b/pkg/harvester/config/harvester-cluster.js
@@ -57,6 +57,8 @@ import {
} from './table-headers';
import { ADD_ONS } from './harvester-map';
import { registerAddonSideNav } from '../utils/dynamic-nav';
+import { setVendor } from '@shell/config/private-label';
+import { createCssVars } from '@shell/utils/color';
const TEMPLATE = HCI.VM_VERSION;
const MONITORING_GROUP = 'Monitoring & Logging::Monitoring';
@@ -109,15 +111,51 @@ export function init($plugin, store) {
}
};
- store.dispatch('setIsSingleProduct', {
- productName: PRODUCT_NAME,
- logo: require(`@shell/assets/images/providers/harvester.svg`),
- productNameKey: 'harvester.productLabel',
- getVersionInfo: (store) => store.getters[`${ PRODUCT_NAME }/byId`]?.(HCI.SETTING, 'server-version')?.value || 'unknown',
- afterLoginRoute: home,
- logoRoute: home,
- supportCustomLogo: true
- });
+ store.watch(
+ (_state, getters) => JSON.stringify([
+ !!getters['harvester-common/isHarvesterPrime'],
+ getters['prefs/theme'] === 'dark',
+ getters['harvester-common/privateLabel']
+ ]),
+ (value) => {
+ const [isHarvesterPrime, isDark, privateLabel] = JSON.parse(value);
+ const primeLogo = isDark ? require('../assets/images/dark/suse-virtualization.svg') : require('../assets/images/suse-virtualization.svg');
+
+ setVendor(privateLabel || '');
+
+ let primaryColorStyle = document.getElementById('harvester-prime-primary-color');
+
+ // set harvester prime primary color style to #4dd192 (Cyan Green)
+ if (isHarvesterPrime) {
+ if (!primaryColorStyle) {
+ primaryColorStyle = document.createElement('style');
+ primaryColorStyle.id = 'harvester-prime-primary-color';
+ document.head.appendChild(primaryColorStyle);
+ primaryColorStyle.sheet.insertRule('body.theme-light, body.theme-dark {}', 0);
+ }
+
+ const colors = createCssVars('#4dd192', isDark ? 'dark' : 'light');
+ const rule = primaryColorStyle.sheet.cssRules[0];
+
+ Object.entries(colors).forEach(([property, color]) => rule.style.setProperty(property.trim(), color));
+ } else {
+ primaryColorStyle?.remove();
+ }
+
+ const primeLabelKey = privateLabel ? 'harvester.branding.primeLabel' : 'harvester.branding.primeEmptyLabel';
+
+ store.dispatch('setIsSingleProduct', {
+ productName: PRODUCT_NAME,
+ logo: isHarvesterPrime ? primeLogo : require(`@shell/assets/images/providers/harvester.svg`),
+ productNameKey: isHarvesterPrime ? primeLabelKey : 'harvester.productLabel',
+ getVersionInfo: (store) => store.getters[`${ PRODUCT_NAME }/byId`]?.(HCI.SETTING, 'server-version')?.value || 'unknown',
+ afterLoginRoute: home,
+ logoRoute: home,
+ supportCustomLogo: !isHarvesterPrime
+ });
+ },
+ { immediate: true }
+ );
}
product({
diff --git a/pkg/harvester/config/settings.ts b/pkg/harvester/config/settings.ts
index 7b2f62bd..bc66b93a 100644
--- a/pkg/harvester/config/settings.ts
+++ b/pkg/harvester/config/settings.ts
@@ -3,6 +3,7 @@ export const HCI_SETTING = {
CONTAINERD_REGISTRY: 'containerd-registry',
LOG_LEVEL: 'log-level',
SERVER_VERSION: 'server-version',
+ SERVER_FLAVOR: 'server-flavor',
UI_INDEX: 'ui-index',
UPGRADE_CHECKER_ENABLED: 'upgrade-checker-enabled',
UPGRADE_CHECKER_URL: 'upgrade-checker-url',
@@ -68,6 +69,7 @@ export const HCI_ALLOWED_SETTINGS = {
kind: 'json', from: 'import', featureFlag: 'csiOnlineExpandValidation'
},
[HCI_SETTING.SERVER_VERSION]: { readOnly: true },
+ [HCI_SETTING.SERVER_FLAVOR]: { readOnly: true },
[HCI_SETTING.UPGRADE_CHECKER_ENABLED]: { kind: 'boolean' },
[HCI_SETTING.UPGRADE_CHECKER_URL]: { kind: 'url' },
[HCI_SETTING.HTTP_PROXY]: { kind: 'json', from: 'import' },
diff --git a/pkg/harvester/l10n/en-us.yaml b/pkg/harvester/l10n/en-us.yaml
index 785378a8..cfa8e46d 100644
--- a/pkg/harvester/l10n/en-us.yaml
+++ b/pkg/harvester/l10n/en-us.yaml
@@ -84,6 +84,8 @@ dialog:
harvester:
branding:
+ primeLabel: '{vendor}'
+ primeEmptyLabel: ''
logos:
tip: 'Upload a logo to replace the Harvester logo in the top-level navigation header. Image height should be 21 pixels with a max width of 200 pixels. Max file size is 20KB. Accepted formats: JPEG, PNG, SVG.'
favicon:
@@ -2445,6 +2447,7 @@ advancedSettings:
'harv-containerd-registry': Containerd Registry Configuration to connect private registries.
'harv-log-level': Configure Harvester server log level. Defaults to Info.
'harv-server-version': Harvester server version.
+ 'harv-server-flavor': "Indicates the Harvester edition: Prime or Community."
'harv-upgrade-checker-enabled': Specifies whether to enable Harvester upgrade check or not. Default is True.
'harv-upgrade-checker-url': Default Harvester upgrade check url. Only used when the upgrade-checker-enabled is equal to True.
'harv-ui-source': Configure how to load the UI source. The `External` option is used to load the UI from a ui-index URL, while the `Bundled` option loads the UI from the local Harvester server.
diff --git a/pkg/harvester/models/management/management.cattle.io.setting.js b/pkg/harvester/models/management/management.cattle.io.setting.js
new file mode 100644
index 00000000..6ab07270
--- /dev/null
+++ b/pkg/harvester/models/management/management.cattle.io.setting.js
@@ -0,0 +1,14 @@
+import ManagementSetting from '@shell/models/management.cattle.io.setting';
+import { HCI_SETTING } from '../../config/settings';
+
+export default class HarvesterManagementSetting extends ManagementSetting {
+ get _availableActions() {
+ const actions = super._availableActions;
+
+ if (this.$rootGetters['isStandaloneHarvester'] && this.id === HCI_SETTING.UI_PL) {
+ return actions.filter((action) => !['goToClone', 'promptRemove'].includes(action.action));
+ }
+
+ return actions;
+ }
+}
diff --git a/pkg/harvester/pages/c/_cluster/brand/index.vue b/pkg/harvester/pages/c/_cluster/brand/index.vue
index 047d57dc..fd493e2a 100644
--- a/pkg/harvester/pages/c/_cluster/brand/index.vue
+++ b/pkg/harvester/pages/c/_cluster/brand/index.vue
@@ -63,6 +63,7 @@ export default {
return {
vendor: getVendor(),
uiPLSetting: {},
+ privateLabelDraft: null,
uiLogoDarkSetting: {},
uiLogoDark: '',
uiLogoLightSetting: {},
@@ -81,6 +82,17 @@ export default {
};
},
computed: {
+ isHarvesterPrime() {
+ return !!this.$store.getters['harvester-common/isHarvesterPrime'];
+ },
+ privateLabel: {
+ get() {
+ return this.privateLabelDraft ?? (this.isHarvesterPrime ? this.$store.getters['harvester-common/privateLabel'] : this.uiPLSetting.value);
+ },
+ set(value) {
+ this.privateLabelDraft = value;
+ }
+ },
mode() {
const schema = this.$store.getters[`management/schemaFor`](MANAGEMENT.SETTING);
@@ -112,7 +124,7 @@ export default {
this.errors.push(e);
},
async save(btnCB) {
- this.uiPLSetting.value = this.uiPLSetting.value.replaceAll(/[\<>&=#()"]/gm, '');
+ this.uiPLSetting.value = (this.privateLabel || '').replaceAll(/[\<>&=#()"]/gm, '');
if (this.customizeLogo) {
this.uiLogoLightSetting.value = this.uiLogoLight;
this.uiLogoDarkSetting.value = this.uiLogoDark;
@@ -169,7 +181,7 @@ export default {