Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for modifying doc links and add support for different links for Rancher Prime #13020

Open
wants to merge 5 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions cypress/e2e/po/edit/auth/azuread.po.ts
Original file line number Diff line number Diff line change
Expand Up @@ -107,4 +107,8 @@ export default class AzureadPo extends PagePo {
save() {
return new AsyncButtonPo('[data-testid="form-save"]').click();
}

permissionsWarningBanner() {
return this.self().get('[data-testid="auth-provider-admin-permissions-warning-banner"]');
}
}
43 changes: 43 additions & 0 deletions cypress/e2e/tests/pages/generic/prime.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import HomePagePo from '@/cypress/e2e/po/pages/home.po';
import AuthProviderPo from '@/cypress/e2e/po/pages/users-and-auth/authProvider.po';
import AzureadPo from '@/cypress/e2e/po/edit/auth/azuread.po';

const homePage = new HomePagePo();
const PRIME_DOCS_BASE = 'https://documentation.suse.com/cloudnative/rancher-manager/';

function interceptVersionAndSetToPrime() {
return cy.intercept('GET', '/rancherversion', {
statusCode: 200,
body: {
Version: '9bf6631da',
GitCommit: '9bf6631da',
RancherPrime: 'true'
}
});
}

describe('Prime Extension', { testIsolation: 'off', tags: ['@generic', '@adminUser'] }, () => {
const authProviderPo = new AuthProviderPo('local');
const azureadPo = new AzureadPo('local');

before(() => {
interceptVersionAndSetToPrime().as('rancherVersion');
cy.login();
HomePagePo.goTo();
});

it('should have prime doc link in the links panel', () => {
HomePagePo.navTo();
homePage.waitForPage();
homePage.supportLinks().eq(0).should('have.attr', 'href').and('satisfy', (href: string) => href.indexOf(PRIME_DOCS_BASE) === 0);
});

it('should have prime doc link in a page that renders a doc link from i18n', () => {
AuthProviderPo.navTo();
authProviderPo.waitForPage();
authProviderPo.selectAzureAd();
azureadPo.waitForPage();

azureadPo.permissionsWarningBanner().find('A').should('have.attr', 'href').and('satisfy', (href: string) => href.indexOf(PRIME_DOCS_BASE) === 0);
});
});
26 changes: 26 additions & 0 deletions pkg/rancher-prime/assets/rancher-prime.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions pkg/rancher-prime/babel.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
module.exports = require('./.shell/pkg/babel.config.js');
109 changes: 109 additions & 0 deletions pkg/rancher-prime/docs.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
import { IPlugin } from '@shell/core/types';

type DocStringMap = {[key:string]: string};

type DocReplacement = {
from: string;
to: string;
};

// String to use in doc references that should be replaced with the current Rancher version
const VERSION_MARKER = '$V$';

// We use an array like this because it is easier to see the from and to
// If we just used a map, the lines are so long, they are difficult to see and edit in the IDE
// This will be turned into a simpler map when we process them to replace the dynamic version number
const DOC_REPLACEMENTS = [
{
from: 'https://ranchermanager.docs.rancher.com/$V$',
to: 'https://documentation.suse.com/cloudnative/rancher-manager/$V$/en/about-rancher/what-is-rancher.html'
},
{
from: 'https://ranchermanager.docs.rancher.com/$V$/how-to-guides/new-user-guides/authentication-permissions-and-global-configuration/authentication-config#external-authentication-configuration-and-principal-users',
to: 'https://documentation.suse.com/cloudnative/rancher-manager/$V$/en/rancher-admin/users/authn-and-authz/authn-and-authz.html#_external_authentication_configuration_and_principal_users'
},
{
from: 'https://ranchermanager.docs.rancher.com/$V$/admin-settings/authentication/google/#3-creating-service-account-credential',
to: 'https://documentation.suse.com/cloudnative/rancher-manager/$V$/en/rancher-admin/users/authn-and-authz/configure-google-oauth.html#_3_creating_service_account_credentials'
},
{
from: 'https://ranchermanager.docs.rancher.com/$V$/monitoring-alerting/configuration/#alertmanager-configuration/',
to: 'https://documentation.suse.com/cloudnative/rancher-manager/$V$/en/observability/monitoring-and-dashboards/configuration/configuration.html#_alertmanager_configuration'
},
{
from: 'https://ranchermanager.docs.rancher.com/$V$/how-to-guides/new-user-guides/launch-kubernetes-with-rancher/rke1-vs-rke2-differences#cluster-api',
to: 'https://documentation.suse.com/cloudnative/rancher-manager/$V$/en/cluster-deployment/rke1-vs-rke2.html#_cluster_api'
},
{
from: 'https://ranchermanager.docs.rancher.com/how-to-guides/new-user-guides/kubernetes-clusters-in-rancher-setup/set-up-cloud-providers/amazon',
to: 'https://documentation.suse.com/cloudnative/rancher-manager/latest/en/cluster-deployment/set-up-cloud-providers/amazon.html'
},
{
from: 'https://ranchermanager.docs.rancher.com/how-to-guides/new-user-guides/kubernetes-clusters-in-rancher-setup/set-up-cloud-providers/azure',
to: 'https://documentation.suse.com/cloudnative/rancher-manager/latest/en/cluster-deployment/set-up-cloud-providers/azure.html'
},
{
from: 'https://ranchermanager.docs.rancher.com/reference-guides/cluster-configuration/rancher-server-configuration/rke2-cluster-configuration#additionalmanifest',
to: 'https://documentation.suse.com/cloudnative/rancher-manager/latest/en/cluster-deployment/configuration/k3s.html#_additionalmanifest',
},
{
from: 'https://ranchermanager.docs.rancher.com/$V$/integrations-in-rancher/logging/logging-helm-chart-options',
to: 'https://documentation.suse.com/cloudnative/rancher-manager/$V$/en/observability/logging/logging-helm-chart-options.html'
},
{
from: 'https://ranchermanager.docs.rancher.com/$V$/monitoring-alerting/',
to: 'https://documentation.suse.com/cloudnative/rancher-manager/$V$/en/observability/monitoring-and-dashboards/monitoring-and-dashboards.html',
},
{
from: 'https://ranchermanager.docs.rancher.com/$V$/reference-guides/cluster-configuration/rancher-server-configuration/aks-cluster-configuration#support-private-kubernetes-service',
to: 'https://documentation.suse.com/cloudnative/rancher-manager/$V$/en/cluster-deployment/hosted-kubernetes/aks/configuration.html#_support_private_kubernetes_service'
},
{
from: 'https://ranchermanager.docs.rancher.com/how-to-guides/new-user-guides/kubernetes-clusters-in-rancher-setup/set-up-clusters-from-hosted-kubernetes-providers/gke',
to: 'https://documentation.suse.com/cloudnative/rancher-manager/latest/en/cluster-deployment/hosted-kubernetes/gke/gke.html'
},
{
from: 'https://docs.rke2.io/install/containerd_registry_configuration',
to: 'https://documentation.suse.com/cloudnative/rke2/latest/en/install/containerd_registry_configuration.html'
},
{
from: 'https://docs.rke2.io/security/hardening_guide',
to: 'https://documentation.suse.com/cloudnative/rke2/latest/en/security/hardening_guide.html'
},
{
from: 'https://docs.k3s.io/installation/private-registry',
to: 'https://documentation.suse.com/cloudnative/k3s/latest/en/installation/private-registry.html'
nwmac marked this conversation as resolved.
Show resolved Hide resolved
},
{
from: 'https://docs.rke2.io/install/private_registry',
to: 'https://documentation.suse.com/cloudnative/rke2/latest/en/install/containerd_registry_configuration.html'
},
{
from: 'https://docs.harvesterhci.io/',
to: 'https://documentation.suse.com/cloudnative/virtualization/v1.3/en/introduction/overview.html'
},
];

// Map will be generated from the DOC_REPLACEMENTS array
const DOC_MAP: DocStringMap = {};

/**
* Installs a link handler that intercepts links and replaces the community links with the Rancher Prime
* documentation links
*/
export function installDocHandler(plugin: IPlugin) {
// Allow doc links to be intercepted
plugin.register('linkInterceptor', 'prime-doc-links', (link: string) => {
// Returning undefined will leave the link unchanged
return DOC_MAP[link];
});

// Initialize the documentation mapping, replacing the version marker with the current Rancher version
DOC_REPLACEMENTS.forEach((r: DocReplacement) => {
// Update the links for the current version of Rancher if required
const from = r.from.replaceAll(VERSION_MARKER, plugin.environment.docsVersion);
const to = r.to.replaceAll(VERSION_MARKER, plugin.environment.docsVersion);

DOC_MAP[from] = to;
});
}
22 changes: 22 additions & 0 deletions pkg/rancher-prime/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
// import { importTypes } from '@rancher/auto-import';
import { IPlugin } from '@shell/core/types';
import { installDocHandler } from './docs';

// Init the package
export default function(plugin: IPlugin) {
if (!plugin.environment.isPrime) {
return false;
}

// Auto-import model, detail, edit from the folders
// importTypes(plugin);

// Provide plugin metadata from package.json
plugin.metadata = require('./package.json');

// Built-in icon
plugin.metadata.icon = require('./assets/rancher-prime.svg');

// Add the handler that will intercept and replace doc links with their Prime doc counterpart
installDocHandler(plugin);
}
26 changes: 26 additions & 0 deletions pkg/rancher-prime/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
{
"name": "rancher-prime",
"description": "Provides customizations for Rancher Prime",
"version": "1.0.0",
"private": false,
"rancher": {
"annotations": {
"catalog.cattle.io/rancher-version": ">= v2.10.0",
"catalog.cattle.io/display-name": "Rancher Prime"
}
},

"engines": {
"node": ">=20.0.0"
},
"devDependencies": {
"@vue/cli-plugin-babel": "~5.0.0",
"@vue/cli-service": "~5.0.0",
"@vue/cli-plugin-typescript": "~5.0.0"
},
"browserslist": [
"> 1%",
"last 2 versions",
"not dead"
]
}
54 changes: 54 additions & 0 deletions pkg/rancher-prime/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
{
"compilerOptions": {
"allowJs": true,
"target": "esnext",
"module": "esnext",
"strict": true,
"jsx": "preserve",
"importHelpers": true,
"moduleResolution": "node",
"skipLibCheck": true,
"esModuleInterop": true,
"allowSyntheticDefaultImports": true,
"sourceMap": true,
"baseUrl": ".",
"preserveSymlinks": true,
"typeRoots": [
"../../node_modules",
"../../shell/types",
"./types"
],
"types": [
"node",
"webpack-env",
"@types/node",
"@types/jest",
"@types/lodash",
"rancher",
"shell"
],
"lib": [
"esnext",
"dom",
"dom.iterable",
"scripthost"
],
"paths": {
"@shell/*": [
"../../shell/*"
],
"@components/*": [
"@rancher/components/*"
]
}
},
"include": [
"**/*.ts",
"**/*.d.ts",
"**/*.tsx",
"**/*.vue"
],
"exclude": [
"../../node_modules"
]
}
1 change: 1 addition & 0 deletions pkg/rancher-prime/vue.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
module.exports = require('./.shell/pkg/vue.config')(__dirname);
7 changes: 6 additions & 1 deletion shell/components/CommunityLinks.vue
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import { SETTING } from '@shell/config/settings';
import { mapGetters } from 'vuex';
import { isRancherPrime } from '@shell/config/version';
import { fetchLinks } from '@shell/config/home-links';
import { processLink } from '@shell/plugins/clean-html';

// i18n-ignore footer.wechat.title, footer.wechat.modalText, footer.wechat.modalText2
export default {
Expand Down Expand Up @@ -77,7 +78,11 @@ export default {
all.push(...this.links.defaults.filter((link) => link.enabled));
}

return all;
// Process the links
return all.map((item) => ({
...item,
value: processLink(item.value)
}));
}
},
methods: {
Expand Down
6 changes: 5 additions & 1 deletion shell/config/version.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@
/**
* Store version data retrieved from the backend /rancherversion API
*/
let _versionData = { RancherPrime: 'false' };
let _versionData = {
Version: '',
RancherPrime: 'false',
GitCommit: '',
};
let _kubeVersionData = {};

export function isRancherPrime() {
Expand Down
15 changes: 14 additions & 1 deletion shell/core/plugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,12 @@ import {
LocationConfig,
ExtensionPoint,
TabLocation,
PluginRouteRecordRaw, RegisterStore, UnregisterStore, CoreStoreSpecifics, CoreStoreConfig, OnNavToPackage, OnNavAwayFromPackage, OnLogOut
PluginRouteRecordRaw, RegisterStore, UnregisterStore, CoreStoreSpecifics, CoreStoreConfig, OnNavToPackage, OnNavAwayFromPackage, OnLogOut,
ExtensionEnvironment
} from './types';
import coreStore, { coreStoreModule, coreStoreState } from '@shell/plugins/dashboard-store';
import { defineAsyncComponent, markRaw, Component } from 'vue';
import { getVersionData, CURRENT_RANCHER_VERSION } from '@shell/config/version';

export type ProductFunction = (plugin: IPlugin, store: any) => void;

Expand Down Expand Up @@ -57,6 +59,17 @@ export class Plugin implements IPlugin {
});
}

get environment(): ExtensionEnvironment {
const versionData = getVersionData();

return {
version: versionData.Version,
commit: versionData.GitCommit,
isPrime: versionData.RancherPrime === 'true',
docsVersion: `v${ CURRENT_RANCHER_VERSION }`
};
}

get metadata() {
return this._metadata;
}
Expand Down
Loading
Loading