#81 coreos: Add stable stream
Merged 4 years ago by codeblock. Opened 4 years ago by rfairley.
fedora-web/ rfairley/websites rfairley-add-stable-stream  into  master

@@ -22,8 +22,9 @@ 

        </div>

      </div>

      <br>

-     <div id="coreos-download-app">

-     </div>

+   </div>

+   <div class="container">

+     <div id="coreos-download-app"></div>

    </div>

  </div>

  {% endblock %}

@@ -29,6 +29,12 @@ 

    "vmware": "VMware",

    "openstack": "OpenStack"

  }

+ // innerText of tab button

+ const tabInnerText = {

+   "cloud_launchable": "Cloud Launchable",

+   "metal_virt": "Bare Metal & Virtualized",

+   "cloud_operator": "For Cloud Operators"

+ }

  function getMember(obj, member) {

    return (member in obj) ? obj[member] : null;

  }
@@ -66,9 +72,9 @@ 

      downloads[download] = entry;

    }

  }

- 

  var coreos_download_app = new Vue({

    el: '#coreos-download-app',

+   created: function() { this.refreshStream() },

    data: {

      // currently selected stream

      stream: 'testing',
@@ -86,19 +92,103 @@ 

        virtualized: {},

        cloud: {}

      },

-     // innerText of tab button

-     tabInnerText: {

-       cloud_launchable: "Cloud Launchable",

-       metal_virt: "Bare Metal & Virtualized",

-       cloud_operator: "For Cloud Operators"

-     }

    },

-   created: function() { this.refreshStream() },

-   watch: { stream: 'refreshStream' },

+   watch: { stream: function() {

+     this.refreshStream();

+   } },

    methods: {

      getObjectUrl: function(path) {

        return getArtifactUrl(this.streamUrl, path);

      },

+     // Adapted from https://stackoverflow.com/a/6109105

+     timeSince: function(rfc3339_timestamp) {

+       var current = Date.now();

+       var timestamp = Date.parse(rfc3339_timestamp);

+       var elapsed = current - timestamp;

+       var msPerMinute = 60 * 1000;

+       var msPerHour = msPerMinute * 60;

+       var msPerDay = msPerHour * 24;

+       var msPerMonth = msPerDay * 30;

+       var msPerYear = msPerDay * 365;

+       function stringize(n, s) {

+         return n + ` ${s}` + (n == 1 ? "" : "s") + ' ago';

+       };

+       if (elapsed < msPerMinute) {

+         return stringize(Math.floor(elapsed/1000), "second");

+       } else if (elapsed < msPerHour) {

+         return stringize(Math.floor(elapsed/msPerMinute), "minute");

+       } else if (elapsed < msPerDay) {

+         return stringize(Math.floor(elapsed/msPerHour), "hour");

+       } else if (elapsed < msPerMonth) {

+         return stringize(Math.floor(elapsed/msPerDay), "day");

+       } else if (elapsed < msPerYear) {

+         return stringize(Math.floor(elapsed/msPerMonth), "month");

+       } else {

+         return stringize(Math.floor(elapsed/msPerYear), "year");

+       }

+     },

+     toggleHidden: function(e) {

+       const id_list = ['cloud-launchable', 'metal-virt', 'cloud-operator'];

+       switch(e.target.innerText) {

+         case tabInnerText.cloud_launchable:

+           show_id = 'cloud-launchable';

+           id_list.map(id => document.getElementById(id).hidden = (id !== show_id));

+           break;

+         case tabInnerText.metal_virt:

+           show_id = 'metal-virt';

+           id_list.map(id => document.getElementById(id).hidden = (id !== show_id));

+           break;

+         case tabInnerText.cloud_operator:

+           show_id = 'cloud-operator';

+           id_list.map(id => document.getElementById(id).hidden = (id !== show_id));

+           break;

+       }

+     },

+     getNavbar: function(h) {

+       cloud_icon = h('i', { class: "fas fa-cloud mr-2" })

+       nav_cloud_launchable_btn = h('button', { class: "nav-link active col-12 h-100 overflow-hidden", attrs: { "data-toggle": "tab" }, on: { click: this.toggleHidden } }, [ cloud_icon, tabInnerText.cloud_launchable ]);

+       nav_cloud_launchable = h('li', { class: "nav-item col-4" }, [ nav_cloud_launchable_btn ]);

+ 

+       server_icon = h('i', { class: "fas fa-server mr-2" })

+       nav_metal_virt_btn = h('button', { class: "nav-link col-12 h-100 overflow-hidden", attrs: { "data-toggle": "tab" }, on: { click: this.toggleHidden } }, [ server_icon, tabInnerText.metal_virt ]);

+       nav_metal_virt = h('li', { class: "nav-item col-4" }, [ nav_metal_virt_btn ]);

+ 

+       cloud_upload_icon = h('i', { class: "fas fa-cloud-upload-alt mr-2" })

+       nav_cloud_operator_btn = h('button', { class: "nav-link col-12 h-100 overflow-hidden", attrs: { "data-toggle": "tab" }, on: { click: this.toggleHidden } }, [ cloud_upload_icon, tabInnerText.cloud_operator ]);

+       nav_cloud_operator = h('li', { class: "nav-item col-4" }, [ nav_cloud_operator_btn ]);

+ 

+       navbar = h('ul', { class: "nav nav-tabs" }, [ nav_cloud_launchable, nav_metal_virt, nav_cloud_operator ]);

+       return navbar;

+     },

+     // Add dropdown options of streams

+     getStreamName: function(h) {

+       if (this.streamData === null) return;

+       option_default = h('option', { attrs: { value: "testing", selected: "selected" }}, "testing");

+       option_stable = h('option', { attrs: { value: "stable" }}, "stable");

+       selectOptions = h('select', {

+         class: "mx-1",

+         on: {

+           change: function(e) {

+             coreos_download_app.stream = e.target.value;

+           }

+         }

+       }, [

+         option_default,

+         option_stable

+       ]);

+       streamName = h('p', {}, [

+         "Stream: ",

+         selectOptions,

+         " (",

+         h('span', {}, [

+           h('a', { attrs: { href: this.getObjectUrl(this.stream + '.json') } }, "JSON")

+         ]),

+         ")",

+         (this.streamData.metadata) ? "—" : null,

+         (this.streamData.metadata) ? h('span', {}, this.timeSince(this.streamData.metadata['last-modified'])) : null

+       ]);

+       return streamName;

+     },

      isAws: function(platform) {

        return platform == "aws";

      },
@@ -194,7 +284,7 @@ 

        this.streamUrl = baseUrl

        fetchStreamData(this.streamUrl, this.stream).then(streamData => {

          this.loading = false;

-         this.streamData = streamData;

+         this.streamData = Object.entries(streamData).length === 0 && streamData.constructor === Object ? null : streamData;

          this.loadStreamDisplay();

        });

      },
@@ -218,82 +308,14 @@ 

          return false;

        }

        return artifact.downloads[contentType].showSignatureAndSha;

-     },

-     // Adapted from https://stackoverflow.com/a/6109105

-     timeSince: function(rfc3339_timestamp) {

-       var current = Date.now();

-       var timestamp = Date.parse(rfc3339_timestamp);

-       var elapsed = current - timestamp;

-       var msPerMinute = 60 * 1000;

-       var msPerHour = msPerMinute * 60;

-       var msPerDay = msPerHour * 24;

-       var msPerMonth = msPerDay * 30;

-       var msPerYear = msPerDay * 365;

-       function stringize(n, s) {

-         return n + ` ${s}` + (n == 1 ? "" : "s") + ' ago';

-       };

-       if (elapsed < msPerMinute) {

-         return stringize(Math.floor(elapsed/1000), "second");

-       } else if (elapsed < msPerHour) {

-         return stringize(Math.floor(elapsed/msPerMinute), "minute");

-       } else if (elapsed < msPerDay) {

-         return stringize(Math.floor(elapsed/msPerHour), "hour");

-       } else if (elapsed < msPerMonth) {

-         return stringize(Math.floor(elapsed/msPerDay), "day");

-       } else if (elapsed < msPerYear) {

-         return stringize(Math.floor(elapsed/msPerMonth), "month");

-       } else {

-         return stringize(Math.floor(elapsed/msPerYear), "year");

-       }

-     },

-     toggleHidden: function(e) {

-       const id_list = ['cloud-launchable', 'metal-virt', 'cloud-operator'];

-       switch(e.target.innerText) {

-         case this.tabInnerText.cloud_launchable:

-           show_id = 'cloud-launchable';

-           id_list.map(id => document.getElementById(id).hidden = (id !== show_id));

-           break;

-         case this.tabInnerText.metal_virt:

-           show_id = 'metal-virt';

-           id_list.map(id => document.getElementById(id).hidden = (id !== show_id));

-           break;

-         case this.tabInnerText.cloud_operator:

-           show_id = 'cloud-operator';

-           id_list.map(id => document.getElementById(id).hidden = (id !== show_id));

-           break;

-       }

-     },

-     getNavbar: function(h) {

-       nav_cloud_launchable_btn = h('button', { class: "nav-link active", attrs: { "data-toggle": "tab" }, on: { click: this.toggleHidden } }, this.tabInnerText.cloud_launchable);

-       nav_cloud_launchable = h('li', { class: "nav-item mr-3 ml-3" }, [ nav_cloud_launchable_btn ]);

- 

-       nav_metal_virt_btn = h('button', { class: "nav-link", attrs: { "data-toggle": "tab" }, on: { click: this.toggleHidden } }, this.tabInnerText.metal_virt);

-       nav_metal_virt = h('li', { class: "nav-item mr-3" }, [ nav_metal_virt_btn ]);

- 

-       nav_cloud_operator_btn = h('button', { class: "nav-link", attrs: { "data-toggle": "tab" }, on: { click: this.toggleHidden } }, this.tabInnerText.cloud_operator);

-       nav_cloud_operator = h('li', { class: "nav-item" }, [ nav_cloud_operator_btn ]);

- 

-       navbar = h('ul', { class: "nav nav-tabs" }, [ nav_cloud_launchable, nav_metal_virt, nav_cloud_operator ]);

-       return navbar

      }

    },

    render: function(h) {

+     var stream_select_container = h('div', { class: "pb-0 pt-3" }, [ h('div', { class: "container" }, [ this.getStreamName(h), this.getNavbar(h) ]) ]);

      if (this.loading) {

-       return h('div', {}, "Loading...");

+       return h('div', {}, [ stream_select_container, "Loading..."] );

      }

      else if (this.streamData) {

-       streamName = h('p', {}, [

-         "Stream: ",

-         h('span', { "class":"font-weight-bold" }, this.streamData.stream),

-         " (",

-         h('span', {}, [

-           h('a', { attrs: { href: this.getObjectUrl(this.streamData.stream + '.json') } }, "JSON")

-         ]),

-         ")",

-         "—",

-         h('span', {}, this.timeSince(this.streamData.metadata['last-modified']))

-       ]);

- 

        cloudLaunchableTitle = h('h3', { class:"font-weight-light" }, "Cloud Launchable");

        cloudLaunchableSection = {};

        cloudLaunchable = {};
@@ -314,7 +336,7 @@ 

            if (coreos_download_app.isAws(platform)) {

              if (displayInfo.list) {

                return h('div', {}, displayInfo.list.map(function(amiInfo) {

-                 return h('div', {}, [

+                 return h('div', { class: "p-2 m-2" }, [

                    amiInfo.platform ? h('div', { class: "font-weight-bold" }, amiInfo.platform) : null,

                    amiInfo.region ? h('div', {}, [ "(", amiInfo.region, ")" ]) : null,

                    amiInfo.release ? h('div', { class: "ml-2" }, [
@@ -372,7 +394,7 @@ 

              }, "Verify signature & SHA256")

            ]),

            coreos_download_app.showSignatureAndSha(imageType, platformFormat, contentType) ? h('div', { class: "bg-gray-100 p-2 my-2" }, [ h('p', {}, [

-               displayDownloads.sha256 ? h('div', {}, [

+               displayDownloads.sha256 ? h('div', { class: "overflow-auto" }, [

                  "SHA256: ",

                  displayDownloads.sha256

                ]) : null,
@@ -416,7 +438,7 @@ 

          return h('div', {}, Object.entries(displayArtifacts).map(function(entry) {

            platformFormat = entry[0];

            displayInfo = entry[1];

-           return h('div', { class: "my-2" }, [

+           return h('div', { class: "p-2 m-2" }, [

              displayInfo.platform ? h('div', { class: "font-weight-bold" }, displayInfo.platform) : null,

              displayInfo.extension ? h('div', {}, [ "(", displayInfo.extension, ")" ]) : null,

              displayInfo.release ? h('div', { class: "ml-2" }, [
@@ -446,7 +468,7 @@ 

          virtualizedSection = h('div', {}, "No virtualized images found.");

        }

        virtualized = h('div', { class: "col-12 py-2 my-2" }, [ virtualizedSection ]);

-       

+ 

        if (this.streamDisplay.cloud) {

          cloudSection = createArtifactsSection(this.streamDisplay.cloud, 'cloud');

        }
@@ -463,17 +485,15 @@ 

          ])

        ]);

  

-       let navbar = this.getNavbar(h);

- 

-       let bare_metal_container = h('div', { class: "col-12 p-0" }, [ bareMetalTitle, verifyBlurb, bareMetal ]);

-       let virtualized_container = h('div', { class: "col-12 p-0" }, [ virtualizedTitle, verifyBlurb, virtualized ]);

+       let bare_metal_container = h('div', { class: "col-6" }, [ bareMetalTitle, verifyBlurb, bareMetal ]);

+       let virtualized_container = h('div', { class: "col-6" }, [ virtualizedTitle, verifyBlurb, virtualized ]);

  

-       let cloud_launchable_container = h('div', { class: "col-12 py-2 my-2", attrs: { id: "cloud-launchable", hidden: false} }, [ cloudLaunchableTitle, streamName, cloudLaunchable ]);

-       let metal_virt_container = h('div', { class: "col-12 py-2 my-2", attrs: { id: "metal-virt", hidden: true } }, [ bare_metal_container, virtualized_container ]);

+       let cloud_launchable_container = h('div', { class: "col-12 py-2 my-2", attrs: { id: "cloud-launchable", hidden: false} }, [ cloudLaunchableTitle, cloudLaunchable ]);

+       let metal_virt_container = h('div', { class: "row col-12 py-2 my-2", attrs: { id: "metal-virt", hidden: true } }, [ bare_metal_container, virtualized_container ]);

        let cloud_operators_container = h('div', { class: "col-12 py-2 my-2", attrs: { id: "cloud-operator", hidden: true } }, [ cloudTitle, verifyBlurb, cloud ]);

  

        return h('div', {}, [

-         navbar,

+         stream_select_container,

          cloud_launchable_container,

          metal_virt_container,

          cloud_operators_container

Changes towards adding an option through a dropdown menu to select the stable stream and fetch the metadata accordingly, based on @abai's work in https://pagure.io/fedora-web/websites/pull-request/78.

WIP - testing that fetch failures are handled properly, and will try to split my first commit (2edb366) up to make review easier.

To fully make the downloads page ready for the stable release on Jan 14th, also need to update the description and title of the page.

@rfairley le us know once this moves out of WIP for review!

Just tried the commits locally, worked really well. Thanks for the help @rfairley !
The next step would be updating the description and title.
After this PR is merged, I can help with the styling of the page.

This should be good to go. Before when testing, trying to fetch with a nonexistent URL I found would result in rendering the title of each section with empty body (showing no images) e.g. Cloud Launchable, whereas I was expecting only the text Loading... to be rendered.

This may be the intended operation - I was going to try to verify this in the code, but I think as this is, it is acceptable. Switching to a URL where the metadata exists through the dropdown menu will reloads the page with the page with the correct images in the case where the metadata URL does exist.

Updated the title - this is good to merge from me.

Just needs to be rebased - working on this.

rebased onto 4a865ac

4 years ago

Now rebased, showing the aliyun artifacts as well.

Switched the default stream back to testing - we will switch the default to stable as a final step at the end of the release.

Page looks as follows: https://rfairley.fedorapeople.org/Screenshot_2020-01-13%20Get%20Fedora.png

(stream is switched to stable in the screenshot, but the default is testing).

Is the gray background in the tab area expected?

@rfairley The Loading is not shown because the async call to fetch the metadata would return and loading will be set to false (https://pagure.io/fedora-web/websites/blob/master/f/sites/static/js/coreos-download.js#_196). Since this.streamData is {} instead of null, the render function will re-render the page with dropdowns and tabs.

Change https://pagure.io/fedora-web/websites/blob/master/f/sites/static/js/coreos-download.js#_197 to this.streamData = Object.entries(streamData).length === 0 && streamData.constructor === Object ? null : streamData; seems to fix the issue (i.e. make streamData remain null instead of updating it to empty object)

@jlebon The gray color comes from https://pagure.io/fedora-websites/issue/964#comment-576026. Originally we would want to move descriptions and tabs into the gray area with three streams: stable, testing, and next. Though for now I think it's good to make the background white to make it look cleaner and add more styles to the page when we have more streams..

EDIT: probably should remove the jumbotron in https://pagure.io/fedora-web/websites/pull-request/81#_2__205 so that the background is consistent

This should be testing, right?

Yes - that should be testing - thanks for catching.

7 new commits added

  • coreos: Remove jumbotron class from stream select area
  • coreos: fix returned streamData during refreshStream
  • coreos: Show last modified only if metadata loaded
  • coreos: Add 'stable' option in streams dropdown
  • coreos-download: add dropdown list for streams
  • coreos-download: use jumbotron instead of container for tabs
  • coreos-download: add icons and change style for buttons
4 years ago

7 new commits added

  • coreos: Remove jumbotron class from stream select area
  • coreos: fix returned streamData during refreshStream
  • coreos: Show last modified only if metadata loaded
  • coreos: Add 'stable' option in streams dropdown
  • coreos-download: add dropdown list for streams
  • coreos-download: use jumbotron instead of container for tabs
  • coreos-download: add icons and change style for buttons
4 years ago

@rfairley The Loading is not shown because the async call to fetch the metadata would return and loading will be set to false (https://pagure.io/fedora-web/websites/blob/master/f/sites/static/js/coreos-download.js#_196). Since this.streamData is {} instead of null, the render function will re-render the page with dropdowns and tabs.

Thank you for debugging this!

Change https://pagure.io/fedora-web/websites/blob/master/f/sites/static/js/coreos-download.js#_197 to this.streamData = Object.entries(streamData).length === 0 && streamData.constructor === Object ? null : streamData; seems to fix the issue (i.e. make streamData remain null instead of updating it to empty object)

Thanks, I've added this, and looks to work. I added a commit for this; added you as a co-author.

@jlebon The gray color comes from https://pagure.io/fedora-websites/issue/964#comment-576026. Originally we would want to move descriptions and tabs into the gray area with three streams: stable, testing, and next. Though for now I think it's good to make the background white to make it look cleaner and add more styles to the page when we have more streams..
EDIT: probably should remove the jumbotron in https://pagure.io/fedora-web/websites/pull-request/81#_2__205 so that the background is consistent

Removed the jumbrotron class from the dropdown area - now has matching color with the rest of the theme.

7 new commits added

  • coreos: remove jumbotron class from stream select area
  • coreos: fix returned streamData during refreshStream
  • coreos: show last modified only if metadata loaded
  • coreos: add 'stable' option in streams dropdown
  • coreos-download: add dropdown list for streams
  • coreos-download: use jumbotron instead of container for tabs
  • coreos-download: add icons and change style for buttons
4 years ago

Np! Thanks for the help :smile:
Tested locally, LGTM!

^ minor edit to make the commit messages have consistent lower case.

Page now renders like so:

https://rfairley.fedorapeople.org/Screenshot_2020-01-13%20Get%20Fedora(1).png
https://rfairley.fedorapeople.org/Screenshot_2020-01-13%20Get%20Fedora(2).png (switched to stable stream in the dropdown here)

Edit: the above URLs will need to be copy/pasted in, including the .png extension

This should be good to merge now.

Let's do the final edits (changing the page description / title) in a separate PR.

Pull-Request has been merged by codeblock

4 years ago