Skip to content

Commit

Permalink
Add product regional availability
Browse files Browse the repository at this point in the history
Fix #10
  • Loading branch information
steren committed Nov 2, 2023
1 parent 7649cf0 commit b7a4494
Show file tree
Hide file tree
Showing 4 changed files with 114 additions and 15 deletions.
2 changes: 2 additions & 0 deletions images/icons/checkbox-24px.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
34 changes: 28 additions & 6 deletions index.html
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,7 @@
box-sizing: inherit;
}

h1, h2 {
h1, h2, h3 {
font-style: normal;
font-weight: normal;
}
Expand All @@ -114,6 +114,10 @@
h2{
font-size: 1.25em;
}
h3{
font-size: 1em;
}


h1 .accent, h2 {
color: var(--blue-500)
Expand Down Expand Up @@ -280,6 +284,10 @@
background-image: url(images/icons/timer-24px.svg);
}

.weight-group.products {
background-image: url(images/icons/checkbox-24px.svg);
}

#results {
padding: 0;
list-style-position: inside;
Expand Down Expand Up @@ -460,13 +468,27 @@ <h2>Optimize for</h2>
<span class="weight-info">Not important</span>
<input type="range" id="latency" name="latency" min="0" max="10" class="weight">
<span class="weight-info">Important</span>

<div id="locations-group">
<label for="locations">Where is your traffic coming from?</label>
<select multiple id="locations" name="locations">
<option value="--current-location--" selected>Your current location</option>
</select>
</div>

</div>

<div id="locations-group">
<label for="locations"><h2>Where is your traffic coming from?</h2></label>
<select multiple id="locations" name="locations">
<option value="--current-location--" selected>Your current location</option>
</select>
<div class="weight-group products">
<details>
<summary><label for="products" class="weight-title">Product availability</label> <img src="images/icons/help_outline_black_24dp.svg" class="help" alt="A question mark" width="16" height="16"/></summary>
<p class="explanation">
Only regions where selected products are available will be suggested.
This list doesn't include <a href="https://cloud.google.com/about/locations#global-products">global products</a>.
Product availability is quickly changing, this tool is likely to not reflect the latest availability data.
For an official and up to date table of product regional availability, please refer to <a href="https://cloud.google.com/about/locations#regions">the official Google Cloud website</a>.
</p>
</details>
<select multiple id="products" name="products"></select>
</div>

</form>
Expand Down
69 changes: 63 additions & 6 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -37,12 +37,38 @@ async function initializeCountrySelect() {

const locationsSelect = document.getElementById('locations');
for (const country of countries) {
const option = document.createElement("option");
// Stoe the stringified object as option value.
// Store the stringified object as option value.
// Adding the actual values as data- attribute mighe be nicer.
option.value = JSON.stringify(country);
option.text = country.name;
locationsSelect.add(option);
locationsSelect.add(new Option(country.name, JSON.stringify(country)));
}
}

/**
* Should this product be selected by default?
* @param {String} product the proeuct to check
* @returns {boolean} true if product should be selected
*/
function defaultSelectedProduct(product) {
let defaultProducts = [
"Compute Engine",
"Cloud Storage",
"Google Kubernetes Engine",
"Cloud Run"
];
return defaultProducts.includes(product);
}

async function initializeProductSelect() {
let products;

await fetch("data/products.json")
.then(data => data.json())
.then(json => products = json);

const productsSelect = document.getElementById('products');

for (const product in products) {
productsSelect.add(new Option(product, JSON.stringify(products[product]), defaultSelectedProduct(product), defaultSelectedProduct(product)));
}
}

Expand Down Expand Up @@ -107,6 +133,8 @@ function bindListeners() {

document.getElementById('locations').addEventListener('change', recommendRegion);

document.getElementById('products').addEventListener('change', recommendRegion);

document.getElementById('share').addEventListener('click', () => {
navigator.share({
title: 'Google Cloud region recommender',
Expand Down Expand Up @@ -231,6 +259,34 @@ async function recommendRegion() {
}
}
}

// Array of allowed regions, based on selected products
params.allowedRegions = new Set();
// get currently selected products
const productSelect = document.getElementById('products');
if(productSelect.selectedIndex === -1) {
console.warn("No selected product");
} else {

// Start with all regions in which the first selected product is available
const firstSelectedOption = productSelect.selectedOptions[0];
const firstSelectionRegionsMap = JSON.parse(firstSelectedOption.value);
for (const region of Object.keys(firstSelectionRegionsMap)) {
if(firstSelectionRegionsMap[region]) {
params.allowedRegions.add(region);
}
}

// For all other selected products, remove from the previous set any region where it's not available
for (let o = 1; o < productSelect.selectedOptions.length; o++) {
const regionsMap = JSON.parse(productSelect.selectedOptions[o].value);
for (const region of Object.keys(regionsMap)) {
if(!regionsMap[region]) {
params.allowedRegions.delete(region);
}
}
}
}

// TODO: Should we always store params in URL? or only when user hits 'Share'?
// In any case, we need to handle the user coordinates in a special way:
Expand All @@ -251,6 +307,7 @@ if(window.location.hash) {
let urlParams = JSON.parse(decodeURIComponent(window.location.hash.slice(1)));
console.log('TODO: load URL params', urlParams);
}
initializeCountrySelect();
await initializeCountrySelect();
await initializeProductSelect();
bindListeners();
recommendRegion();
24 changes: 21 additions & 3 deletions region-optimizer.js
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,18 @@ function normalizeAttributes(map, attribute) {
}
}

/**
* Filter out any region from the results that isn't in the list of allowed regions
* @param {Set} allowedRegions set of allowed regions
* @param {Array} sortedResults array of results, sorted by score
*/
function keepOnlyAllowedRegionsFromResults(allowedRegions, sortedResults) {
return sortedResults.filter(result => allowedRegions.has(result.region));
}




function rankRegions(regions, inputs) {
let results = [];
let latencyData;
Expand Down Expand Up @@ -110,14 +122,19 @@ function rankRegions(regions, inputs) {
}
}

let resultSorted = results.sort(function (a, b) {
const resultSorted = results.sort(function (a, b) {
return b.score - a.score;
});

return resultSorted;
const resultFilteredSorted = keepOnlyAllowedRegionsFromResults(inputs.allowedRegions, resultSorted);

return resultFilteredSorted;
}

/*
@param regions: {
region: {}
}
@param inputs: {
weights: {
latency: 0.5,
Expand All @@ -126,7 +143,8 @@ function rankRegions(regions, inputs) {
},
locations: [
{latitude, longitude}
]
],
allowedRegions: ['us-central1', 'us-east1']
}
@return [{
region: 'us-central1',
Expand Down

0 comments on commit b7a4494

Please sign in to comment.