diff --git a/static/js/dashboard.js b/static/js/dashboard.js
deleted file mode 100644
index 3cb1d80fe..000000000
--- a/static/js/dashboard.js
+++ /dev/null
@@ -1,572 +0,0 @@
-class Badge {
-
- constructor(base, key, date) { // Class constructor
- this.base = base; // Class body/properties
- this.key = key; // Class body/properties
- const fields = key.split("-");
- this.pattern = fields[0];
- this.platform = fields[1];
- if ( fields[2] != "ci.json" ) {
- this.version = fields[2];
- } else {
- this.version = "";
- }
- this.date = date.substr(5, 5);
- }
-
- string() {
- return this.key;
- }
-
- getLabel(field) {
- if(field == "pattern") {
- return stringForKey(this.platform)+" "+this.version;
- }
- if(field == "platform") {
- return stringForKey(this.pattern)+" - "+this.version;
- }
- if(field == "version") {
- return stringForKey(this.pattern)+" : "+stringForKey(this.platform);
- }
- if(field == "date") {
- return stringForKey(this.pattern)+" : "+stringForKey(this.platform)+" "+this.version;
- }
- return stringForKey(this.pattern)+" : "+ stringForKey(this.platform)+" "+this.version+" @ "+ this.date;
- }
-
- getURI() {
- return this.base+"/"+this.key;
- }
-
- getJenkinsURI() {
- return jenkins_base_url(this.pattern)+"/job/"+jenkins_job(this.pattern, this.platform, this.version)+"/lastBuild/";
- }
-
- getJiraSearch() {
- return "https://issues.redhat.com/issues/?jql=project%3D%22Validated%20Patterns%22%20and%20labels%20in%20(ci-fail)%20and%20component%3D"+jira_component(this.pattern)+"%20and%20status%20not%20in%20(Closed)";
- }
-}
-
-function sleep(ms) {
- return new Promise(resolve => setTimeout(resolve, ms));
-}
-
-function filterBadges(badges, field, value) {
- if ( field === "date" ) {
- return badges.filter(badge => badge.date === value);
- }
- if ( field === "pattern" ) {
- return badges.filter(badge => badge.pattern === value);
- }
- if ( field === "platform" ) {
- return badges.filter(badge => badge.platform === value);
- }
- if ( field === "version" ) {
- return badges.filter(badge => badge.version === value);
- }
- return badges;
-}
-
-function rowTitle(field, value) {
- if ( field === "date" ) {
- return stringForKey(value);
- }
- if ( field === "pattern" ) {
- return stringForKey(value);
- }
- if ( field === "platform" ) {
- return stringForKey(value);
- }
- return value;
-}
-
-function get_shield_url(badge, label, links) {
- base = 'https://img.shields.io/endpoint?style=flat&logo=git&logoColor=white';
- // TODO: Replace the second link with the CI Job URL
- if ( links === "internal") {
- base = base +'&link='+ encodeURI(badge.getJenkinsURI()) + '&link=' + encodeURI(badge.getJiraSearch());
- } else {
- base = base +'&link='+ encodeURI(badge.getURI()) + '&link=' + encodeURI(repo_url(badge.pattern));
- }
- if ( label != "" ) {
- base = base +'&label='+ encodeURI(label);
- }
- return base + '&url=' + encodeURI(badge.getURI());
-}
-
-function get_key_url(color, label, links) {
- uri = 'https://validatedpatterns.io/'+color+'.json';
- base = 'https://img.shields.io/endpoint?style=flat&logo=git&logoColor=white';
-
- base = base +'&link='+ encodeURI("/") + '&link=' + encodeURI(uri);
- if ( label != "" ) {
- base = base +'&label='+ encodeURI(label);
- } else if ( links === "internal" ) {
- base = base +'&label='+ encodeURI("Job name with link");
- } else {
- base = base +'&label='+ encodeURI("Job name");
- }
- return base + '&url=' + encodeURI(uri);
-}
-
-function jira_component(pattern) {
- const dictionary = {
- aegitops: "ansible-edge",
- devsecops: "devsecops",
- manuela: "industrial-edge",
- mcgitops: "multicloud-gitops",
- medicaldiag: "medical-diagnosis"
- };
-
- if ( pattern in dictionary ) {
- return dictionary[pattern];
- }
- return pattern;
-}
-
-function jenkins_job(pattern, platform, version) {
- ciplatform = platform
- if ( platform == "azr" ) {
- ciplatform = "azure";
- }
-
- return pattern+"-"+ciplatform+"-ocp"+version+"-interop";
-}
-
-function jenkins_base_url(key) {
- const prefix = 'https://mps-jenkins-csb-mpqe.apps.ocp-c1.prod.psi.redhat.com/job/ValidatedPatterns';
- const dictionary = {
- aegitops: "AnsibleEdgeGitops",
- devsecops: "MulticlusterDevSecOps",
- manuela: "Manuela",
- mcgitops: "MultiCloudGitops",
- medicaldiag: "MedicalDiagnosis"
- };
-
- if ( key in dictionary ) {
- return prefix + '/job/' + dictionary[key];
- }
- return prefix;
-}
-
-function pattern_url(key) {
- const prefix = 'https://validatedpatterns.io/patterns/'
- const dictionary = {
- aegitops: "ansible-edge-gitops",
- devsecops: "devsecops",
- manuela: "industrial-edge",
- mcgitops: "multicloud-gitops",
- medicaldiag: "medical-diagnosis"
- };
-
- if ( key in dictionary ) {
- return prefix + dictionary[key] + '/';
- }
- return prefix + key + '/';
-}
-
-function repo_url(key) {
- const prefix = 'https://github.com/hybrid-cloud-patterns/'
- const dictionary = {
- aegitops: "ansible-edge-gitops",
- devsecops: "multicluster-devsecops",
- manuela: "industrial-edge",
- mcgitops: "multicloud-gitops",
- medicaldiag: "medical-diagnosis"
- };
-
- if ( key in dictionary ) {
- return prefix + dictionary[key] + '/';
- }
- return prefix + key + '/';
-}
-
-function stringForKey(key) {
- const dateRegex = /^(\d{2})-(\d{2})$/;
- const months = [
- "Jan",
- "Feb",
- "March",
- "April",
- "May",
- "June",
- "July",
- "Aug",
- "Sept",
- "Oct",
- "Nov",
- "Dec"
- ];
-
- const dictionary = {
- aegitops: "Ansible Edge",
- devsecops: "DevSecOps",
- manuela: "Industrial",
- mcgitops: "Core GitOps",
- medicaldiag: "Image Classification",
- azr: "Azure",
- gcp: "GCP",
- aws: "AWS"
- };
-
- if ( key in dictionary ) {
- return dictionary[key];
- }
-
- const matches = dateRegex.exec(key);
- if ( matches ) {
- monthIndex = parseInt(matches[1], 10) - 1;
- return months[monthIndex] + " "+ matches[2];
- }
- return key;
-}
-
-function getBadgeDate(xml) {
- parent = xml.parentNode;
- for (j = 0; j < parent.childNodes.length; j++) {
- if ( parent.childNodes[j].nodeName == "LastModified" ) {
- return parent.childNodes[j].childNodes[0].nodeValue;
- }
- }
- return "2033-03-22T16:45:47.966Z";
-}
-
-function getUniqueValues(badges, field){
- results = [];
- badges.forEach(b => {
- if (field == 'date' && ! results.includes(b.date) ) {
- results.push(b.date);
- } else if (field == 'platform' && ! results.includes(b.platform) ) {
- results.push(b.platform);
- } else if (field == 'pattern' && ! results.includes(b.pattern) ) {
- results.push(b.pattern);
- } else if (field == 'version' && b.version != "" && ! results.includes(b.version) ) {
- results.push(b.version);
- }
- });
-
- if ( field === "pattern" ) {
- return results.sort(function(a, b){return -1 * a.localeCompare(b)});
- } else if ( field === "version" ) {
- return results.sort(function(a, b){return -1 * a.localeCompare(b)});
- } else if ( field === "date" ) {
- return results.sort(function(a, b){return -1 * a.localeCompare(b)});
- }
-
- return results.sort();
-}
-
-function patternSort(a, b){
- if ( a.pattern != b.pattern ) {
- return a.pattern.localeCompare(b.pattern);
- }
- if ( a.platform != b.platform ) {
- return a.platform.localeCompare(b.platform);
- }
- if ( a.version != b.version ) {
- return -1 * a.version.localeCompare(b.version);
- }
- return -1 * a.date.localeCompare(b.date)
-}
-
-function patternVertSort(a, b){
- if ( a.version != b.version ) {
- return -1 * a.version.localeCompare(b.version);
- }
- if ( a.pattern != b.pattern ) {
- return a.pattern.localeCompare(b.pattern);
- }
- if ( a.platform != b.platform ) {
- return a.platform.localeCompare(b.platform);
- }
- return -1 * a.date.localeCompare(b.date)
-}
-
-function toCamelCase(str) {
- return str.replace(/(?:^\w|[A-Z]|\b\w|\s+)/g, function(match, index) {
- if (+match === 0) return ""; // or if (/\s+/.test(match)) for white spaces
- return index === 0 ? match.toLowerCase() : match.toUpperCase();
- });
-}
-
-function toTitleCase(str) {
- return str.replace(
- /\w\S*/g,
- function(txt) {
- return txt.charAt(0).toUpperCase() + txt.substr(1).toLowerCase();
- }
- );
-}
-
-function createKeyTable(rows, links) {
- //document.getElementById('data').innerHTML = 'Hello World!';
-
- tableText = "
";
- tableText = tableText + "
Key
";
- tableText = tableText + "
";
-
- tableText = tableText + "";
- rows.forEach(r => {
- tableText = tableText + "| | ";
- });
- tableText = tableText + "
";
-
- tableText = tableText + "
";
- return tableText;
-}
-
-function getContentPrefix() {
- prefix = ""
- if ( false ) {
- prefix = prefix + "";
- } else {
- prefix = prefix + " ";
- prefix = prefix + " ";
- prefix = prefix + " ";
- prefix = prefix + " ";
- }
- return prefix;
-}
-
-function getContentSuffix() {
- prefix = ""
- if ( false ) {
- prefix = prefix + " ";
- } else {
- prefix = prefix + " ";
- prefix = prefix + " ";
- prefix = prefix + " ";
- prefix = prefix + " ";
- }
- prefix = prefix + " | ";
- return prefix;
-}
-
-
-function createFilteredHorizontalTable(badges, field, value, titles, links = "public", max = 20) {
- //document.getElementById('data').innerHTML = 'Hello World!';
-
- tableText = "";
- if ( titles ) {
- tableText = tableText + "
"+toTitleCase("By "+field)+"
";
- }
- tableText = tableText + "
";
-
- rows = getUniqueValues(badges, field);
-
- rows.forEach(r => {
- pBadges = filterBadges(badges, field, r);
-
- tableText = tableText + "";
- if ( value == null && field == "pattern" ) {
- tableText = tableText + "| " + rowTitle(field, r) + " | ";
- } else if ( value == null ) {
- tableText = tableText + "" + rowTitle(field, r) + " | ";
- }
-
- let index = 0;
- max = 100;
- tableText = tableText + getContentPrefix();
-
- pBadges.forEach(b => {
- if ( pBadges.length > max && index >= max ) {
- tableText = tableText + "
";
- index = 0;
- }
-
- tableText = tableText + " "
- //tableText = tableText + "
"
- tableText = tableText + "";
- //tableText = tableText + " | ";
- tableText = tableText + " "
- index = index + 1;
- });
- tableText = tableText + getContentSuffix();
- tableText = tableText + "
";
- });
-
- return tableText + "
";
-}
-
-function createFilteredVerticalTable(badges, field, value, titles, links = "public") {
- //document.getElementById('data').innerHTML = 'Hello World!';
-
- tableText = "";
- if ( titles ) {
- tableText = tableText + "
"+toTitleCase("By "+field)+"
";
- }
- tableText = tableText + "
";
-
- //style='vertical-align:top'
- rows = getUniqueValues(badges, field);
-
- fieldColumns = [];
- tableText = tableText + "";
- rows.forEach(r => {
- fieldColumns.push(filterBadges(badges, field, r));
-
- // https://stackoverflow.com/questions/43775947/dynamically-generate-table-from-json-array-in-javascript
- if ( value == null && field != "date" ) {
- tableText = tableText + "| " + rowTitle(field, r) + " | ";
- }
- });
- tableText = tableText + "
";
-
- any = true;
- row = 0;
- numColumns = fieldColumns.length;
- while (any) {
- any = false;
- tableText = tableText + "";
- for ( i = 0; i < numColumns; i++) {
- blist = fieldColumns[i];
- tableText = tableText + "| ";
- if ( blist.length > row ) {
- b = blist[row];
- // console.log(b);
- tableText = tableText + "";
- any = true;
- }
- tableText = tableText + " | ";
- }
- tableText = tableText + "
";
- row = row + 1;
- }
-
- return tableText + "
";
-
-}
-
-function getBadges(xmlText, bucket_url, badge_set) {
- parser = new DOMParser();
- var xmlDoc = parser.parseFromString(xmlText, "application/xml");
- const errorNode = xmlDoc.querySelector("parsererror");
- if (errorNode) {
- // parsing failed
- console.log("failed: "+errorNode);
- return;
- }
-
- var badges = [];
- var entries = xmlDoc.getElementsByTagName("Key");
- // var entries = xmlDoc.childNodes.getElementsByTagName("Contents");
- // var entries = xmlDoc.childNodes;
- // document.getElementById("data").innerHTML = errorNode.childNodes[1].nodeValue;
-
- l = entries.length;
- console.log("processing +entries[0].nodeName+ "+l);
-
- for (i = 0; i < l; i++) {
- // entries[i].childNodes[0].nodeValue
- key = entries[i].childNodes[0].nodeValue;
-
- if (badge_set == "GA" && key.endsWith("stable-badge.json") ) {
- badges.push(new Badge(bucket_url, key, getBadgeDate(entries[i])));
- } else if (badge_set == "early" && key.endsWith("prerelease-badge.json") ) {
- badges.push(new Badge(bucket_url, key, getBadgeDate(entries[i])));
- } else if (badge_set == "all" && key.endsWith("-badge.json") ) {
- badges.push(new Badge(bucket_url, key, getBadgeDate(entries[i])));
- } else {
- console.log("Skipping: " + key + " - "+badge_set);
- }
- }
-
- return badges;
-}
-
-function processBucketXML(text, options) {
- const filter_field = options.get("filter_field");
- const filter_value = options.get("filter_value");
- const links = options.get("links");
- badges = getBadges(text, options.get('bucket'), options.get('sets'));
-
- htmlText = "";
-
- if (filter_field != null ) {
- if ( filter_value != null) {
- badges = filterBadges(badges, filter_field, filter_value);
- }
- badges.sort(patternSort);
- numElements = Math.min(Math.floor(window.innerWidth/140), 6);
- // if ( window.innerWidth < 1200 ) {
- // No left or right sidebar
- // numElements = Math.floor(window.innerWidth/140);
- // } else if ( window.innerWidth < 1450 ) {
- // No right sidebar
- // numElements = Math.floor((window.innerWidth-290)/140);
- // } else {
- // Left and right sidebar, but fixed inner width
- // numElements = Math.floor(832/140);
- // }
- htmlText = createFilteredHorizontalTable(badges, filter_field, filter_value, false, links, numElements);
-
- } else {
- htmlText = createKeyTable(["green", "yellow", "red"], links);
-
- badges.sort(function(a, b){return -1 * a.date.localeCompare(b.date)});
- htmlText = htmlText + createFilteredHorizontalTable(badges, "date", null, true, links, Math.floor((window.innerWidth-200)/200));
-
- badges.sort(patternVertSort);
- htmlText = htmlText + createFilteredHorizontalTable(badges, "pattern", null, true, links, Math.floor((window.innerWidth-200)/140));
- htmlText = htmlText + createFilteredVerticalTable(badges, "platform", null, true, links);
- htmlText = htmlText + createFilteredVerticalTable(badges, "version", null, true, links);
- }
- document.getElementById(options.get('target')).innerHTML = htmlText;
-}
-
-function getBucketOptions(input) {
- const options = new Map();
- const queryString = window.location.search;
- const urlParams = new URLSearchParams(queryString);
-
- options.set('sets', 'GA');
- options.set('links', 'public');
- options.set('target', 'dataset');
- options.set('bucket', 'https://storage.googleapis.com/hcp-results');
-
- // input.bucket , or input["bucket"]
-
- const fields = [ "sets", "bucket", "target", "filter_field", "filter_value", "links" ];
- for ( i=0; i < fields.length; i++) {
- const key = fields[i];
- var value = input[key];
- if ( value == null ) {
- value = urlParams.get(fields[i]);
- }
- if ( value != null ) {
- console.log(key, value);
- options.set(fields[i], value);
- }
- }
-
- const sections = [ "date", "version", "platform", "pattern" ];
-
- filter_field = options.get("filter_field");
- if ( filter_field == null ) {
- for ( i=0; i < sections.length; i++) {
- if ( urlParams.get(sections[i]) != null ) {
- options.set("filter_field", sections[i]);
- if (options.get("filter_value") == null && urlParams.get(sections[i]) != null) {
- options.set("filter_value", urlParams.get(sections[i]));
- }
- }
- }
- }
-
- console.log(options);
- return options;
-}
-
-function obtainBadges(inputs) {
- let req = new XMLHttpRequest();
- const options = getBucketOptions(inputs);
- req.open('GET', options.get('bucket'));
- req.onload = function() {
- if (req.status == 200) {
- processBucketXML(req.responseText, options);
- } else {
- console.log("Error: " + req.status);
- }
- }
- req.send();
-}
diff --git a/static/js/dashboard.v2.js b/static/js/dashboard.v2.js
index 8ac24c7f7..0b33a9cb4 100644
--- a/static/js/dashboard.v2.js
+++ b/static/js/dashboard.v2.js
@@ -4,30 +4,76 @@
class Badge {
- constructor (base, key, date) {
+ constructor(base, key, date) {
this.base = base
this.key = key
+ this._json = null
+ this.operator = 'N/A'
+ this.date = date.substr(0, 10)
+ this.pattern = ''
+ this.platform = ''
+ this.version = ''
+
+ if (isNewCiBadgeBase(base)) {
+ return
+ }
+
const fields = key.split('-')
this.pattern = fields[0]
this.platform = fields[1]
- if (fields[fields.length-2] == 'operator') {
- this.operator = fields[fields.length-5]
+ if (fields[fields.length - 2] == 'operator') {
+ this.operator = fields[fields.length - 5]
} else {
- this.operator = 'N/A'
+ this.operator = 'N/A'
}
if (fields[2] != 'ci.json') {
- this.version = fields[2]
+ this.version = fields[2]
} else {
- this.version = ''
+ this.version = ''
}
- this.date = date.substr(0, 10)
}
- string () {
+ applyJson(json) {
+ this._json = json
+
+ if (!isNewCiBadgeBase(this.base)) {
+ return this
+ }
+
+ var patternId = ciPatternIdFromJson(json, this.key)
+
+ if (patternId != null) {
+ this.pattern = patternId
+ }
+
+ var platform = normalizeInfraProvider(json.infraProvider)
+ if (platform != null && json.infraProvider) {
+ this.platform = platform
+ }
+
+ var version = ocpMajorMinor(json.openshiftVersion)
+ if (version != null) {
+ this.version = version
+ } else if (json.openshiftVersion != null && json.openshiftVersion !== '') {
+ this.version = String(json.openshiftVersion)
+ }
+
+ if (json.date != null && json.date !== '') {
+ this.date = String(json.date).substr(0, 10)
+ }
+
+ if (json.operator != null && json.operator !== '') {
+ this.operator = json.operator
+ }
+
+ return this
+ }
+
+ string() {
return this.key
}
- getURI () {
+ getURI() {
return this.base + '/' + this.key
}
}
@@ -36,18 +82,10 @@ class Badge {
// Helper Functions
// ============================================
-function getJiraSearch (pattern) {
- return 'https://issues.redhat.com/issues/?jql=project%3D%22Validated%20Patterns%22%20and%20labels%20in%20(ci-fail)%20and%20component%3D' + jira_component(pattern) + '%20and%20status%20not%20in%20(Closed)'
-}
-
-function sleep (ms) {
- return new Promise(resolve => setTimeout(resolve, ms))
-}
-
// Still present in badge buckets but no longer in the CI matrix (omit from dashboard)
var CI_DASHBOARD_EXCLUDED_OCP_VERSIONS = ['4.19']
-function excludeRetiredOcpVersionsFromDashboard (badges) {
+function excludeRetiredOcpVersionsFromDashboard(badges) {
if (!badges || badges.length === 0) {
return badges || []
}
@@ -56,7 +94,7 @@ function excludeRetiredOcpVersionsFromDashboard (badges) {
})
}
-function filterBadges (badges, field, value) {
+function filterBadges(badges, field, value) {
if (field === 'pattern') {
return badges.filter(badge => badge.pattern === value)
}
@@ -75,19 +113,6 @@ function filterBadges (badges, field, value) {
return badges
}
-function jira_component (pattern) {
- if (pattern == 'aegitops') {
- return 'ansible-edge'
- } else if (pattern == 'manuela') {
- return 'industrial-edge'
- } else if (pattern == 'mcgitops') {
- return 'multicloud-gitops'
- } else if (pattern == 'medicaldiag') {
- return 'medical-diagnosis'
- }
- return pattern
-}
-
// CI pattern keys for patterns in the Archived tier. Keep in sync with
// content/patterns/**/_index.* where tier: archived.
var ARCHIVED_CI_PATTERNS = {
@@ -132,7 +157,83 @@ var CI_PATTERN_DOC_SLUG = {
vsk: 'virtualization-starter-kit'
}
-function pattern_url (key) {
+// New CI badge bucket (S3 keys under ci-badges/) — distinct from legacy vp-results filenames.
+
+var NEW_CI_BADGE_KEY_PREFIX = "https://vp-qe-ci-badges"
+
+function isNewCiBadgeBase(base) {
+ return base != null && base.startsWith(NEW_CI_BADGE_KEY_PREFIX)
+}
+
+function normalizeInfraProvider(provider) {
+ if (provider == null || provider === '') {
+ return null
+ }
+ var p = String(provider).toLowerCase()
+ if (p === 'azure') {
+ return 'azr'
+ }
+ if (p === 'google' || p === 'gcp') {
+ return 'gcp'
+ }
+ if (p === 'amazon' || p === 'aws') {
+ return 'aws'
+ }
+ return p
+}
+
+function ocpMajorMinor(version) {
+ if (version == null || version === '') {
+ return null
+ }
+ var match = String(version).match(/^(\d+\.\d+)/)
+ return match ? match[1] : null
+}
+
+function badgeOcpVersion(badge) {
+ if (badge == null) {
+ return null
+ }
+ if (badge._json && badge._json.openshiftVersion) {
+ var fromJson = ocpMajorMinor(badge._json.openshiftVersion)
+ if (fromJson != null) {
+ return fromJson
+ }
+ }
+ if (badge.version != null && badge.version !== '' && badge.version !== 'none') {
+ return badge.version
+ }
+ return null
+}
+
+function ciPatternIdFromJson(json, key) {
+ if (json == null) {
+ return null
+ }
+ if (json.patternName == null || json.patternName === '') {
+ return null
+ }
+ var name = String(json.patternName).toLowerCase()
+ if (name === 'mcg') {
+ if (json.variant === 'hub') {
+ return 'mcgitops'
+ }
+ if (String(key).includes("-hosted-")) {
+
+ return 'mcgitopshcp'
+ }
+ if (String(key).includes("-single-")) {
+ return 'mcgitopsstandalone'
+ }
+ return 'mcgitops'
+ }
+ if (name === 'ansibleedgegitops' || name === 'ansible-edge' || name === 'aegitops') {
+ return 'aegitops'
+ }
+ return name
+}
+
+function pattern_url(key) {
if (key == null || key === '') {
return '/patterns/'
}
@@ -150,28 +251,58 @@ function pattern_url (key) {
return '/patterns/' + key + '/'
}
-function stringForKey (key) {
+function stringForKey(key) {
if (key == 'azr') {
return 'Azure'
}
+ if (key == 'agof') {
+ return 'AnsibleGitopsFramework'
+ }
+ if (key == 'coco') {
+ return 'CoCo'
+ }
if (key == 'gcp') {
return 'Google'
}
if (key == 'aws') {
- return 'Amazon'
+ return 'AWS'
}
if (key == 'aegitops') {
- return 'Ansible Edge'
+ return 'AnsibleEdgeGitops'
}
if (key == 'devsecops') {
return 'DevSecOps'
}
- if (key == 'manuela') {
- return 'Industrial'
+ if (key == 'manuela' || key == 'industrialedge') {
+ return 'IndustrialEdge'
}
if (key == 'mcgitops') {
return 'Core GitOps'
}
+ if (key == 'mcgitopshcp') {
+ return 'MultiCloudGitopsHypershift'
+ }
+ if (key == 'mcgitopsstandalone') {
+ return 'MultiCloudGitopsStandalone'
+ }
+ if (key == 'ragllm') {
+ return 'RAG-LLM'
+ }
+ if (key == 'travelops') {
+ return 'TravelOps'
+ }
+ if (key == 'layeredzerotrust') {
+ return 'LayeredZeroTrust'
+ }
+ if (key == 'hypershift') {
+ return 'Hypershift'
+ }
+ if (key == 'openshiftai') {
+ return 'OpenShiftAI'
+ }
+ if (key == 'patternsoperator') {
+ return 'PatternsOperator'
+ }
if (key == 'medicaldiag') {
return 'Medical Diagnosis'
}
@@ -190,30 +321,30 @@ function stringForKey (key) {
return key
}
-function getBadgeDate (xml) {
- parent = xml.parentNode
- for (j = 0; j < parent.childNodes.length; j++) {
+function getBadgeDate(xml) {
+ let parent = xml.parentNode
+ for (let j = 0; j < parent.childNodes.length; j++) {
if (parent.childNodes[j].nodeName == 'LastModified') {
- return parent.childNodes[j].childNodes[0].nodeValue
+ return parent.childNodes[j].childNodes[0].nodeValue
}
}
return '2033-03-22T16:45:47.966Z'
}
-function getUniqueValues (badges, field) {
- results = []
+function getUniqueValues(badges, field) {
+ let results = []
badges.forEach(b => {
if (field == 'date' && !results.includes(b.date)) {
- results.push(b.date)
+ results.push(b.date)
} else if (field == 'platform' && !results.includes(b.platform)) {
- results.push(b.platform)
+ results.push(b.platform)
} else if (field == 'pattern' && !results.includes(b.pattern)) {
- results.push(b.pattern)
+ results.push(b.pattern)
} else if (field == 'version' && b.version != '' && !results.includes(b.version)) {
- results.push(b.version)
+ results.push(b.version)
} else if (field == 'operator' && b.operator != '' && !results.includes(b.operator)) {
- results.push(b.operator)
+ results.push(b.operator)
}
})
@@ -228,7 +359,7 @@ function getUniqueValues (badges, field) {
return results.sort()
}
-function patternSort (a, b) {
+function patternSort(a, b) {
if (a.pattern != b.pattern) {
return a.pattern.localeCompare(b.pattern)
}
@@ -241,7 +372,7 @@ function patternSort (a, b) {
return -1 * a.date.localeCompare(b.date)
}
-function patternVertSort (a, b) {
+function patternVertSort(a, b) {
if (a.version != b.version) {
return -1 * a.version.localeCompare(b.version)
}
@@ -254,78 +385,68 @@ function patternVertSort (a, b) {
return -1 * a.date.localeCompare(b.date)
}
-function toCamelCase (str) {
- return str.replace(/(?:^\w|[A-Z]|\b\w|\s+)/g, function (match, index) {
- if (+match === 0) return ''
- return index === 0 ? match.toLowerCase() : match.toUpperCase()
- })
-}
-
-function toTitleCase (str) {
+function toTitleCase(str) {
return str.replace(
- /\w\S*/g,
- function (txt) {
- return txt.charAt(0).toUpperCase() + txt.substr(1).toLowerCase()
- }
- )
+ /\w\S*/g,
+ function (txt) {
+ return txt.charAt(0).toUpperCase() + txt.substr(1).toLowerCase()
+ }
+ )
}
// ============================================
// Network / JSON Fetching
// ============================================
-function jsonSuccess() {
- if (this.status < 200 || this.status >= 300) {
- console.warn('getJSON HTTP', this.status, this.responseURL)
- }
- this.callback.apply(this, this.arguments)
-}
-
-function jsonError() {
- console.error(this.statusText);
+function badgeStatusColor(badge) {
+ if (badge == null) return 'unavailable'
+ if (badge._json != null && badge._json.color) return badge._json.color
+ if (badge._color) return badge._color
+ return 'unavailable'
}
-function parseBadgeJsonResponseText (text) {
- if (text == null) return null
- var t = String(text).replace(/^\uFEFF/, '').trim()
- if (t.length === 0) return null
- var first = t.charCodeAt(0)
- if (first === 0x3C) return null // '<' — XML/HTML/S3 error bodies
- try {
- return JSON.parse(t)
- } catch (e) {
- return null
+function enrichBadgesFromJson(badges) {
+ if (!badges || badges.length === 0) {
+ return Promise.resolve(badges || [])
}
-}
-
-function getJSON(url, callback, ...args) {
- const jsonRequest = new XMLHttpRequest();
- jsonRequest.callback = callback;
- jsonRequest.arguments = args;
- jsonRequest.onload = jsonSuccess;
- jsonRequest.onerror = jsonError;
- jsonRequest.open("GET", url, true);
- jsonRequest.send(null);
+ return Promise.all(badges.map(function (badge) {
+ return fetch(badge.getURI())
+ .then(function (response) {
+ if (!response.ok) {
+ throw new Error('HTTP error: ' + response.status)
+ }
+ return response.json()
+ })
+ .then(function (json) {
+ return badge.applyJson(json)
+ })
+ .catch(function (err) {
+ console.error('Fetch problem: ' + err.message + ' when fetching ' + badge.getURI())
+ return badge
+ })
+ })).then(function () {
+ return badges
+ })
}
// ============================================
// Legacy Badge Rendering (for pattern page embeds)
// ============================================
-function getLabel (field, json_obj) {
+function getLabel(field, badge) {
if (field == 'pattern') {
- return stringForKey(json_obj.infraProvider) + ' ' + json_obj.openshiftVersion
+ return platformDisplayName(badge._json.infraProvider) + ' ' + badge._json.openshiftVersion
}
if (field == 'platform') {
- return stringForKey(json_obj.patternName) + ' - ' + json_obj.openshiftVersion
+ return stringForKey(badge.pattern) + ' - ' + badge._json.openshiftVersion
}
if (field == 'version') {
- return stringForKey(json_obj.patternName) + ' : ' + stringForKey(json_obj.infraProvider)
+ return stringForKey(badge.pattern) + ' : ' + platformDisplayName(badge._json.infraProvider)
}
- return stringForKey(json_obj.patternName) + ' : ' + stringForKey(json_obj.infraProvider) + ' ' + json_obj.openshiftVersion
+ return stringForKey(badge.pattern) + ' : ' + platformDisplayName(badge._json.infraProvider) + ' ' + badge._json.openshiftVersion
}
-function rowTitle (field, value) {
+function rowTitle(field, value) {
if (field === 'pattern') {
return stringForKey(value)
}
@@ -335,112 +456,81 @@ function rowTitle (field, value) {
return value
}
-function renderSetButtons(sets){
- var currentURL = new URL(window.location.href)
- if (currentURL.searchParams.get('view') === 'classic') {
- ;['pattern', 'platform', 'version', 'date', 'sort'].forEach(function (k) {
- currentURL.searchParams.delete(k)
- })
- currentURL.searchParams.set('view', 'classic')
- }
- const queryString = window.location.search
- const urlParams = new URLSearchParams(queryString)
- var setList = {'GA': 'GA', 'early': 'Pre-release', 'all': 'All'}
- var buttonText = ""
- buttonText += ''
- return buttonText
-}
-
-function renderSingleBadge (key, field, linkType, badge_url) {
- var json_obj = parseBadgeJsonResponseText(this.responseText)
- if (json_obj == null) {
- var failedEl = document.getElementById(key + '-' + field)
- if (failedEl) {
- var fallbackLink = document.createElement('a')
- fallbackLink.href = badge_url
- fallbackLink.className = 'ci-label ci-label-load-error'
- fallbackLink.target = '_blank'
- fallbackLink.rel = 'noopener noreferrer'
- fallbackLink.textContent = 'Unavailable'
- fallbackLink.setAttribute('aria-label', 'Open badge URL in a new tab')
- failedEl.replaceWith(fallbackLink)
- }
- console.warn('Badge JSON parse failed:', badge_url)
- return
- }
- var branchLabel = json_obj.patternBranch
- var color = json_obj.color
-
- var envLabel = getLabel(field, json_obj)
- if (badge_url.endsWith("stable-badge.json") ) {
- var badgeClass = "ci-label-environment-stable";
- } else if (badge_url.endsWith("prerelease-badge.json") ) {
- var badgeClass = "ci-label-environment-prerelease";
- } else if (badge_url.endsWith("operator-badge.json") ) {
- var badgeClass = "ci-label-environment-prerelease";
- branchLabel = json_obj.triggerSource +" "+json_obj.triggerVersion;
- } else if (badge_url.endsWith("nightly-badge.json") ) {
- var badgeClass = "ci-label-environment-prerelease";
- branchLabel = "nightly ("+ json_obj.patternBranch+")";
- }
-
- if ( linkType == "internal") {
- envLink = json_obj.jenkinsURL
- branchLink = encodeURI(getJiraSearch(json_obj.patternName));
- } else {
- envLink = encodeURI(badge_url)
- branchLink = encodeURI(json_obj.patternRepo)
- }
-
- badgeText = ''
- if (envLink != null) {
- badgeText += '' + envLabel + ''
- } else {
- badgeText += '' + envLabel + ''
- }
- if (branchLink != null) {
- badgeText += '' + branchLabel + ''
+function renderSetButtons(sets) {
+ var currentURL = new URL(window.location.href)
+ if (currentURL.searchParams.get('view') === 'classic') {
+ ;['pattern', 'platform', 'version', 'date', 'sort'].forEach(function (k) {
+ currentURL.searchParams.delete(k)
+ })
+ currentURL.searchParams.set('view', 'classic')
+ }
+ var setList = { 'GA': 'GA', 'early': 'Pre-release', 'all': 'All' }
+ var buttonText = ""
+ buttonText += ''
+ return buttonText
}
-function renderBadgePlaceholder (key, field) {
- return ''
+function renderBadgeHtml(badge, field) {
+ let badge_url = badge.getURI()
+ let json_obj = badge._json
+ if (json_obj == null) {
+ return 'Unavailable'
+ }
+
+ let branchLabel = json_obj.patternBranch
+ let color = json_obj.color || 'green'
+ let envLabel = getLabel(field, badge)
+ let badgeClass = 'ci-label-environment-prerelease'
+
+ if (badge_url.endsWith('stable-badge.json')) {
+ badgeClass = 'ci-label-environment-stable'
+ } else if (badge_url.endsWith('operator-badge.json')) {
+ branchLabel = json_obj.triggerSource + ' ' + json_obj.triggerVersion
+ } else if (badge_url.endsWith('nightly-badge.json')) {
+ branchLabel = 'nightly (' + json_obj.patternBranch + ')'
+ }
+
+ let envLink = encodeURI(badge_url)
+ let branchLink = json_obj.patternRepo != null ? encodeURI(json_obj.patternRepo) : null
+ let badgeText = ''
+ badgeText += '' + envLabel + ''
+ if (branchLink != null) {
+ badgeText += '' + branchLabel + ''
+ } else {
+ badgeText += '' + branchLabel + ''
+ }
+ badgeText += ''
+ return badgeText
}
-function renderBadges (badges, field, value, links) {
+function renderBadges(badges, field, value) {
+ let pBadges = badges
if (field != null && value != null) {
- pBadges = filterBadges(badges, field, value)
- } else {
- pBadges = badges
+ pBadges = filterBadges(badges, field, value)
}
- badgeText = ''
- pBadges.forEach(b => {
- badgeText += renderBadgePlaceholder(b.string(), field)
- getJSON(b.getURI(), renderSingleBadge, b.string(), field, links, b.getURI())
+ let badgeText = '
'
+ pBadges.forEach(function (b) {
+ badgeText += renderBadgeHtml(b, field)
})
badgeText += '
'
return badgeText
}
-function legacyFilteredHref (field, rowValue) {
+function legacyFilteredHref(field, rowValue) {
var cur = new URLSearchParams(window.location.search)
if (cur.get('view') !== 'classic') {
return '?' + field + '=' + encodeURIComponent(rowValue)
@@ -453,38 +543,37 @@ function legacyFilteredHref (field, rowValue) {
return '?' + next.toString()
}
-function createFilteredHorizontalTable (badges, field, value, titles, links) {
- tableText = "
"
+function createFilteredHorizontalTable(badges, field, value, titles) {
+ let tableText = "
"
if (titles) {
tableText += "
- " + toTitleCase('By ' + field) + '
'
}
tableText += ""
- rows = getUniqueValues(badges, field)
+ let rows = getUniqueValues(badges, field)
tableText += "
"
rows.forEach(r => {
tableText += "'
})
tableText += '
'
return tableText + '
'
}
-function processBadgesLegacy (badges, options) {
+function processBadgesLegacy(badges, options) {
const filter_field = options.get('filter_field')
const filter_value = options.get('filter_value')
- const links = options.get("links")
var htmlText = ""
if (options.get('show_dashboard_tabs') === true) {
@@ -495,9 +584,9 @@ function processBadgesLegacy (badges, options) {
if (filter_field === 'date') {
badges.sort(function (a, b) { return -1 * a.date.localeCompare(b.date) })
if (filter_value != null && filter_value != "all") {
- htmlText += renderBadges(badges, filter_field, filter_value, links)
+ htmlText += renderBadges(badges, filter_field, filter_value)
} else if (filter_value == "all") {
- htmlText += createFilteredHorizontalTable(badges, filter_field, null, true, links)
+ htmlText += createFilteredHorizontalTable(badges, filter_field, null, true)
}
} else if (filter_field != null) {
if (filter_value != null && filter_value != "all") {
@@ -505,21 +594,21 @@ function processBadgesLegacy (badges, options) {
}
badges.sort(patternSort)
if (filter_value != null && filter_value != "all") {
- htmlText += renderBadges(badges, filter_field, filter_value, links)
+ htmlText += renderBadges(badges, filter_field, filter_value)
} else if (filter_value == "all") {
- htmlText += createFilteredHorizontalTable(badges, filter_field, null, true, links)
+ htmlText += createFilteredHorizontalTable(badges, filter_field, null, true)
}
} else {
// Classic home: same long-scroll layout as pre-redesign CI page — all groupings at once
badges.sort(function (a, b) { return -1 * a.date.localeCompare(b.date) })
badges.sort(patternVertSort)
- htmlText += createFilteredHorizontalTable(badges, 'date', null, true, links)
- htmlText += createFilteredHorizontalTable(badges, 'pattern', null, true, links)
- htmlText += createFilteredHorizontalTable(badges, 'platform', null, true, links)
- htmlText += createFilteredHorizontalTable(badges, 'version', null, true, links)
+ htmlText += createFilteredHorizontalTable(badges, 'date', null, true)
+ htmlText += createFilteredHorizontalTable(badges, 'pattern', null, true)
+ htmlText += createFilteredHorizontalTable(badges, 'platform', null, true)
+ htmlText += createFilteredHorizontalTable(badges, 'version', null, true)
var setsVal = options.get('sets') || 'GA'
if (String(setsVal).includes('all') || String(setsVal).includes('early')) {
- htmlText += createFilteredHorizontalTable(badges, 'operator', null, true, links)
+ htmlText += createFilteredHorizontalTable(badges, 'operator', null, true)
}
}
@@ -530,16 +619,16 @@ function processBadgesLegacy (badges, options) {
// New Dashboard Rendering (for CI status page)
// ============================================
-function statusLabel (color) {
+function statusLabel(color) {
if (color === 'green') return 'Passed'
if (color === 'yellow') return 'CI infrastructure failure'
if (color === 'red') return 'CI test failure'
return 'Unknown'
}
-function platformDisplayName (platform) {
+function platformDisplayName(platform) {
var names = {
- 'aws': 'AWS (us-east-1)',
+ 'aws': 'AWS',
'azr': 'Azure',
'gcp': 'Google Cloud',
'nutanix': 'Nutanix',
@@ -548,7 +637,7 @@ function platformDisplayName (platform) {
return names[platform] || stringForKey(platform)
}
-function platformIconSvg (platform) {
+function platformIconSvg(platform) {
if (platform === 'aws' || platform === 'gcp') {
return '
'
}
@@ -561,7 +650,7 @@ function platformIconSvg (platform) {
return '
'
}
-function timeAgo (dateStr) {
+function timeAgo(dateStr) {
if (!dateStr) return ''
var date = new Date(dateStr + 'T00:00:00')
var now = new Date()
@@ -584,24 +673,11 @@ function timeAgo (dateStr) {
return years + (years === 1 ? ' year ago' : ' years ago')
}
-function sanitizeId (str) {
+function sanitizeId(str) {
return str.replace(/\./g, '_').replace(/[^a-zA-Z0-9_-]/g, '-')
}
-function getLatestPerPatternPlatform (badges) {
- var seen = {}
- var result = []
- badges.forEach(function (b) {
- var compositeKey = b.pattern + '-' + b.platform
- if (!seen[compositeKey]) {
- seen[compositeKey] = true
- result.push(b)
- }
- })
- return result
-}
-
-function getCurrentTab () {
+function getCurrentTab() {
var params = new URLSearchParams(window.location.search)
if (params.get('view') === 'classic') return 'classic'
if (params.get('date') != null) return 'history'
@@ -615,11 +691,11 @@ function getCurrentTab () {
return 'overview'
}
-function buildTabUrl (paramKey) {
+function buildTabUrl(paramKey) {
var u = new URL(window.location.href)
- ;['pattern', 'platform', 'version', 'date', 'view'].forEach(function (k) {
- u.searchParams.delete(k)
- })
+ ;['pattern', 'platform', 'version', 'date', 'view'].forEach(function (k) {
+ u.searchParams.delete(k)
+ })
if (paramKey != null) {
u.searchParams.set(paramKey, 'all')
}
@@ -627,7 +703,7 @@ function buildTabUrl (paramKey) {
return u.pathname + (qs ? '?' + qs : '')
}
-function buildPatternDetailHref (pattern) {
+function buildPatternDetailHref(pattern) {
var u = new URL(window.location.href)
u.searchParams.delete('view')
u.searchParams.set('pattern', pattern)
@@ -635,17 +711,17 @@ function buildPatternDetailHref (pattern) {
return u.pathname + (qs ? '?' + qs : '')
}
-function buildClassicTabUrl () {
+function buildClassicTabUrl() {
var u = new URL(window.location.href)
- ;['pattern', 'platform', 'version', 'date', 'sort'].forEach(function (k) {
- u.searchParams.delete(k)
- })
+ ;['pattern', 'platform', 'version', 'date', 'sort'].forEach(function (k) {
+ u.searchParams.delete(k)
+ })
u.searchParams.set('view', 'classic')
var qs = u.searchParams.toString()
return u.pathname + (qs ? '?' + qs : '')
}
-function renderTabs (activeTab) {
+function renderTabs(activeTab) {
var tabs = [
{ id: 'overview', label: 'Overview', href: buildTabUrl(null) },
{ id: 'infrastructure', label: 'By Platform', href: buildTabUrl('platform') },
@@ -664,7 +740,7 @@ function renderTabs (activeTab) {
return html
}
-function renderSortControl (currentSort) {
+function renderSortControl(currentSort) {
var html = '