@chapeaux/cpx-operator-graph
Advanced tools
Comparing version 0.4.3 to 0.5.0
@@ -6,3 +6,11 @@ "use strict"; | ||
const tmpl = `<style> | ||
:host { font-family: Red Hat Display, sans-serif; } | ||
:host { | ||
font-family: var(--cpxOGFontFamily, 'Red Hat Display', sans-serif); | ||
font-size: var(--cpxOGFontSize, 16px ); | ||
} | ||
h3 { | ||
font-family: var(--cpxOGH3FontFamily, 'Red Hat Display', sans-serif); | ||
font-weight: medium; | ||
font-size: var(--cpxOGH3FontSize, 20px); | ||
} | ||
.node { fill: transparent; stroke-width: var(--cpxOGStrokeWidth,3); stroke: var(--cpxOGDisconnectedColor, #d2d2d2); } | ||
@@ -26,3 +34,6 @@ .edges { fill: transparent; stroke-width: var(--cpxOGStrokeWidth,3); stroke: var(--cpxOGConnectedColor,#0266c8); } | ||
tbody td:nth-child(1) {} | ||
tbody th:nth-child(2) { color: var(--cpxOGConnectedColor, #0266c8); text-align: left; } | ||
tbody th:nth-child(2) { } | ||
tbody th:nth-child(2) label { color: var(--cpxOGConnectedColor, #0266c8); text-align: left; } | ||
tbody th:nth-child(2) input { opacity: 0; width:0; height:0; } | ||
tbody [active] th:nth-child(2) label { color: #333; font-weight: normal; } | ||
tbody td:nth-child(3) { text-align: right; } | ||
@@ -33,8 +44,8 @@ tbody td:nth-child(4) { padding-left: 24px; } | ||
.toggle { line-height: 25px; padding-left: 0; font-size: 16px; position:relative; } | ||
input[type=checkbox] { height: 0; width: 0; visibility: hidden; order: 2; } | ||
label { | ||
.toggle { justify-self: end; padding-right: 10em; font-size: var(--cpxOGToggleFontSize, 16px); } | ||
.toggle input[type=checkbox] { height: 0; width: 0; opacity: 0; } | ||
.toggle label { | ||
cursor: pointer; | ||
text-indent: 60px; | ||
font-size: 20px; | ||
font-size: var(--cpxOGToggleFontSize, 16px); | ||
width: 50px; | ||
@@ -45,5 +56,3 @@ height: 30px; | ||
border-radius: 25px; | ||
position: absolute; | ||
right: 8em; | ||
top: 0; | ||
position: relative; | ||
white-space: nowrap; | ||
@@ -54,3 +63,3 @@ line-height: 30px; | ||
label:after { | ||
.toggle label:after { | ||
content: ''; | ||
@@ -67,3 +76,3 @@ position: absolute; | ||
input:checked + label { | ||
.toggle input:checked + label { | ||
background: var(--cpxOGConnectedColor, #0266c8); | ||
@@ -73,5 +82,9 @@ color: #151515; | ||
input:checked + label:after { left: calc(100% - 7px); transform: translateX(-100%); } | ||
label:active:after { width: 33px; } | ||
.options { display: grid; grid-template-columns: 50% 50%; margin-bottom: 60px; } | ||
.toggle input:checked + label:after { left: calc(100% - 7px); transform: translateX(-100%); } | ||
.toggle label:active:after { width: 33px; } | ||
.options { | ||
display: grid; | ||
grid-template-columns: 1fr 3fr; | ||
margin-bottom: 60px; | ||
} | ||
</style> | ||
@@ -81,7 +94,7 @@ <section> | ||
<div class="options"> | ||
<pfe-select><select id="ocp_versions"></select></pfe-select> | ||
<pfe-select id="ocp_versions"><select></select></pfe-select> | ||
</div> | ||
<h3>Channel</h3> | ||
<div class="options"> | ||
<pfe-select><select id="channels"></select></pfe-select> | ||
<pfe-select id="channels"><select></select></pfe-select> | ||
<div class="toggle"> | ||
@@ -103,44 +116,19 @@ <input type="checkbox" name="all-channels" value="all" id="all-channels"> | ||
</table>`; | ||
function versionSelector(strings, csv, versions, all) { | ||
return `<tr> | ||
<td>Head</td> | ||
<th scope="row"> | ||
<input name="${csv.packageName}" type="radio" id="${csv.version}" /> | ||
<label for="${csv.version}">${csv.version}</label> | ||
</th> | ||
<td> | ||
${csv.replaces ? `Replaces: ${csv.replaces}` : ''} | ||
${csv.skips ? `Skips: ${csv.skips}` : ''} | ||
</td> | ||
<td><!-- INACTIVE ONLY IN --> | ||
<svg active inbound viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"> | ||
<g class="node"> | ||
<circle cx="20" cy="50" r="10"/> | ||
<circle class="active" cx="20" cy="50" r="3"/> | ||
<line class="inbound outbound" x1="10" y1="50" x2="30" y2="50"/> | ||
<line class="inbound" x1="5" y1="43" x2="35" y2="43" stroke="white" stroke-width="12"/> | ||
<line class="outbound" x1="5" y1="57" x2="35" y2="57" stroke="white" stroke-width="12"/> | ||
</g> | ||
<g class="edges"> | ||
<path d="M 31 53 C 50 58, 80 60, 80 100" /> | ||
<path d="M 31 53 C 50 58, 90 60, 90 100" /> | ||
</g> | ||
</svg> | ||
</td> | ||
<td>beta</td> | ||
</tr>`; | ||
class SkipRange { | ||
constructor(range) { | ||
Object.defineProperty(this, "min", { | ||
enumerable: true, | ||
configurable: true, | ||
writable: true, | ||
value: void 0 | ||
}); | ||
Object.defineProperty(this, "max", { | ||
enumerable: true, | ||
configurable: true, | ||
writable: true, | ||
value: void 0 | ||
}); | ||
range.split(' '); | ||
} | ||
} | ||
function setCurve(edge) { | ||
const edgeVerticalLength = edge.source().renderedPosition('x') - edge.target().renderedPosition('x'); | ||
const decreaseFactor = -0.1; | ||
const controlPointDistance = edgeVerticalLength * decreaseFactor; | ||
const controlPointDistances = [controlPointDistance, -1 * controlPointDistance]; | ||
edge.data('controlPointDistances', controlPointDistances.join(' ')); | ||
} | ||
class OperatorVersion { | ||
} | ||
class OperatorPackage { | ||
} | ||
class OperatorChannel { | ||
} | ||
class OperatorGraph { | ||
@@ -180,4 +168,68 @@ constructor() { | ||
} | ||
class OperatorBundle { | ||
constructor() { | ||
class OperatorVersion { | ||
constructor(op) { | ||
Object.defineProperty(this, "package", { | ||
enumerable: true, | ||
configurable: true, | ||
writable: true, | ||
value: void 0 | ||
}); | ||
Object.defineProperty(this, "channel_name", { | ||
enumerable: true, | ||
configurable: true, | ||
writable: true, | ||
value: void 0 | ||
}); | ||
Object.defineProperty(this, "csv_name", { | ||
enumerable: true, | ||
configurable: true, | ||
writable: true, | ||
value: void 0 | ||
}); | ||
Object.defineProperty(this, "latest_in_channel", { | ||
enumerable: true, | ||
configurable: true, | ||
writable: true, | ||
value: void 0 | ||
}); | ||
Object.defineProperty(this, "ocp_version", { | ||
enumerable: true, | ||
configurable: true, | ||
writable: true, | ||
value: void 0 | ||
}); | ||
Object.defineProperty(this, "version", { | ||
enumerable: true, | ||
configurable: true, | ||
writable: true, | ||
value: void 0 | ||
}); | ||
Object.defineProperty(this, "skips", { | ||
enumerable: true, | ||
configurable: true, | ||
writable: true, | ||
value: void 0 | ||
}); | ||
Object.defineProperty(this, "skip_range", { | ||
enumerable: true, | ||
configurable: true, | ||
writable: true, | ||
value: void 0 | ||
}); | ||
Object.defineProperty(this, "replaces", { | ||
enumerable: true, | ||
configurable: true, | ||
writable: true, | ||
value: void 0 | ||
}); | ||
Object.assign(this, op); | ||
if (op.skip_range) { | ||
this.skip_range = new SkipRange(op.skip_range); | ||
} | ||
} | ||
} | ||
class OperatorPackage { | ||
} | ||
class OperatorChannel { | ||
constructor(name, version) { | ||
Object.defineProperty(this, "versions", { | ||
@@ -187,5 +239,5 @@ enumerable: true, | ||
writable: true, | ||
value: new Set() | ||
value: new Map() | ||
}); | ||
Object.defineProperty(this, "channels", { | ||
Object.defineProperty(this, "name", { | ||
enumerable: true, | ||
@@ -196,12 +248,67 @@ configurable: true, | ||
}); | ||
Object.defineProperty(this, "index", { | ||
this.name = name; | ||
this.versions.set(version.version, version); | ||
} | ||
getVersions(ord) { | ||
return [...this.versions.keys()].sort((a, b) => (0, semver_parser_1.compareSemVer)(b, a)); | ||
} | ||
} | ||
class OperatorIndex { | ||
constructor(version, channel) { | ||
Object.defineProperty(this, "channels", { | ||
enumerable: true, | ||
configurable: true, | ||
writable: true, | ||
value: new Map() | ||
}); | ||
Object.defineProperty(this, "version", { | ||
enumerable: true, | ||
configurable: true, | ||
writable: true, | ||
value: void 0 | ||
}); | ||
this.version = version; | ||
this.channels.set(channel.name, channel); | ||
} | ||
getVersions() { } | ||
getChannels() { } | ||
getAllVersions() { | ||
const versions = new Map(); | ||
const chs = this.channels.forEach(ch => { | ||
ch.versions.forEach(v => { | ||
versions.set(v.version, v); | ||
}); | ||
}); | ||
const orderedVersions = [...versions.keys()].sort((a, b) => (0, semver_parser_1.compareSemVer)(b, a)); | ||
return orderedVersions; | ||
} | ||
} | ||
class OperatorBundle { | ||
constructor(data) { | ||
Object.defineProperty(this, "indices", { | ||
enumerable: true, | ||
configurable: true, | ||
writable: true, | ||
value: new Map() | ||
}); | ||
data.map(op => { | ||
const version = new OperatorVersion(op); | ||
const channel = new OperatorChannel(op.channel_name, version); | ||
const index = new OperatorIndex(op.ocp_version, channel); | ||
if (this.indices.has(index.version)) { | ||
if (this.indices.get(index.version).channels.has(channel.name)) { | ||
if (!this.indices.get(index.version).channels.get(channel.name).versions.has(version.version)) { | ||
this.indices.get(index.version).channels.get(channel.name).versions.set(version.version, version); | ||
} | ||
} | ||
else { | ||
this.indices.get(index.version).channels.set(channel.name, channel); | ||
} | ||
} | ||
else { | ||
this.indices.set(index.version, index); | ||
} | ||
}); | ||
} | ||
getChannelsByIndex(index) { } | ||
getVersionsByChannel(channel) { } | ||
} | ||
class CPXOperatorGraph extends HTMLElement { | ||
@@ -216,3 +323,3 @@ constructor(url) { | ||
}); | ||
Object.defineProperty(this, "_data", { | ||
Object.defineProperty(this, "bundle", { | ||
enumerable: true, | ||
@@ -223,25 +330,25 @@ configurable: true, | ||
}); | ||
Object.defineProperty(this, "_order", { | ||
Object.defineProperty(this, "_data", { | ||
enumerable: true, | ||
configurable: true, | ||
writable: true, | ||
value: "desc" | ||
value: [] | ||
}); | ||
Object.defineProperty(this, "_channel", { | ||
Object.defineProperty(this, "_order", { | ||
enumerable: true, | ||
configurable: true, | ||
writable: true, | ||
value: "" | ||
value: "desc" | ||
}); | ||
Object.defineProperty(this, "_channels", { | ||
Object.defineProperty(this, "_index", { | ||
enumerable: true, | ||
configurable: true, | ||
writable: true, | ||
value: new Map() | ||
value: "" | ||
}); | ||
Object.defineProperty(this, "_versions", { | ||
Object.defineProperty(this, "_channel", { | ||
enumerable: true, | ||
configurable: true, | ||
writable: true, | ||
value: new Map() | ||
value: "" | ||
}); | ||
@@ -280,40 +387,17 @@ Object.defineProperty(this, "_body", { | ||
this._data = val; | ||
if (this._data) { | ||
this._data.map(csv => { | ||
if (!this.versions.has(csv.version)) { | ||
this.versions.set(csv.version, new Set(csv.version)); | ||
} | ||
else { | ||
if (!this.versions.get(csv.version).has(csv.version)) { | ||
this.versions.get(csv.version).add(csv.version); | ||
} | ||
} | ||
if (this.channels.has(csv.channel_name)) { | ||
const channelInfo = this.channels.get(csv.channel_name); | ||
channelInfo.push(csv); | ||
this.channels.set(csv.channel_name, channelInfo); | ||
} | ||
else { | ||
this.channels.set(csv.channel_name, [csv]); | ||
} | ||
}); | ||
this.channels.forEach((versions, channel, d) => { | ||
d.set(channel, versions.sort((a, b) => { | ||
const ord = { desc: 1, asc: -1 }; | ||
return (0, semver_parser_1.compareSemVer)(b['version'], a['version']) * ord[this.order]; | ||
})); | ||
}); | ||
} | ||
this.bundle = new OperatorBundle(this._data); | ||
this.shadowRoot.innerHTML = tmpl; | ||
this.render(); | ||
if (this.channels.size > 0) { | ||
const channelSelect = this.shadowRoot.querySelector('#channels'); | ||
[...this.channels.keys()].forEach(channel => { | ||
if (this.bundle.indices.size > 0) { | ||
const indexSelect = this.shadowRoot.querySelector('#ocp_versions select'); | ||
[...this.bundle.indices.keys()].sort().forEach(index => { | ||
const opt = document.createElement('option'); | ||
opt.innerHTML = channel; | ||
opt.setAttribute('value', channel); | ||
if (this.channel === channel) { | ||
opt.innerHTML = index; | ||
opt.setAttribute('value', index); | ||
if (this.index === index) { | ||
this.index = index; | ||
this.setChannels(); | ||
opt.setAttribute('selected', 'selected'); | ||
} | ||
channelSelect.appendChild(opt); | ||
indexSelect.appendChild(opt); | ||
}); | ||
@@ -330,4 +414,15 @@ } | ||
} | ||
get index() { | ||
return this._index !== "" ? this._index : [...this.bundle.indices.keys()][0]; | ||
} | ||
set index(val) { | ||
if (this._index === val) | ||
return; | ||
this._index = val; | ||
this.setAttribute('index', this._index); | ||
this.setChannels(); | ||
this.render(); | ||
} | ||
get channel() { | ||
return this._channel !== "" ? this._channel : [...this.channels.keys()][0]; | ||
return this._channel !== "" ? this._channel : [...this.bundle.indices.get(this.index).channels.keys()][0]; | ||
} | ||
@@ -341,18 +436,2 @@ set channel(val) { | ||
} | ||
get channels() { | ||
return this._channels; | ||
} | ||
set channels(val) { | ||
if (this._channels === val) | ||
return; | ||
this._channels = val; | ||
} | ||
get versions() { | ||
return this._versions; | ||
} | ||
set versions(val) { | ||
if (this._versions === val) | ||
return; | ||
this._versions = val; | ||
} | ||
get body() { | ||
@@ -365,9 +444,16 @@ if (!this._body) { | ||
connectedCallback() { | ||
this.addEventListener('pfe-select:change', evt => this.channel = evt['detail'].value); | ||
this.shadowRoot.addEventListener('pfe-select:change', evt => { | ||
if (evt.target['id'] === 'ocp_versions') { | ||
this.index = evt['detail'].value; | ||
} | ||
else if (evt.target['id'] === 'channels') { | ||
this.channel = evt['detail'].value; | ||
} | ||
}); | ||
} | ||
static get observedAttributes() { | ||
return ["url", "filter", "query", "sort", "order", "group", "channel"]; | ||
return ["url", "order", "channel", "index"]; | ||
} | ||
attributeChangedCallback(name, oldVal, newVal) { | ||
this[name] = newVal; | ||
attributeChangedCallback(attr, oldVal, newVal) { | ||
this[attr] = newVal; | ||
} | ||
@@ -381,18 +467,62 @@ handleClick(id) { | ||
this.shadowRoot.getElementById(id).setAttribute('active', ''); | ||
const activeInput = this.shadowRoot.querySelector(`[active] input`); | ||
activeInput['click'](); | ||
activeInput['focus'](); | ||
}; | ||
} | ||
setChannels() { | ||
this.channel = ""; | ||
if (this.bundle && this.bundle.indices) { | ||
if (this.bundle.indices.get(this.index).channels.size > 0) { | ||
const channelSelect = this.shadowRoot.querySelector('#channels select'); | ||
while (channelSelect.firstChild) { | ||
channelSelect.removeChild(channelSelect.firstChild); | ||
} | ||
[...this.bundle.indices.get(this.index).channels.keys()].sort().forEach(channel => { | ||
const opt = document.createElement('option'); | ||
opt.innerHTML = channel; | ||
opt.setAttribute('value', channel); | ||
if (this.channel === channel) { | ||
this.channel = channel; | ||
opt.setAttribute('selected', 'selected'); | ||
} | ||
channelSelect.appendChild(opt); | ||
}); | ||
} | ||
} | ||
} | ||
render(all) { | ||
if (this.channels.size > 0) { | ||
if (!all) { | ||
if (this.channels.get(this.channel)) { | ||
while (this.body.firstChild) { | ||
this.body.removeChild(this.body.firstChild); | ||
} | ||
this.channels.get(this.channel).forEach(csv => { | ||
if (this.bundle && this.bundle.indices) { | ||
const currIndex = this.bundle.indices.get(this.index); | ||
const currChannel = this.bundle.indices.get(this.index).channels.get(this.channel); | ||
if (currIndex && currChannel && currChannel.versions.size > 0) { | ||
while (this.body.firstChild) { | ||
this.body.removeChild(this.body.firstChild); | ||
} | ||
if (!all) { | ||
currChannel.getVersions().map(ver => { | ||
const csv = currChannel.versions.get(ver); | ||
const escVer = ver.replaceAll('.', ''); | ||
const escChannel = currChannel.name.replaceAll('.', ''); | ||
const verChannels = []; | ||
currIndex.channels.forEach(ch => { | ||
if (ch.name !== csv.channel_name && ch.versions.has(csv.version)) { | ||
verChannels.push(ch.name); | ||
} | ||
}); | ||
const row = document.createElement('tr'); | ||
row.id = csv['_id']; | ||
row.onclick = this.handleClick(row.id); | ||
if (csv.latest_in_channel && csv.replaces !== null) { | ||
row.setAttribute('inbound', ''); | ||
} | ||
if (csv.replaces === null) { | ||
row.setAttribute('outbound', ''); | ||
} | ||
row.innerHTML = `<td></td> | ||
<th scope="row">${csv['version']}</th> | ||
<td>${csv['replaces'] || ''}</td> | ||
<th scope="row"><label for="${escVer}">${csv['version']}</label><input type="radio" id="${escVer}" name="${escChannel}" value="${csv['version']}"></th> | ||
<td> | ||
${csv['replaces'] ? `Replaces: ${csv['replaces'].replace(csv.package + '.', '')}` : ''} | ||
${csv.skips && csv.skips.length ? `Skips: ${csv.skips.join(',')}` : ''} | ||
</td> | ||
<td><svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"> | ||
@@ -408,6 +538,8 @@ <g class="node"> | ||
</svg></td> | ||
<td>${csv['channels'] || ''}</td>`; | ||
<td>${verChannels.join(', ')}</td>`; | ||
this.body.appendChild(row); | ||
}); | ||
} | ||
else { | ||
} | ||
} | ||
@@ -414,0 +546,0 @@ } |
import { compareSemVer } from 'https://cdn.skypack.dev/semver-parser'; | ||
const tmpl = `<style> | ||
:host { font-family: Red Hat Display, sans-serif; } | ||
:host { | ||
font-family: var(--cpxOGFontFamily, 'Red Hat Display', sans-serif); | ||
font-size: var(--cpxOGFontSize, 16px ); | ||
} | ||
h3 { | ||
font-family: var(--cpxOGH3FontFamily, 'Red Hat Display', sans-serif); | ||
font-weight: medium; | ||
font-size: var(--cpxOGH3FontSize, 20px); | ||
} | ||
.node { fill: transparent; stroke-width: var(--cpxOGStrokeWidth,3); stroke: var(--cpxOGDisconnectedColor, #d2d2d2); } | ||
@@ -22,3 +30,6 @@ .edges { fill: transparent; stroke-width: var(--cpxOGStrokeWidth,3); stroke: var(--cpxOGConnectedColor,#0266c8); } | ||
tbody td:nth-child(1) {} | ||
tbody th:nth-child(2) { color: var(--cpxOGConnectedColor, #0266c8); text-align: left; } | ||
tbody th:nth-child(2) { } | ||
tbody th:nth-child(2) label { color: var(--cpxOGConnectedColor, #0266c8); text-align: left; } | ||
tbody th:nth-child(2) input { opacity: 0; width:0; height:0; } | ||
tbody [active] th:nth-child(2) label { color: #333; font-weight: normal; } | ||
tbody td:nth-child(3) { text-align: right; } | ||
@@ -29,8 +40,8 @@ tbody td:nth-child(4) { padding-left: 24px; } | ||
.toggle { line-height: 25px; padding-left: 0; font-size: 16px; position:relative; } | ||
input[type=checkbox] { height: 0; width: 0; visibility: hidden; order: 2; } | ||
label { | ||
.toggle { justify-self: end; padding-right: 10em; font-size: var(--cpxOGToggleFontSize, 16px); } | ||
.toggle input[type=checkbox] { height: 0; width: 0; opacity: 0; } | ||
.toggle label { | ||
cursor: pointer; | ||
text-indent: 60px; | ||
font-size: 20px; | ||
font-size: var(--cpxOGToggleFontSize, 16px); | ||
width: 50px; | ||
@@ -41,5 +52,3 @@ height: 30px; | ||
border-radius: 25px; | ||
position: absolute; | ||
right: 8em; | ||
top: 0; | ||
position: relative; | ||
white-space: nowrap; | ||
@@ -50,3 +59,3 @@ line-height: 30px; | ||
label:after { | ||
.toggle label:after { | ||
content: ''; | ||
@@ -63,3 +72,3 @@ position: absolute; | ||
input:checked + label { | ||
.toggle input:checked + label { | ||
background: var(--cpxOGConnectedColor, #0266c8); | ||
@@ -69,5 +78,9 @@ color: #151515; | ||
input:checked + label:after { left: calc(100% - 7px); transform: translateX(-100%); } | ||
label:active:after { width: 33px; } | ||
.options { display: grid; grid-template-columns: 50% 50%; margin-bottom: 60px; } | ||
.toggle input:checked + label:after { left: calc(100% - 7px); transform: translateX(-100%); } | ||
.toggle label:active:after { width: 33px; } | ||
.options { | ||
display: grid; | ||
grid-template-columns: 1fr 3fr; | ||
margin-bottom: 60px; | ||
} | ||
</style> | ||
@@ -77,7 +90,7 @@ <section> | ||
<div class="options"> | ||
<pfe-select><select id="ocp_versions"></select></pfe-select> | ||
<pfe-select id="ocp_versions"><select></select></pfe-select> | ||
</div> | ||
<h3>Channel</h3> | ||
<div class="options"> | ||
<pfe-select><select id="channels"></select></pfe-select> | ||
<pfe-select id="channels"><select></select></pfe-select> | ||
<div class="toggle"> | ||
@@ -99,44 +112,19 @@ <input type="checkbox" name="all-channels" value="all" id="all-channels"> | ||
</table>`; | ||
function versionSelector(strings, csv, versions, all) { | ||
return `<tr> | ||
<td>Head</td> | ||
<th scope="row"> | ||
<input name="${csv.packageName}" type="radio" id="${csv.version}" /> | ||
<label for="${csv.version}">${csv.version}</label> | ||
</th> | ||
<td> | ||
${csv.replaces ? `Replaces: ${csv.replaces}` : ''} | ||
${csv.skips ? `Skips: ${csv.skips}` : ''} | ||
</td> | ||
<td><!-- INACTIVE ONLY IN --> | ||
<svg active inbound viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"> | ||
<g class="node"> | ||
<circle cx="20" cy="50" r="10"/> | ||
<circle class="active" cx="20" cy="50" r="3"/> | ||
<line class="inbound outbound" x1="10" y1="50" x2="30" y2="50"/> | ||
<line class="inbound" x1="5" y1="43" x2="35" y2="43" stroke="white" stroke-width="12"/> | ||
<line class="outbound" x1="5" y1="57" x2="35" y2="57" stroke="white" stroke-width="12"/> | ||
</g> | ||
<g class="edges"> | ||
<path d="M 31 53 C 50 58, 80 60, 80 100" /> | ||
<path d="M 31 53 C 50 58, 90 60, 90 100" /> | ||
</g> | ||
</svg> | ||
</td> | ||
<td>beta</td> | ||
</tr>`; | ||
class SkipRange { | ||
constructor(range) { | ||
Object.defineProperty(this, "min", { | ||
enumerable: true, | ||
configurable: true, | ||
writable: true, | ||
value: void 0 | ||
}); | ||
Object.defineProperty(this, "max", { | ||
enumerable: true, | ||
configurable: true, | ||
writable: true, | ||
value: void 0 | ||
}); | ||
range.split(' '); | ||
} | ||
} | ||
function setCurve(edge) { | ||
const edgeVerticalLength = edge.source().renderedPosition('x') - edge.target().renderedPosition('x'); | ||
const decreaseFactor = -0.1; | ||
const controlPointDistance = edgeVerticalLength * decreaseFactor; | ||
const controlPointDistances = [controlPointDistance, -1 * controlPointDistance]; | ||
edge.data('controlPointDistances', controlPointDistances.join(' ')); | ||
} | ||
class OperatorVersion { | ||
} | ||
class OperatorPackage { | ||
} | ||
class OperatorChannel { | ||
} | ||
class OperatorGraph { | ||
@@ -176,4 +164,68 @@ constructor() { | ||
} | ||
class OperatorBundle { | ||
constructor() { | ||
class OperatorVersion { | ||
constructor(op) { | ||
Object.defineProperty(this, "package", { | ||
enumerable: true, | ||
configurable: true, | ||
writable: true, | ||
value: void 0 | ||
}); | ||
Object.defineProperty(this, "channel_name", { | ||
enumerable: true, | ||
configurable: true, | ||
writable: true, | ||
value: void 0 | ||
}); | ||
Object.defineProperty(this, "csv_name", { | ||
enumerable: true, | ||
configurable: true, | ||
writable: true, | ||
value: void 0 | ||
}); | ||
Object.defineProperty(this, "latest_in_channel", { | ||
enumerable: true, | ||
configurable: true, | ||
writable: true, | ||
value: void 0 | ||
}); | ||
Object.defineProperty(this, "ocp_version", { | ||
enumerable: true, | ||
configurable: true, | ||
writable: true, | ||
value: void 0 | ||
}); | ||
Object.defineProperty(this, "version", { | ||
enumerable: true, | ||
configurable: true, | ||
writable: true, | ||
value: void 0 | ||
}); | ||
Object.defineProperty(this, "skips", { | ||
enumerable: true, | ||
configurable: true, | ||
writable: true, | ||
value: void 0 | ||
}); | ||
Object.defineProperty(this, "skip_range", { | ||
enumerable: true, | ||
configurable: true, | ||
writable: true, | ||
value: void 0 | ||
}); | ||
Object.defineProperty(this, "replaces", { | ||
enumerable: true, | ||
configurable: true, | ||
writable: true, | ||
value: void 0 | ||
}); | ||
Object.assign(this, op); | ||
if (op.skip_range) { | ||
this.skip_range = new SkipRange(op.skip_range); | ||
} | ||
} | ||
} | ||
class OperatorPackage { | ||
} | ||
class OperatorChannel { | ||
constructor(name, version) { | ||
Object.defineProperty(this, "versions", { | ||
@@ -183,5 +235,5 @@ enumerable: true, | ||
writable: true, | ||
value: new Set() | ||
value: new Map() | ||
}); | ||
Object.defineProperty(this, "channels", { | ||
Object.defineProperty(this, "name", { | ||
enumerable: true, | ||
@@ -192,12 +244,67 @@ configurable: true, | ||
}); | ||
Object.defineProperty(this, "index", { | ||
this.name = name; | ||
this.versions.set(version.version, version); | ||
} | ||
getVersions(ord) { | ||
return [...this.versions.keys()].sort((a, b) => compareSemVer(b, a)); | ||
} | ||
} | ||
class OperatorIndex { | ||
constructor(version, channel) { | ||
Object.defineProperty(this, "channels", { | ||
enumerable: true, | ||
configurable: true, | ||
writable: true, | ||
value: new Map() | ||
}); | ||
Object.defineProperty(this, "version", { | ||
enumerable: true, | ||
configurable: true, | ||
writable: true, | ||
value: void 0 | ||
}); | ||
this.version = version; | ||
this.channels.set(channel.name, channel); | ||
} | ||
getVersions() { } | ||
getChannels() { } | ||
getAllVersions() { | ||
const versions = new Map(); | ||
const chs = this.channels.forEach(ch => { | ||
ch.versions.forEach(v => { | ||
versions.set(v.version, v); | ||
}); | ||
}); | ||
const orderedVersions = [...versions.keys()].sort((a, b) => compareSemVer(b, a)); | ||
return orderedVersions; | ||
} | ||
} | ||
class OperatorBundle { | ||
constructor(data) { | ||
Object.defineProperty(this, "indices", { | ||
enumerable: true, | ||
configurable: true, | ||
writable: true, | ||
value: new Map() | ||
}); | ||
data.map(op => { | ||
const version = new OperatorVersion(op); | ||
const channel = new OperatorChannel(op.channel_name, version); | ||
const index = new OperatorIndex(op.ocp_version, channel); | ||
if (this.indices.has(index.version)) { | ||
if (this.indices.get(index.version).channels.has(channel.name)) { | ||
if (!this.indices.get(index.version).channels.get(channel.name).versions.has(version.version)) { | ||
this.indices.get(index.version).channels.get(channel.name).versions.set(version.version, version); | ||
} | ||
} | ||
else { | ||
this.indices.get(index.version).channels.set(channel.name, channel); | ||
} | ||
} | ||
else { | ||
this.indices.set(index.version, index); | ||
} | ||
}); | ||
} | ||
getChannelsByIndex(index) { } | ||
getVersionsByChannel(channel) { } | ||
} | ||
export class CPXOperatorGraph extends HTMLElement { | ||
@@ -212,3 +319,3 @@ constructor(url) { | ||
}); | ||
Object.defineProperty(this, "_data", { | ||
Object.defineProperty(this, "bundle", { | ||
enumerable: true, | ||
@@ -219,25 +326,25 @@ configurable: true, | ||
}); | ||
Object.defineProperty(this, "_order", { | ||
Object.defineProperty(this, "_data", { | ||
enumerable: true, | ||
configurable: true, | ||
writable: true, | ||
value: "desc" | ||
value: [] | ||
}); | ||
Object.defineProperty(this, "_channel", { | ||
Object.defineProperty(this, "_order", { | ||
enumerable: true, | ||
configurable: true, | ||
writable: true, | ||
value: "" | ||
value: "desc" | ||
}); | ||
Object.defineProperty(this, "_channels", { | ||
Object.defineProperty(this, "_index", { | ||
enumerable: true, | ||
configurable: true, | ||
writable: true, | ||
value: new Map() | ||
value: "" | ||
}); | ||
Object.defineProperty(this, "_versions", { | ||
Object.defineProperty(this, "_channel", { | ||
enumerable: true, | ||
configurable: true, | ||
writable: true, | ||
value: new Map() | ||
value: "" | ||
}); | ||
@@ -276,40 +383,17 @@ Object.defineProperty(this, "_body", { | ||
this._data = val; | ||
if (this._data) { | ||
this._data.map(csv => { | ||
if (!this.versions.has(csv.version)) { | ||
this.versions.set(csv.version, new Set(csv.version)); | ||
} | ||
else { | ||
if (!this.versions.get(csv.version).has(csv.version)) { | ||
this.versions.get(csv.version).add(csv.version); | ||
} | ||
} | ||
if (this.channels.has(csv.channel_name)) { | ||
const channelInfo = this.channels.get(csv.channel_name); | ||
channelInfo.push(csv); | ||
this.channels.set(csv.channel_name, channelInfo); | ||
} | ||
else { | ||
this.channels.set(csv.channel_name, [csv]); | ||
} | ||
}); | ||
this.channels.forEach((versions, channel, d) => { | ||
d.set(channel, versions.sort((a, b) => { | ||
const ord = { desc: 1, asc: -1 }; | ||
return compareSemVer(b['version'], a['version']) * ord[this.order]; | ||
})); | ||
}); | ||
} | ||
this.bundle = new OperatorBundle(this._data); | ||
this.shadowRoot.innerHTML = tmpl; | ||
this.render(); | ||
if (this.channels.size > 0) { | ||
const channelSelect = this.shadowRoot.querySelector('#channels'); | ||
[...this.channels.keys()].forEach(channel => { | ||
if (this.bundle.indices.size > 0) { | ||
const indexSelect = this.shadowRoot.querySelector('#ocp_versions select'); | ||
[...this.bundle.indices.keys()].sort().forEach(index => { | ||
const opt = document.createElement('option'); | ||
opt.innerHTML = channel; | ||
opt.setAttribute('value', channel); | ||
if (this.channel === channel) { | ||
opt.innerHTML = index; | ||
opt.setAttribute('value', index); | ||
if (this.index === index) { | ||
this.index = index; | ||
this.setChannels(); | ||
opt.setAttribute('selected', 'selected'); | ||
} | ||
channelSelect.appendChild(opt); | ||
indexSelect.appendChild(opt); | ||
}); | ||
@@ -326,4 +410,15 @@ } | ||
} | ||
get index() { | ||
return this._index !== "" ? this._index : [...this.bundle.indices.keys()][0]; | ||
} | ||
set index(val) { | ||
if (this._index === val) | ||
return; | ||
this._index = val; | ||
this.setAttribute('index', this._index); | ||
this.setChannels(); | ||
this.render(); | ||
} | ||
get channel() { | ||
return this._channel !== "" ? this._channel : [...this.channels.keys()][0]; | ||
return this._channel !== "" ? this._channel : [...this.bundle.indices.get(this.index).channels.keys()][0]; | ||
} | ||
@@ -337,18 +432,2 @@ set channel(val) { | ||
} | ||
get channels() { | ||
return this._channels; | ||
} | ||
set channels(val) { | ||
if (this._channels === val) | ||
return; | ||
this._channels = val; | ||
} | ||
get versions() { | ||
return this._versions; | ||
} | ||
set versions(val) { | ||
if (this._versions === val) | ||
return; | ||
this._versions = val; | ||
} | ||
get body() { | ||
@@ -361,9 +440,16 @@ if (!this._body) { | ||
connectedCallback() { | ||
this.addEventListener('pfe-select:change', evt => this.channel = evt['detail'].value); | ||
this.shadowRoot.addEventListener('pfe-select:change', evt => { | ||
if (evt.target['id'] === 'ocp_versions') { | ||
this.index = evt['detail'].value; | ||
} | ||
else if (evt.target['id'] === 'channels') { | ||
this.channel = evt['detail'].value; | ||
} | ||
}); | ||
} | ||
static get observedAttributes() { | ||
return ["url", "filter", "query", "sort", "order", "group", "channel"]; | ||
return ["url", "order", "channel", "index"]; | ||
} | ||
attributeChangedCallback(name, oldVal, newVal) { | ||
this[name] = newVal; | ||
attributeChangedCallback(attr, oldVal, newVal) { | ||
this[attr] = newVal; | ||
} | ||
@@ -377,18 +463,62 @@ handleClick(id) { | ||
this.shadowRoot.getElementById(id).setAttribute('active', ''); | ||
const activeInput = this.shadowRoot.querySelector(`[active] input`); | ||
activeInput['click'](); | ||
activeInput['focus'](); | ||
}; | ||
} | ||
setChannels() { | ||
this.channel = ""; | ||
if (this.bundle && this.bundle.indices) { | ||
if (this.bundle.indices.get(this.index).channels.size > 0) { | ||
const channelSelect = this.shadowRoot.querySelector('#channels select'); | ||
while (channelSelect.firstChild) { | ||
channelSelect.removeChild(channelSelect.firstChild); | ||
} | ||
[...this.bundle.indices.get(this.index).channels.keys()].sort().forEach(channel => { | ||
const opt = document.createElement('option'); | ||
opt.innerHTML = channel; | ||
opt.setAttribute('value', channel); | ||
if (this.channel === channel) { | ||
this.channel = channel; | ||
opt.setAttribute('selected', 'selected'); | ||
} | ||
channelSelect.appendChild(opt); | ||
}); | ||
} | ||
} | ||
} | ||
render(all) { | ||
if (this.channels.size > 0) { | ||
if (!all) { | ||
if (this.channels.get(this.channel)) { | ||
while (this.body.firstChild) { | ||
this.body.removeChild(this.body.firstChild); | ||
} | ||
this.channels.get(this.channel).forEach(csv => { | ||
if (this.bundle && this.bundle.indices) { | ||
const currIndex = this.bundle.indices.get(this.index); | ||
const currChannel = this.bundle.indices.get(this.index).channels.get(this.channel); | ||
if (currIndex && currChannel && currChannel.versions.size > 0) { | ||
while (this.body.firstChild) { | ||
this.body.removeChild(this.body.firstChild); | ||
} | ||
if (!all) { | ||
currChannel.getVersions().map(ver => { | ||
const csv = currChannel.versions.get(ver); | ||
const escVer = ver.replaceAll('.', ''); | ||
const escChannel = currChannel.name.replaceAll('.', ''); | ||
const verChannels = []; | ||
currIndex.channels.forEach(ch => { | ||
if (ch.name !== csv.channel_name && ch.versions.has(csv.version)) { | ||
verChannels.push(ch.name); | ||
} | ||
}); | ||
const row = document.createElement('tr'); | ||
row.id = csv['_id']; | ||
row.onclick = this.handleClick(row.id); | ||
if (csv.latest_in_channel && csv.replaces !== null) { | ||
row.setAttribute('inbound', ''); | ||
} | ||
if (csv.replaces === null) { | ||
row.setAttribute('outbound', ''); | ||
} | ||
row.innerHTML = `<td></td> | ||
<th scope="row">${csv['version']}</th> | ||
<td>${csv['replaces'] || ''}</td> | ||
<th scope="row"><label for="${escVer}">${csv['version']}</label><input type="radio" id="${escVer}" name="${escChannel}" value="${csv['version']}"></th> | ||
<td> | ||
${csv['replaces'] ? `Replaces: ${csv['replaces'].replace(csv.package + '.', '')}` : ''} | ||
${csv.skips && csv.skips.length ? `Skips: ${csv.skips.join(',')}` : ''} | ||
</td> | ||
<td><svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"> | ||
@@ -404,6 +534,8 @@ <g class="node"> | ||
</svg></td> | ||
<td>${csv['channels'] || ''}</td>`; | ||
<td>${verChannels.join(', ')}</td>`; | ||
this.body.appendChild(row); | ||
}); | ||
} | ||
else { | ||
} | ||
} | ||
@@ -410,0 +542,0 @@ } |
{ | ||
"name": "@chapeaux/cpx-operator-graph", | ||
"version": "0.4.3", | ||
"version": "0.5.0", | ||
"description": "Chapeaux Operator Graph Component", | ||
@@ -32,3 +32,3 @@ "type": "module", | ||
"homepage": "https://github.com/chapeaux/cpx-components/components/cpx-operator-graph", | ||
"gitHead": "7fc3b7573b82d5e76e95ca2df0c32a28c8d62ac1", | ||
"gitHead": "e4651a50cdecf5ff12faa979877507f60e202b29", | ||
"dependencies": { | ||
@@ -35,0 +35,0 @@ "semver-parser": "^4.0.0" |
83625
7
1092