<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>Forem: Kevan Y</title>
    <description>The latest articles on Forem by Kevan Y (@pandanoxes).</description>
    <link>https://forem.com/pandanoxes</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F459661%2F691346ec-2e0c-4fdc-a9b5-356235a48938.png</url>
      <title>Forem: Kevan Y</title>
      <link>https://forem.com/pandanoxes</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/pandanoxes"/>
    <language>en</language>
    <item>
      <title>Working with Next.js + MUI (edit)</title>
      <dc:creator>Kevan Y</dc:creator>
      <pubDate>Sat, 23 Apr 2022 03:21:36 +0000</pubDate>
      <link>https://forem.com/pandanoxes/working-with-nextjs-mui-kgk</link>
      <guid>https://forem.com/pandanoxes/working-with-nextjs-mui-kgk</guid>
      <description>&lt;h2&gt;
  
  
  Intro
&lt;/h2&gt;

&lt;p&gt;This week I worked on the front-end part of telescope. I didn't touch that much on the front-end in telescope, but I had experience with Next.js before. The &lt;a href="https://github.com/Seneca-CDOT/telescope/issues/3357"&gt;Issue&lt;/a&gt; I will be working on is to implement a UI for the &lt;code&gt;dependency-discovery&lt;/code&gt; services. &lt;/p&gt;

&lt;h2&gt;
  
  
  Planning / Implementation
&lt;/h2&gt;

&lt;p&gt;They were no designs pre-planned for this issue. I had to make a simple, fast, and functional design.&lt;br&gt;
Before getting into the design we have to understand the &lt;code&gt;dependency-discovery&lt;/code&gt; API, we need to know all the possible route and what kind of data each route return to make use of all our API data as much as possible.&lt;/p&gt;
&lt;h3&gt;
  
  
  &lt;code&gt;/projects&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;This route returns an array of string of the list of the dependencies we use in telescope repo.&lt;/p&gt;
&lt;h4&gt;
  
  
  Samples of data
&lt;/h4&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="s2"&gt;"@algolia/client-common"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="s2"&gt;"@babel/helpers"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="s2"&gt;"react"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h3&gt;
  
  
  &lt;code&gt;/projects/:namespace/:name?&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;This route returns the general information of the dependency. It's an object with &lt;code&gt;id&lt;/code&gt; as string, &lt;code&gt;license&lt;/code&gt; as string, and 'gitRepository' as object. &lt;code&gt;gitRepository&lt;/code&gt; has a &lt;code&gt;type&lt;/code&gt; as string, &lt;code&gt;url&lt;/code&gt; as string, &lt;code&gt;directory&lt;/code&gt; as string, and &lt;code&gt;issuesUrl&lt;/code&gt; as string.&lt;/p&gt;
&lt;h4&gt;
  
  
  Samples of data
&lt;/h4&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"@babel/core"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"license"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"MIT"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"gitRepository"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"git"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"url"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"https://github.com/babel/babel"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"directory"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"packages/babel-core"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"issuesUrl"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"https://github.com/babel/babel/issues?q=is%3Aopen+is%3Aissue+label%3A%22hacktoberfest%22%2C%22good+first+issue%22%2C%22help+wanted%22"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h3&gt;
  
  
  &lt;code&gt;/github/:namespace/:name?&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;This route returns an array of issue label &lt;code&gt;hacktoberfest&lt;/code&gt;, &lt;code&gt;Help wanted&lt;/code&gt;, and &lt;code&gt;good first issue&lt;/code&gt; of the dependency. Each object has a &lt;code&gt;htmlUrl&lt;/code&gt; as string, &lt;code&gt;title&lt;/code&gt; as string, &lt;code&gt;body&lt;/code&gt; as string, and &lt;code&gt;createdAt&lt;/code&gt; as string.&lt;/p&gt;
&lt;h4&gt;
  
  
  Samples of data
&lt;/h4&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"htmlUrl"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"https://github.com/babel/babel/issues/7357"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"title"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"injecting external-helpers in a node app"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"body"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"&amp;lt;!---&lt;/span&gt;&lt;span class="se"&gt;\r\n&lt;/span&gt;&lt;span class="s2"&gt;Thanks for filing an issue 😄 ! Before you submit, please read the following:&lt;/span&gt;&lt;span class="se"&gt;\r\n\r\n&lt;/span&gt;&lt;span class="s2"&gt;Search open/closed issues before submitting since someone might have asked the same thing before!&lt;/span&gt;&lt;span class="se"&gt;\r\n\r\n&lt;/span&gt;&lt;span class="s2"&gt;If you have a support request or question please submit them to one of this resources:&lt;/span&gt;&lt;span class="se"&gt;\r\n\r\n&lt;/span&gt;&lt;span class="s2"&gt;* Slack Community: https://slack.babeljs.io/&lt;/span&gt;&lt;span class="se"&gt;\r\n&lt;/span&gt;&lt;span class="s2"&gt;* StackOverflow: http://stackoverflow.com/questions/tagged/babeljs using the tag `babeljs`&lt;/span&gt;&lt;span class="se"&gt;\r\n&lt;/span&gt;&lt;span class="s2"&gt;* Also have a look at the readme for more information on how to get support:&lt;/span&gt;&lt;span class="se"&gt;\r\n&lt;/span&gt;&lt;span class="s2"&gt;  https://github.com/babel/babel/blob/master/README.md&lt;/span&gt;&lt;span class="se"&gt;\r\n\r\n&lt;/span&gt;&lt;span class="s2"&gt;Issues on GitHub are only related to problems of Babel itself and we cannot answer &lt;/span&gt;&lt;span class="se"&gt;\r\n&lt;/span&gt;&lt;span class="s2"&gt;support questions here.&lt;/span&gt;&lt;span class="se"&gt;\r\n&lt;/span&gt;&lt;span class="s2"&gt;--&amp;gt;&lt;/span&gt;&lt;span class="se"&gt;\r\n\r\n&lt;/span&gt;&lt;span class="s2"&gt;Choose one: is this a bug report or feature request? (docs?) bug report&lt;/span&gt;&lt;span class="se"&gt;\r\n\r\n&lt;/span&gt;&lt;span class="s2"&gt;I'm trying to use a package that assumes that the external-helpers are available as a global. From the [docs](https://babeljs.io/docs/plugins/external-helpers/#injecting-the-external-helpers), I should be able to inject them to `global` in my node app by using `require(&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;babel-core&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;).buildExternalHelpers();`. However, use of that still results in the following error: `ReferenceError: babelHelpers is not defined`&lt;/span&gt;&lt;span class="se"&gt;\r\n\r\n&lt;/span&gt;&lt;span class="s2"&gt;### Babel/Babylon Configuration (.babelrc, package.json, cli command)&lt;/span&gt;&lt;span class="se"&gt;\r\n&lt;/span&gt;&lt;span class="s2"&gt;Since the `buildExternalHelpers()` function needs to run before the package is imported and my app uses es module imports, I'm using a bootstrap file as an entry point that is ignored from transpilation and just tries to inject the helpers before loading the actual app:&lt;/span&gt;&lt;span class="se"&gt;\r\n\r\n&lt;/span&gt;&lt;span class="s2"&gt;```

js&lt;/span&gt;&lt;span class="se"&gt;\r\n&lt;/span&gt;&lt;span class="s2"&gt;require(&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;babel-core&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;).buildExternalHelpers();&lt;/span&gt;&lt;span class="se"&gt;\r\n&lt;/span&gt;&lt;span class="s2"&gt;const app = require('./app');&lt;/span&gt;&lt;span class="se"&gt;\r\n&lt;/span&gt;&lt;span class="s2"&gt;

```&lt;/span&gt;&lt;span class="se"&gt;\r\n\r\n&lt;/span&gt;&lt;span class="s2"&gt;### Expected Behavior&lt;/span&gt;&lt;span class="se"&gt;\r\n\r\n&lt;/span&gt;&lt;span class="s2"&gt;`babelHelpers` should be added to `global` so that it is available for the package that assumes it is available there.&lt;/span&gt;&lt;span class="se"&gt;\r\n\r\n&lt;/span&gt;&lt;span class="s2"&gt;from the docs:&lt;/span&gt;&lt;span class="se"&gt;\r\n&lt;/span&gt;&lt;span class="s2"&gt;&amp;gt; This injects the external helpers into `global`.&lt;/span&gt;&lt;span class="se"&gt;\r\n\r\n&lt;/span&gt;&lt;span class="s2"&gt;### Current Behavior&lt;/span&gt;&lt;span class="se"&gt;\r\n\r\n&lt;/span&gt;&lt;span class="s2"&gt;`babelHelpers` is not made available on `global`, resulting in `ReferenceError: babelHelpers is not defined`&lt;/span&gt;&lt;span class="se"&gt;\r\n\r\n&lt;/span&gt;&lt;span class="s2"&gt;### Possible Solution&lt;/span&gt;&lt;span class="se"&gt;\r\n\r\n&lt;/span&gt;&lt;span class="s2"&gt;The docs also [mention](https://babeljs.io/docs/plugins/external-helpers/#getting-the-external-helpers) generating a helpers file with `./node_modules/.bin/babel-external-helpers [options] &amp;gt; helpers.js`. It wasn't obvious to me that this file could be imported to accomplish the same goal as `buildExternalHelpers()` until I started reading the source of that file. Importing that file instead does work for my app. I'll need this file elsewhere, so I'll likely just continue importing that instead, even if there is a way to use `buildExternalHelpers()`.&lt;/span&gt;&lt;span class="se"&gt;\r\n\r\n&lt;/span&gt;&lt;span class="s2"&gt;With that approach, my bootstrap file has the following contents instead:&lt;/span&gt;&lt;span class="se"&gt;\r\n\r\n&lt;/span&gt;&lt;span class="s2"&gt;```

js&lt;/span&gt;&lt;span class="se"&gt;\r\n&lt;/span&gt;&lt;span class="s2"&gt;require('../../vendor/babel-helpers');&lt;/span&gt;&lt;span class="se"&gt;\r\n&lt;/span&gt;&lt;span class="s2"&gt;const app = require('./app');&lt;/span&gt;&lt;span class="se"&gt;\r\n&lt;/span&gt;&lt;span class="s2"&gt;

```&lt;/span&gt;&lt;span class="se"&gt;\r\n\r\n&lt;/span&gt;&lt;span class="s2"&gt;### Your Environment&lt;/span&gt;&lt;span class="se"&gt;\r\n&lt;/span&gt;&lt;span class="s2"&gt;&amp;lt;!--- Include as many relevant details about the environment you experienced the bug in --&amp;gt;&lt;/span&gt;&lt;span class="se"&gt;\r\n\r\n&lt;/span&gt;&lt;span class="s2"&gt;| software         | version(s)&lt;/span&gt;&lt;span class="se"&gt;\r\n&lt;/span&gt;&lt;span class="s2"&gt;| ---------------- | -------&lt;/span&gt;&lt;span class="se"&gt;\r\n&lt;/span&gt;&lt;span class="s2"&gt;| Babel            | 6.26.0&lt;/span&gt;&lt;span class="se"&gt;\r\n&lt;/span&gt;&lt;span class="s2"&gt;| node             | 8.9.4&lt;/span&gt;&lt;span class="se"&gt;\r\n&lt;/span&gt;&lt;span class="s2"&gt;| npm              | 5.6.0&lt;/span&gt;&lt;span class="se"&gt;\r\n&lt;/span&gt;&lt;span class="s2"&gt;| Operating System | macOS High Sierra &lt;/span&gt;&lt;span class="se"&gt;\r\n\r\n&lt;/span&gt;&lt;span class="s2"&gt;### Forum&lt;/span&gt;&lt;span class="se"&gt;\r\n\r\n&lt;/span&gt;&lt;span class="s2"&gt;While I was still trying to find a working solution, I was trying to find the best place to ask questions. The website still links to a discourse forum that no longer seems to exist. It'd be a good idea to either remove the link from the site or at least have it link to somewhere that describes the currently recommended approach for getting that type of help.&lt;/span&gt;&lt;span class="se"&gt;\r\n&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"createdAt"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"2018-02-08T20:49:23Z"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Now we know what the API return, let's makes a draft design. For simplicity, I'm gonna draw it by hand.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fttsx9uk7fzlh02q6ineq.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fttsx9uk7fzlh02q6ineq.png" alt="Image description" width="800" height="600"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I started to look at what MUI component I could use for this.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Icons - &lt;a href="https://mui.com/material-ui/material-icons/"&gt;link&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Table - &lt;a href="https://mui.com/material-ui/react-table/"&gt;link&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Collapse - &lt;a href="https://mui.com/material-ui/api/collapse/"&gt;link&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;After that, I need to plan how I will structure my code and what to add/modify.&lt;/p&gt;

&lt;p&gt;1 - Create a route at &lt;code&gt;/dependencies&lt;/code&gt; in &lt;code&gt;src\web\app\src\pages&lt;/code&gt; in Next.js the name of the file is our route name. &lt;br&gt;
The page should follow the other page in telescope which means it has an SEO, and Navbar component. Also, we need to add our DependenciesPage component which is our dependencies page.&lt;br&gt;
I was thinking to use &lt;code&gt;getStaticProps&lt;/code&gt; + revalidate features from Next.Js to make a static page. But since our API services need to be run at the time when Next.Js builds all static HTML, so we might need to modify our docker-compose to run our &lt;code&gt;dependency-discovery&lt;/code&gt; services first then after our services it's up we can build our static HTML. For simplicity, I decided to just use &lt;code&gt;useEffect&lt;/code&gt; to fetch the data.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;SEO&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;../components/SEO&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;NavBar&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;../components/NavBar&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;DependenciesPage&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;../components/DependenciesPage&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;dependencies&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;SEO&lt;/span&gt; &lt;span class="na"&gt;pageTitle&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"Dependencies | Telescope"&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;NavBar&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;DependenciesPage&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="nx"&gt;dependencies&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;2 - Add a new icon to redirect into our new route in the navbar &lt;code&gt;src\web\app\src\components\NavBar\index.tsx&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;FiPackage&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;react-icons/fi&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;iconProps&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;NavBarIconProps&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
 &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="p"&gt;...&lt;/span&gt;
 &lt;span class="p"&gt;},&lt;/span&gt;
 &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;href&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/dependencies&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;title&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Dependencies&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;ariaLabel&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Dependencies&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;Icon&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;FiPackage&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;3 - Set our &lt;code&gt;dependencyDiscoveryUrl&lt;/code&gt; env.&lt;br&gt;
In docker-compose &lt;code&gt;docker\docker-compose.yml&lt;/code&gt;, we need forward &lt;code&gt;DEPENDENCY_DISCOVERY_URL&lt;/code&gt; in the build args.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;services&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;nginx&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;build&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;context&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;../src/web&lt;/span&gt;
      &lt;span class="na"&gt;dockerfile&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Dockerfile&lt;/span&gt;
      &lt;span class="na"&gt;cache_from&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;docker.cdot.systems/nginx:buildcache&lt;/span&gt;
      &lt;span class="c1"&gt;# next.js needs build-time access to a number of API URL values, forward as ARGs&lt;/span&gt;
      &lt;span class="na"&gt;args&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="s"&gt;...&lt;/span&gt;
        &lt;span class="s"&gt;- DEPENDENCY_DISCOVERY_URL&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We also need to modify the &lt;code&gt;Dockerfile&lt;/code&gt; in &lt;code&gt;src\web\Dockerfile&lt;/code&gt; to add &lt;code&gt;DEPENDENCY_DISCOVERY_URL&lt;/code&gt; as build args.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight docker"&gt;&lt;code&gt;&lt;span class="k"&gt;ARG&lt;/span&gt;&lt;span class="s"&gt; DEPENDENCY_DISCOVERY_URL&lt;/span&gt;
&lt;span class="k"&gt;ENV&lt;/span&gt;&lt;span class="s"&gt; NEXT_PUBLIC_DEPENDENCY_DISCOVERY_URL ${DEPENDENCY_DISCOVERY_URL}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now we need to forward that env to be accessible in Next.Js. We will need to modify &lt;code&gt;src\web\app\next.config.js&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;envVarsToForward&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
 &lt;span class="p"&gt;...,&lt;/span&gt;
 &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;DEPENDENCY_DISCOVERY_URL&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;4 - Create our &lt;code&gt;DependenciesPage&lt;/code&gt; components in &lt;code&gt;src\web\app\src\components&lt;/code&gt; (Because it contains a lot of lines of code I'm just putting some parts. &lt;a href="https://github.com/Seneca-CDOT/telescope/blob/master/src/web/app/src/components/DependenciesPage.tsx"&gt;Read more&lt;/a&gt;)&lt;br&gt;
Our &lt;code&gt;DependenciesPage&lt;/code&gt; components should have a &lt;code&gt;useEffect&lt;/code&gt; that runs once on &lt;code&gt;onMount&lt;/code&gt; to fetch our dependencies at route &lt;code&gt;/projects&lt;/code&gt;. As JSX, it will have our Page title, and a &lt;code&gt;DependenciesTable&lt;/code&gt; component which is our table of dependencies, it has a dependencies(List of the dependencies) props.&lt;br&gt;
We also need some style to make our page responsive and adjust color in light/dark mode.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;dependencyDiscoveryUrl&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;../config&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;makeStyles&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@material-ui/core/styles&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;useState&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;react&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;useStyles&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;makeStyles&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;theme&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;root&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;backgroundColor&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;theme&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;palette&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;background&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;default&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;fontFamily&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Spartan&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;padding&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;1em 0 2em 0&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;paddingTop&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;env(safe-area-inset-top)&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;wordWrap&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;break-word&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;theme&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;breakpoints&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;down&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1024&lt;/span&gt;&lt;span class="p"&gt;)]:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;maxWidth&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;none&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;&amp;amp; h1&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;theme&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;palette&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;text&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;secondary&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;fontSize&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;24&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;transition&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;color 1s&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;marginTop&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;&amp;amp; p, blockquote&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;theme&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;palette&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;text&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;primary&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;fontSize&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;16&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;margin&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="na"&gt;container&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;padding&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;2vh 18vw&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;theme&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;breakpoints&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;down&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1024&lt;/span&gt;&lt;span class="p"&gt;)]:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;padding&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;2vh 8vw&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;wordWrap&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;break-word&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;}));&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;DependenciesPage&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
   &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;dependencies&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setDependencies&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;useState&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;string&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
   &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;classes&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useStyles&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

   &lt;span class="nf"&gt;useEffect&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;fetchDependenciesData&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;dependencyDiscoveryUrl&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/projects`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="nf"&gt;setDependencies&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;fetchDependenciesData&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Error Fetching Dependencies&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;e&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;})();&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;

  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt; &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;classes&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;root&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt; &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;classes&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;container&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;h1&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;Dependencies&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;h1&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;DependenciesTable&lt;/span&gt; &lt;span class="na"&gt;dependencies&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;dependencies&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="nx"&gt;DependenciesPage&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;5 - Create &lt;code&gt;DependenciesTable&lt;/code&gt; component in &lt;code&gt;src\web\app\src\components\DependenciesTable\index.tsx&lt;/code&gt; (Because it contains a lot of lines of code I'm just putting some parts. &lt;a href="https://github.com/Seneca-CDOT/telescope/blob/master/src/web/app/src/components/DependenciesTable/index.tsx"&gt;Read more&lt;/a&gt;). This would be the component that contains our table, search bar, and table navigation. We can get our dependency list from the props dependencies. Create a function to update the dependency list based on the search query.&lt;br&gt;
Set the limit of the rows per page to 15.&lt;br&gt;
We also need to add some style to match our drawing design and adjust color for light/dark mode.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;DependenciesTableProps&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;dependencies&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;[];&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;DependenciesTable&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;dependencies&lt;/span&gt; &lt;span class="p"&gt;}:&lt;/span&gt; &lt;span class="nx"&gt;DependenciesTableProps&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;classes&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useStyles&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;page&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setPage&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;rowsPerPage&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;15&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// Set 15 element per page&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;searchField&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setSearchField&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;''&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="c1"&gt;// Compute dependencyList based on search query&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;dependencyList&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useMemo&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;setPage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;searchField&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;dependencies&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;dependencies&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;filter&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="na"&gt;dependency&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;dependency&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toLowerCase&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;includes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;searchField&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toLowerCase&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;dependencies&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;searchField&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;

  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;SearchInput&lt;/span&gt; &lt;span class="na"&gt;text&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;searchField&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="na"&gt;setText&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;setSearchField&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="na"&gt;labelFor&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"Browse for a dependency"&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;

      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;TableContainer&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Table&lt;/span&gt; &lt;span class="na"&gt;sx&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;minWidth&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;450&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="na"&gt;aria-label&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"custom pagination table"&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
          &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;TableBody&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;dependencyList&lt;/span&gt;
              &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;slice&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;page&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nx"&gt;rowsPerPage&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;page&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nx"&gt;rowsPerPage&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;rowsPerPage&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
              &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;dependency&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Row&lt;/span&gt; &lt;span class="na"&gt;key&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;dependency&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="na"&gt;dependency&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;dependency&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;;&lt;/span&gt;
              &lt;span class="p"&gt;})&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
          &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;TableBody&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;Table&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;TablePagination&lt;/span&gt;
          &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;classes&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;root&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
          &lt;span class="na"&gt;rowsPerPageOptions&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
          &lt;span class="na"&gt;component&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"div"&lt;/span&gt;
          &lt;span class="na"&gt;count&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;dependencyList&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
          &lt;span class="na"&gt;rowsPerPage&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;rowsPerPage&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
          &lt;span class="na"&gt;page&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;page&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
          &lt;span class="na"&gt;onPageChange&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;handleChangePage&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;TableContainer&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;/&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="nx"&gt;DependenciesTable&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;6 - Create &lt;code&gt;Row&lt;/code&gt; component in &lt;code&gt;src\web\app\src\components\DependenciesTable\Row.tsx&lt;/code&gt; (&lt;a href="https://github.com/Seneca-CDOT/telescope/blob/master/src/web/app/src/components/DependenciesTable/Row.tsx"&gt;Read more&lt;/a&gt;). This content each of our row with the collapse. We have some &lt;code&gt;useEffect&lt;/code&gt; waiting on a state called &lt;code&gt;open&lt;/code&gt; (state for the collapsed component) to be changed to trigger the fetch for dependency information. For fetch GitHub issues, add more checks to see if API returns 403 which means API limit reached, if 403 we need to show a message saying &lt;code&gt;Github API reached a limit, please use the link directly &amp;lt;Dependency name&amp;gt;&lt;/code&gt;.&lt;br&gt;
We also need to add some style to match our drawing design and adjust color for light/dark mode.&lt;/p&gt;

&lt;p&gt;7 - Testing part : &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Making sure our design is responsive,&lt;/li&gt;
&lt;li&gt;Show the right color in light/dark mode. &lt;/li&gt;
&lt;li&gt;Working search bar.&lt;/li&gt;
&lt;li&gt;Working pagination.&lt;/li&gt;
&lt;li&gt;Working collapse and data fetch on collapse open.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Pull request reviews
&lt;/h2&gt;

&lt;p&gt;Feedback from &lt;a href="https://github.com/humphd"&gt;@humphd&lt;/a&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Use SWR instead of using &lt;code&gt;useEffect&lt;/code&gt; for fetching&lt;/li&gt;
&lt;li&gt;Add a paragraph to explain what is it after the title.&lt;/li&gt;
&lt;li&gt;Add a spinner when content is loading.&lt;/li&gt;
&lt;li&gt;Fix color, and font size issues.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Feedback from &lt;a href="https://github.com/joelazwar"&gt;@joelazwar&lt;/a&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Reset item number to 1 when we search for something&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Feedback from &lt;a href="https://github.com/DukeManh"&gt;@DukeManh&lt;/a&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Use the Default SWR fetcher instead of creating one.&lt;/li&gt;
&lt;li&gt;Rename some functions.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Final products
&lt;/h2&gt;

&lt;p&gt;Once the code is merged the staging environment will ship this feature first. &lt;br&gt;
On release 3.0.0, it will be shipped to production environment&lt;br&gt;
Staging: &lt;a href="https://dev.telescope.cdot.systems/dependencies/"&gt;https://dev.telescope.cdot.systems/dependencies/&lt;/a&gt;&lt;br&gt;
Production: &lt;a href="https://telescope.cdot.systems/dependencies/"&gt;https://telescope.cdot.systems/dependencies/&lt;/a&gt;&lt;/p&gt;

</description>
      <category>opensource</category>
      <category>nextjs</category>
      <category>typescript</category>
    </item>
    <item>
      <title>Hard bug fixed by a simple fix</title>
      <dc:creator>Kevan Y</dc:creator>
      <pubDate>Mon, 18 Apr 2022 03:16:07 +0000</pubDate>
      <link>https://forem.com/pandanoxes/hard-bug-fixed-by-a-simple-fix-2p9a</link>
      <guid>https://forem.com/pandanoxes/hard-bug-fixed-by-a-simple-fix-2p9a</guid>
      <description>&lt;p&gt;Opened my &lt;a href="https://github.com/Seneca-CDOT/telescope/pull/3307"&gt;Pull request&lt;/a&gt; on adding best practices for the SSO services. The e2e test was failing in the pipeline, despised testing locally. &lt;br&gt;
On the CI, the test case was only failing on Chromium.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;FAIL browser: chromium src/api/sso/test/e2e/auth-flows.test.js (28.142 s)
  Authentication Flows
    ✕ Login flow preserves state param (25222 ms)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;First, some of my reviewers are using Mac M1  (ARM architecture), they were not able to build the image properly since the node-alpine version because it was missing some build-in package to build the image. I had to use a bigger node version. &lt;br&gt;
After pushing those changes, &lt;a href="https://github.com/humphd"&gt;@humphd&lt;/a&gt; helped me to debug, this issue wasn't able to be producible locally.&lt;/p&gt;

&lt;p&gt;I started to run on different environment, and this is the result showed below:&lt;br&gt;
&lt;strong&gt;Windows 11 pro 21H2&lt;/strong&gt; - test case pass. (by @Kevan-Y )&lt;br&gt;
&lt;strong&gt;Windows 11 pro 21H2 on WSL2 Ubuntu-20.04&lt;/strong&gt; - test case pass  (by @Kevan-Y )&lt;br&gt;
&lt;strong&gt;Amazon Linux 2 AMI (HVM) - Kernel 5.10 (ami-0c02fb55956c7d316 (64-bit x86)) - t2.large&lt;/strong&gt; - test case pass  (by @Kevan-Y )&lt;br&gt;
&lt;strong&gt;MacOS M1&lt;/strong&gt; -  test case pass (by @humphd)&lt;/p&gt;

&lt;p&gt;It wasn't looking good. This makes debugging hard since it's only happening on CI.&lt;/p&gt;

&lt;p&gt;I started to increase the timeout of the test case to 30000ms&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;it&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Login flow preserves state param&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;state&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;login&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;page&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;user1&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;user1pass&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="c1"&gt;// Expect the state to match what we sent originally (see index.html &amp;lt;a&amp;gt;)&lt;/span&gt;
    &lt;span class="nx"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;toEqual&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;abc123&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="mi"&gt;30000&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Despite increasing timeout it was failing. &lt;/p&gt;

&lt;p&gt;Possibility due to some other container such as elastic search, it crashed, since that container had some issue with the memory not enough allocated. I increased the memory in the docker-compose file.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;  &lt;span class="na"&gt;elasticsearch&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;environment&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="c1"&gt;# Limit the initial heap size. By default it will use 1/4 of available RAM&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;ES_JAVA_OPTS=-Xms512m&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;-Xmx512m'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After pushing these changes, the CI pipeline was still failing.&lt;/p&gt;

&lt;p&gt;I decided to skip all the e2e test cases and only run &lt;code&gt;Login flow preserves state param&lt;/code&gt; of &lt;code&gt;src/api/sso/test/e2e/auth-flows.test.js&lt;/code&gt; for the purpose of debugging and also turn on &lt;code&gt;LOG_LEVEL&lt;/code&gt; to &lt;code&gt;debug&lt;/code&gt;.&lt;br&gt;
I pushed those changes, but it wasn't helping. They were 0 logs that helped to identify which place it when wrong. So I switch to the basic way of debugging. "Put console.log on each line"&lt;/p&gt;

&lt;p&gt;In &lt;code&gt;src\api\sso\test\e2e\auth-flows.test.js&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt; &lt;span class="nx"&gt;it&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Login flow preserves state param&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Start test case by await login&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;state&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;login&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;page&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;user1&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;user1pass&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Done await login&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="c1"&gt;// Expect the state to match what we sent originally (see index.html &amp;lt;a&amp;gt;)&lt;/span&gt;
    &lt;span class="nx"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;toEqual&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;abc123&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="mi"&gt;30000&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In &lt;code&gt;src\api\sso\test\e2e\browser-util.js&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;login&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;page&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;username&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;password&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Start login and wait for page&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="c1"&gt;// Click login button and then wait for the login page to load&lt;/span&gt;
  &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;all&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;
    &lt;span class="nx"&gt;page&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;waitForNavigation&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
      &lt;span class="na"&gt;url&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sr"&gt;/simplesaml&lt;/span&gt;&lt;span class="se"&gt;\/&lt;/span&gt;&lt;span class="sr"&gt;module&lt;/span&gt;&lt;span class="se"&gt;\.&lt;/span&gt;&lt;span class="sr"&gt;php&lt;/span&gt;&lt;span class="se"&gt;\/&lt;/span&gt;&lt;span class="sr"&gt;core&lt;/span&gt;&lt;span class="se"&gt;\/&lt;/span&gt;&lt;span class="sr"&gt;loginuserpass&lt;/span&gt;&lt;span class="se"&gt;\.&lt;/span&gt;&lt;span class="sr"&gt;php/&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;waitUtil&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;networkidle&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;}),&lt;/span&gt;
    &lt;span class="nx"&gt;page&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;click&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;#login&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
  &lt;span class="p"&gt;]);&lt;/span&gt;
  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;after click login&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;click input[name="username"]&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="c1"&gt;// Fill the login form, star with username&lt;/span&gt;
  &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;page&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;click&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;input[name="username"]&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;after click input[name="username"]&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;fill input[name="username"]&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;page&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;fill&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;input[name="username"]&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;username&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;after fill input[name="username"]&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="c1"&gt;// Now enter the password&lt;/span&gt;
  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;click input[name="password"]&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;page&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;click&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;input[name="password"]&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;after click input[name="password"]&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;fill input[name="password"]&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;page&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;fill&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;input[name="password"]&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;password&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;after fill input[name="password"]&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;wait for the new page to load&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="c1"&gt;// Click login button and then wait for the new page to load&lt;/span&gt;
  &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;all&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;
    &lt;span class="nx"&gt;page&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;waitForNavigation&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
      &lt;span class="na"&gt;url&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sr"&gt;/^http:&lt;/span&gt;&lt;span class="se"&gt;\/\/&lt;/span&gt;&lt;span class="sr"&gt;localhost:&lt;/span&gt;&lt;span class="se"&gt;\d&lt;/span&gt;&lt;span class="sr"&gt;+&lt;/span&gt;&lt;span class="se"&gt;\/&lt;/span&gt;&lt;span class="sr"&gt;auth&lt;/span&gt;&lt;span class="se"&gt;\.&lt;/span&gt;&lt;span class="sr"&gt;html&lt;/span&gt;&lt;span class="se"&gt;\?&lt;/span&gt;&lt;span class="sr"&gt;access_token=&lt;/span&gt;&lt;span class="se"&gt;[^&lt;/span&gt;&lt;span class="sr"&gt;&amp;amp;&lt;/span&gt;&lt;span class="se"&gt;]&lt;/span&gt;&lt;span class="sr"&gt;+&amp;amp;state=/&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;waitUtil&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;load&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;}),&lt;/span&gt;
    &lt;span class="nx"&gt;page&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;click&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;text=/.*Login.*/&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
  &lt;span class="p"&gt;]);&lt;/span&gt;

  &lt;span class="c1"&gt;// The token and state will get returned on the query string&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;getTokenAndState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;page&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After pushing this change, I finally got some good debug result. The test case was timing out in&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;all&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;
    &lt;span class="nx"&gt;page&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;waitForNavigation&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
      &lt;span class="na"&gt;url&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sr"&gt;/simplesaml&lt;/span&gt;&lt;span class="se"&gt;\/&lt;/span&gt;&lt;span class="sr"&gt;module&lt;/span&gt;&lt;span class="se"&gt;\.&lt;/span&gt;&lt;span class="sr"&gt;php&lt;/span&gt;&lt;span class="se"&gt;\/&lt;/span&gt;&lt;span class="sr"&gt;core&lt;/span&gt;&lt;span class="se"&gt;\/&lt;/span&gt;&lt;span class="sr"&gt;loginuserpass&lt;/span&gt;&lt;span class="se"&gt;\.&lt;/span&gt;&lt;span class="sr"&gt;php/&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;waitUtil&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;networkidle&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;}),&lt;/span&gt;
    &lt;span class="nx"&gt;page&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;click&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;#login&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
  &lt;span class="p"&gt;]);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;One possible issue mentioned by &lt;a href="https://github.com/humphd"&gt;@Humphd&lt;/a&gt;, the event was sitting on that page for some reason and never navigates.&lt;br&gt;
Instead of &lt;code&gt;waitUtil: 'networkidle'&lt;/code&gt;, we change to &lt;code&gt;waitUtil: 'load'&lt;/code&gt;. &lt;a href="https://playwright.dev/docs/api/class-page#page-wait-for-navigation"&gt;see reference&lt;/a&gt;&lt;br&gt;
Even with that, it didn't work. But the ultimate fix was to try to update from version &lt;code&gt;1.19.2&lt;/code&gt; to &lt;code&gt;1.20.2&lt;/code&gt; of &lt;code&gt;playwright&lt;/code&gt; which might potentially fix it.&lt;br&gt;
It was the right solution, just an update of the dependencies, and everything works fine.&lt;/p&gt;

&lt;p&gt;Spend a couple of days trying to debug this, and the fix was just a dependency update. It was a good experience, in the end. Sometimes we have to wait for the upstream to fix for us.&lt;/p&gt;

</description>
      <category>opensource</category>
    </item>
    <item>
      <title>Discovered new tools.</title>
      <dc:creator>Kevan Y</dc:creator>
      <pubDate>Thu, 07 Apr 2022 00:29:03 +0000</pubDate>
      <link>https://forem.com/pandanoxes/discovered-new-tools-29al</link>
      <guid>https://forem.com/pandanoxes/discovered-new-tools-29al</guid>
      <description>&lt;h2&gt;
  
  
  &lt;a href="https://github.com/oauth2-proxy/oauth2-proxy"&gt;Oauth2-proxy&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;It's a reverse proxy and static files server that provides authentication in the middle of a user request. &lt;br&gt;
In telescope, I had to use &lt;code&gt;oauth2-proxy&lt;/code&gt; and &lt;code&gt;nginx&lt;/code&gt; to secure the route for Supabase studio.&lt;br&gt;
&lt;a href="https://github.com/Seneca-CDOT/telescope/pull/3098"&gt;Add studio under our subdomain #3098&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  Process
&lt;/h3&gt;
&lt;h4&gt;
  
  
  Configure our docker-compose for staging/production
&lt;/h4&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="c1"&gt;# production.yml&lt;/span&gt;
  &lt;span class="na"&gt;nginx&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;depends_on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;oauth2-proxy&lt;/span&gt;

  &lt;span class="na"&gt;oauth2-proxy&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;bitnami/oauth2-proxy:7.2.1&lt;/span&gt;
    &lt;span class="na"&gt;container_name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;oauth2-proxy'&lt;/span&gt;
    &lt;span class="na"&gt;command&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;[&lt;/span&gt;
        &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;--provider=github'&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt;
        &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;--cookie-secure=true'&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt;
        &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;--cookie-secret=${OAUTH2_SUPABASE_COOKIE_SECRET}'&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt;
        &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;--upstream=http://studio:3000'&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt;
        &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;--http-address=0.0.0.0:8080'&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt;
        &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;--reverse-proxy=true'&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt;
        &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;--email-domain=*'&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt;
        &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;--github-org=Seneca-CDOT'&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt;
        &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;--github-team=telescope-admins'&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt;
        &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;--client-id=${OAUTH2_SUPABASE_CLIENT_ID}'&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt;
        &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;--client-secret=${OAUTH2_SUPABASE_CLIENT_SECRET}'&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt;
      &lt;span class="pi"&gt;]&lt;/span&gt;
    &lt;span class="na"&gt;depends_on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;studio&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Set &lt;code&gt;nginx&lt;/code&gt; services to depend on &lt;code&gt;oauth2-proxy&lt;/code&gt;. So we let &lt;code&gt;oauth2-proxy&lt;/code&gt; start first before starting &lt;code&gt;nginx&lt;/code&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Declare our &lt;code&gt;oauth2-proxy&lt;/code&gt; services to use image &lt;code&gt;bitnami/oauth2-proxy:7.2.1&lt;/code&gt;, we give the following command.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;--provider=github&lt;/code&gt;, this tell to use GitHub Oauth services &lt;a href="https://oauth2-proxy.github.io/oauth2-proxy/docs/configuration/oauth_provider#github-auth-provider"&gt;see&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;--cookie-secure=true&lt;/code&gt;, Set our cookie to be secure.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;--cookie-secret=${OAUTH2_SUPABASE_COOKIE_SECRET}&lt;/code&gt;, set a long seed string for secure cookies.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;--upstream=http://studio:3000&lt;/code&gt;, set the upstream to be redirected to after authorized, in our case it would be Supabase studio.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;--http-address=0.0.0.0:8080&lt;/code&gt;, listen on for HTTP clients.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;--reverse-proxy=true&lt;/code&gt;, set reverse-proxy to be true since we are putting our &lt;code&gt;oauth2-proxy&lt;/code&gt; under &lt;code&gt;nginx&lt;/code&gt;. It helps to automatically set a redirect route.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;--email-domain=*&lt;/code&gt;, this is for restricting certain email domains, but for us, we allow any domain.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;--github-org=Seneca-CDOT&lt;/code&gt;, this is for restricting by GitHub organization, for use we allow only member that is in Seneca-CDOT.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;--github-team=telescope-admins&lt;/code&gt;, this is for restricting within an organization to specific teams,  for use we allow only member that is in Seneca-CDOT organization and telescope-admins teams.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;--client-id=${OAUTH2_SUPABASE_CLIENT_ID}&lt;/code&gt;, this is our GitHub Oauth client id &lt;a href="https://docs.github.com/en/developers/apps/building-oauth-apps/authorizing-oauth-apps"&gt;see&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;--client-secret=${OAUTH2_SUPABASE_CLIENT_SECRET}&lt;/code&gt;, this is our GitHub Oauth client secret &lt;a href="https://docs.github.com/en/developers/apps/building-oauth-apps/authorizing-oauth-apps"&gt;see&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;
  
  
  Configure our nginx config for staging/production
&lt;/h4&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# nginx.conf.template
  server {
    listen 443 ssl http2;
    server_name ${SUPABASE_HOST};

    location / {
      proxy_set_header Connection "";
      proxy_set_header Host $host;
      proxy_set_header X-Real-IP $remote_addr;
      proxy_set_header X-Scheme $scheme;
      proxy_pass http://oauth2-proxy:8080/;
    }
  }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;In this PR &lt;a href="https://github.com/Seneca-CDOT/telescope/issues/2964"&gt;#2964&lt;/a&gt;, we added the DNS and SSL.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;In our nginx config, we declare a new server with a server name of our &lt;code&gt;${SUPABASE_HOST}&lt;/code&gt; and listen to port 443.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Set the location to be &lt;code&gt;/&lt;/code&gt;, set the proxy to be our &lt;code&gt;oauth2-proxy&lt;/code&gt; services. &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Set the the proxy header &lt;code&gt;proxy_set_header&lt;/code&gt;, &lt;code&gt;proxy_set_header&lt;/code&gt;, &lt;code&gt;proxy_set_header&lt;/code&gt;, this will give our &lt;code&gt;oauth2-proxy&lt;/code&gt; the right information to set up the redirect route.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
  
  
  &lt;a href="https://hurl.dev/"&gt;Hurl&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://github.com/Orange-OpenSource/hurl"&gt;Hurl&lt;/a&gt; is an open-source command-line tool that runs HTTP requests defined in a simple plain text format.&lt;br&gt;
The sources code is written in Rust which makes this tool very fast to run.&lt;br&gt;
It's made by a French Telecom company called &lt;a href="https://www.orange.com/en"&gt;Orange&lt;/a&gt;, &lt;/p&gt;
&lt;h3&gt;
  
  
  Linux installation
&lt;/h3&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-LO&lt;/span&gt; https://github.com/Orange-OpenSource/hurl/releases/download/1.6.1/hurl_1.6.1_amd64.deb
&lt;span class="nb"&gt;sudo &lt;/span&gt;dpkg &lt;span class="nt"&gt;-i&lt;/span&gt; hurl_1.6.1_amd64.deb
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h3&gt;
  
  
  To check if it's installed
&lt;/h3&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;hurl -h
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h3&gt;
  
  
  Scenario to test
&lt;/h3&gt;

&lt;p&gt;Note: any POST, PUT, DELETE, and GET request needs user to be authenticated. For that let's assume our API uses basic auth and the username is &lt;code&gt;user1@email.com&lt;/code&gt; and the password is &lt;code&gt;password1&lt;/code&gt;. For the authentication, we use a base64 which can be generated with the following code below.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;btoa&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;user1@email.com:password1&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="err"&gt;#&lt;/span&gt; &lt;span class="nx"&gt;Output&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;dXNlcjFAZW1haWwuY29tOnBhc3N3b3JkMQ&lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;POST sending a file, it should return a status code of 201, header Locations of the URL to get the data, and JSON body containing an id based on nanoid, create date in string, update date in string&lt;/li&gt;
&lt;li&gt;GET at URL of the location previously returned in POST, and compare if the data returned matches the content posted.&lt;/li&gt;
&lt;li&gt;PUT at URL of the location previously returned in POST, and update the content, it should return a status code of 200, and JSON body containing an id based on nanoid, create date in string, newest update date in string (should be greater than create date).&lt;/li&gt;
&lt;li&gt;GET at URL of the location previously returned in POST, and compare if the data returned matches the content updated.&lt;/li&gt;
&lt;li&gt;DELETE at URL of the location previously returned in POST, it should return a status code of 200&lt;/li&gt;
&lt;/ol&gt;

&lt;h4&gt;
  
  
  Folder structure
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;.
├── .github
│   ├── workflows
│   │   └── ci.yml
├── tests
│   ├── fixtures
│   │   └── data.txt
│   ├── integration
│   │   ├── myTest.hurl
├── docker
│   ├── docker-compose.yml
├── Dockerfile
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Test case file
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# myTest.hurl

# 1. POST request 
# Make a POST and send our txt file located in the fixtures folder
# Set the content type to be a text/plain
POST http://localhost:8080/cat
Content-Type: text/plain
# https://hurl.dev/docs/request.html#file-body
file,./fixtures/data.txt;
# Set the Authorization to be a Basic auth and our base64 credential
Authorization: Basic dXNlcjFAZW1haWwuY29tOnBhc3N3b3JkMQ==

# Check the response to be 201
HTTP/1.1 201

# https://hurl.dev/docs/asserting-response.html
[Asserts]
# Assert header Location to contain the URL for getting our data
header "Location" matches "^http:\/\/localhost:8080\/cat\/[A-Za-z0-9_-]+$"

# Assert id to matches id generated with nanoid https://www.npmjs.com/package/nanoid
jsonpath "$.id" matches "^[A-Za-z0-9_-]+$"

# Assert created to return a string
jsonpath "$.created" isString

# Assert created to return a string
jsonpath "$.updated" isString

# https://hurl.dev/docs/capturing-response.html#captures
[Captures]
# Capture the header location value and store to url
# This value can be call later in the code.
url: header "Location"
# Capture the id from the returned json and store cat_id
cat_id: jsonpath "$.id"
# Capture the created date from the returned json and store cat_created
cat_created: jsonpath "$.created"
# Capture the updated date from the returned json and store cat_updated
cat_updated: jsonpath "$.updated"

# 2. GET request 
# GET at the url previously captured
GET {{url}}
# Set the Authorization to be a Basic auth and our base64 credential
Authorization: Basic dXNlcjFAZW1haWwuY29tOnBhc3N3b3JkMQ==

# Check the response to be 200
HTTP/1.1 200
# Check the response content type to be text/plain
Content-Type: text/plain
# Check the response body to match the content of data.txt.
file,./fixtures/data.txt;

# 3. PUT request
# PUT at the url previously captured
PUT {{url}}
# Set the Authorization to be a Basic auth and our base64 credential
Authorization: Basic dXNlcjFAZW1haWwuY29tOnBhc3N3b3JkMQ==
Content-Type: text/plain
# Set the request body with our new content 
# https://hurl.dev/docs/request.html#raw-string-body
```New content```

# Check the response to be 200
HTTP/1.1 200

[Asserts]
# Assert id to be the same as cat_id (id captured in the POST return)
jsonpath "$.id" == {{cat_id}}

# Assert created to be the same as cat_created (created captured in the POST return)
jsonpath "$.created" == {{cat_created}}

# Assert updated to be different as cat_updated (updated captured in the POST return)
jsonpath "$.updated" != {{cat_updated}}

# 4. GET request 
# GET at the url previously captured
GET {{url}}
# Set the Authorization to be a Basic auth and our base64 credential
Authorization: Basic dXNlcjFAZW1haWwuY29tOnBhc3N3b3JkMQ==

# Check the response to be 200
HTTP/1.1 200
# Check the response content type to be text/plain
Content-Type: text/plain
# Check the response body to match the new content updated from the PUT request
```New content```

# 5. DELETE request 
# DELETE at the url previously captured
DELETE {{url}}
# Set the Authorization to be a Basic auth and our base64 credential
Authorization: Basic dXNlcjFAZW1haWwuY29tOnBhc3N3b3JkMQ==

# Check the response to be 200
HTTP/1.1 200
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  To run the test case. See &lt;a href="https://hurl.dev/docs/running-tests.html"&gt;how to run&lt;/a&gt; and &lt;a href="https://hurl.dev/docs/man-page.html#options"&gt;command option&lt;/a&gt;
&lt;/h4&gt;

&lt;p&gt;Let's assume we are in the root of our folder.&lt;br&gt;
Let's assume we have a &lt;code&gt;docker-compose.yml&lt;/code&gt; that is already running our microservices and exposes at port 8080.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;hurl &lt;span class="nt"&gt;--test&lt;/span&gt; &lt;span class="nt"&gt;--file-root&lt;/span&gt; &lt;span class="s2"&gt;"./tests"&lt;/span&gt; &lt;span class="s2"&gt;"./tests/integration/myTest.hurl"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;--test&lt;/code&gt;, activate the test mode which enables &lt;code&gt;--no-output&lt;/code&gt;, &lt;code&gt;--progress&lt;/code&gt;, and &lt;code&gt;--summary&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;--file-root&lt;/code&gt; set our file root, we need this because we want our fixture to be accessible. &lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  Samples of response
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;❯ hurl &lt;span class="nt"&gt;--test&lt;/span&gt; &lt;span class="nt"&gt;--file-root&lt;/span&gt; &lt;span class="s2"&gt;"./tests"&lt;/span&gt; &lt;span class="s2"&gt;"./tests/integration/myTest.hurl"&lt;/span&gt;
./tests/integration/myTest.hurl: RUNNING &lt;span class="o"&gt;[&lt;/span&gt;1/1]
./tests/integration/myTest.hurl: SUCCESS
&lt;span class="nt"&gt;--------------------------------------------------------------------------------&lt;/span&gt;
Executed:  1
Succeeded: 1 &lt;span class="o"&gt;(&lt;/span&gt;100.0%&lt;span class="o"&gt;)&lt;/span&gt;
Failed:    0 &lt;span class="o"&gt;(&lt;/span&gt;0.0%&lt;span class="o"&gt;)&lt;/span&gt;
Duration:  10ms
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Run on CI pipeline
&lt;/h4&gt;

&lt;p&gt;Let's assume we have a &lt;code&gt;docker-compose.yml&lt;/code&gt; that spins up our microservices and exposes at port 8080.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="c1"&gt;# .github/workflows/ci.yml&lt;/span&gt;
&lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ci&lt;/span&gt;
&lt;span class="na"&gt;on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;pull_request&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;branches&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;main&lt;/span&gt;
  &lt;span class="na"&gt;push&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;branches&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;main&lt;/span&gt;

&lt;span class="na"&gt;jobs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;hurl-test&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;runs-on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ubuntu-latest&lt;/span&gt;
  &lt;span class="na"&gt;steps&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;🏗 Setup repo&lt;/span&gt;
      &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/checkout@v2&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;📦 Install hurl&lt;/span&gt;
      &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt;
        &lt;span class="s"&gt;curl -LO https://github.com/Orange-OpenSource/hurl/releases/download/1.6.1/hurl_1.6.1_amd64.deb&lt;/span&gt;
        &lt;span class="s"&gt;sudo dpkg -i hurl_1.6.1_amd64.deb&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;🏗 Build Containers&lt;/span&gt;
      &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;docker-compose -f docker/docker-compose.yml up -d&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;✨ Run Hurl Tests&lt;/span&gt;
      &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;hurl --test --file-root "./tests" "tests/integration/myTest.hurl"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Opinion about this new testing tool.
&lt;/h4&gt;

&lt;p&gt;In overall, this is a pretty unique testing tool, it's super fast and powerful since the code base is written in rust. The learning curves are pretty simple (I managed to learn the basics in a couple of hours), less setup todo since it's just a plain file, the syntax is English friendly, besides the &lt;a href="https://goessner.net/articles/JsonPath/"&gt;jsonPath&lt;/a&gt; that could take some times to adapt.&lt;/p&gt;

&lt;p&gt;There is some limitation, like for the assert, sometimes it's not that easy to compare an object to an object or read from an object since when you read a capture of an object, it tries to construct into a string so you are not able to use jsonPath to get some property.&lt;/p&gt;

&lt;p&gt;Thanks to &lt;a href="https://github.com/humphd"&gt;@humphd&lt;/a&gt; who showed us this tool.  And I'm happy because it's a French company that made this wonderful open-source tool.&lt;/p&gt;

</description>
      <category>opensource</category>
    </item>
    <item>
      <title>Release 2.9</title>
      <dc:creator>Kevan Y</dc:creator>
      <pubDate>Mon, 04 Apr 2022 02:23:51 +0000</pubDate>
      <link>https://forem.com/pandanoxes/release-29-1g59</link>
      <guid>https://forem.com/pandanoxes/release-29-1g59</guid>
      <description>&lt;h2&gt;
  
  
  My Work
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://github.com/Seneca-CDOT/telescope/issues/1668" rel="noopener noreferrer"&gt;Apply Dockerfile best practices from Snyk recommendations #1668&lt;/a&gt; &lt;br&gt;
List of Dockerfile worked:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/Seneca-CDOT/telescope/pull/3231" rel="noopener noreferrer"&gt;https://github.com/Seneca-CDOT/telescope/pull/3231&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/Seneca-CDOT/telescope/pull/3256" rel="noopener noreferrer"&gt;https://github.com/Seneca-CDOT/telescope/pull/3256&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/Seneca-CDOT/telescope/pull/3236" rel="noopener noreferrer"&gt;https://github.com/Seneca-CDOT/telescope/pull/3236&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/Seneca-CDOT/telescope/pull/3235" rel="noopener noreferrer"&gt;https://github.com/Seneca-CDOT/telescope/pull/3235&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/Seneca-CDOT/telescope/pull/3255" rel="noopener noreferrer"&gt;https://github.com/Seneca-CDOT/telescope/pull/3255&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/Seneca-CDOT/telescope/pull/3238" rel="noopener noreferrer"&gt;https://github.com/Seneca-CDOT/telescope/pull/3238&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/Seneca-CDOT/telescope/pull/3307" rel="noopener noreferrer"&gt;https://github.com/Seneca-CDOT/telescope/pull/3307&lt;/a&gt; (In progress, fixing failing e2e test)&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/Seneca-CDOT/telescope/pull/3239" rel="noopener noreferrer"&gt;https://github.com/Seneca-CDOT/telescope/pull/3239&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/Seneca-CDOT/telescope/pull/3309" rel="noopener noreferrer"&gt;https://github.com/Seneca-CDOT/telescope/pull/3309&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In overall it was pretty straightforward once one of the PR got reviewed, and I can use it as a template.&lt;/p&gt;
&lt;h2&gt;
  
  
  One of the process steps
&lt;/h2&gt;

&lt;p&gt;References&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fkl294lauud2o7i2cqjd6.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fkl294lauud2o7i2cqjd6.png" alt="Image description"&gt;&lt;/a&gt;&lt;br&gt;
&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/8vXoMqWgbQQ"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;For the image version we need to use an image to a specific version(Not using alpine version for package installation since M1 required more tools to work)
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt; &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;FROM node:lts as base&lt;/span&gt;
 &lt;span class="s"&gt;+ FROM node:16 as base&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Setup multi staging
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt; &lt;span class="s"&gt;+ FROM node:16 as base&lt;/span&gt;
 &lt;span class="s"&gt;+ FROM base as dependencies&lt;/span&gt;
 &lt;span class="s"&gt;+ FROM node:16-alpine3.15 as deploy&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Base stage is for installing the tool needed for package installation. &lt;br&gt;
Dependencies stage is for installing node_modules.&lt;br&gt;
Deploy stage is where we copy sources code from the build context and node_modules from Dependencies and run our services.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Run node app as node user
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="s"&gt;+ COPY --chown=node:node . .&lt;/span&gt;
&lt;span class="s"&gt;+ USER node&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This allows Node user to have permission to read our sources code.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Add a healthcheck
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="s"&gt;+ ENV PORT&lt;/span&gt;
&lt;span class="s"&gt;+ HEALTHCHECK --interval=30s --timeout=30s --start-period=5s --retries=3 \&lt;/span&gt;
&lt;span class="s"&gt;+   CMD wget --no-verbose --tries=1 --spider localhost:${DEPENDENCY_DISCOVERY_PORT}/healthcheck || exit &lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is the change I made, one thing &lt;a href="https://github.com/humphd" rel="noopener noreferrer"&gt;@humphd&lt;/a&gt; noticed building the application with a node-alpine image, on ARM architecture, it's required to use a bigger node image to be able to build it. &lt;a href="https://github.com/Seneca-CDOT/telescope/pull/3336" rel="noopener noreferrer"&gt;See PR 3336&lt;/a&gt;&lt;/p&gt;

</description>
      <category>opensource</category>
    </item>
    <item>
      <title>Release 2.9 rethinking about my goal</title>
      <dc:creator>Kevan Y</dc:creator>
      <pubDate>Mon, 21 Mar 2022 15:58:35 +0000</pubDate>
      <link>https://forem.com/pandanoxes/release-29-rethinking-about-my-goal-3i3m</link>
      <guid>https://forem.com/pandanoxes/release-29-rethinking-about-my-goal-3i3m</guid>
      <description>&lt;h2&gt;
  
  
  Which part of Telescope 3.0 do I own?
&lt;/h2&gt;

&lt;p&gt;In the past 2 weeks in telescope, I have been working in Docker, nginx, and oauth. So I guess I'm gonna own those parts. &lt;/p&gt;

&lt;h2&gt;
  
  
  Which existing Issues are part of this? Which new Issues do I need to file in order to properly describe the work? When will those issues be filed?
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://github.com/Seneca-CDOT/telescope/issues/3088"&gt;Add full OAuth2 capabilities to SSO service #3088&lt;/a&gt;, new issue, after adding oauth to Portainer, we found that it's not convenient to create 2 different oauth github app for staging and development, also in the future if we want to secure more route with oauth2-proxy, we will have to create more oauth github app. This issue will solve that, by enabling full OAuth2 capabilities in our SSO.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/Seneca-CDOT/telescope/issues/1668"&gt;Apply Dockerfile best practices from Snyk recommendations
#1668&lt;/a&gt;, undergoing, I started to refactoring some Dockerfile already and will keep refactoring the rest for 2.9 release.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/Seneca-CDOT/telescope/issues/3278"&gt;Refactor all our dockerfile to use our base image. #3278&lt;/a&gt;, new issue, in &lt;a href="https://github.com/Seneca-CDOT/telescope/issues/2803"&gt;#2803&lt;/a&gt; we created a base to be used in all other of dockerfile.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/Seneca-CDOT/telescope/issues/3033"&gt;Expose supabase studio under nginx #3033
&lt;/a&gt; - undergoing, waiting on &lt;a href="https://github.com/Seneca-CDOT/telescope/issues/2979"&gt;#2979&lt;/a&gt;, once the secret thing is done. I can push my local change into it.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/Seneca-CDOT/telescope/issues/3029"&gt;See if our nginx configs make any of these common mistakes #3029&lt;/a&gt;, new issue, this issue for check if we setup our nginx config correctly.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Who can I depend on for support in development, debugging, testing, and reviews? I can't do this alone.
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://github.com/TDDR"&gt;@TDDR&lt;/a&gt;, is our Docker guy, along &lt;a href="https://github.com/manekenpix"&gt;@manekenpix&lt;/a&gt;, and &lt;a href="https://github.com/humphd"&gt;@humphd&lt;/a&gt; who knows most of the telescope part and provide a lot of help.&lt;/p&gt;

&lt;h2&gt;
  
  
  What are the risks that I see, which could prevent me from getting this shipped?
&lt;/h2&gt;

&lt;p&gt;I think time is a big issue. With my course load specially PRJ class + job hunting + doing research and preparing the document to be able to work in Canada is starting, my schedule is getting filled quickly. I started 2 different side projects at the beginning of the semester utilizing web3, nextjs, and redux, but had to pause them because not enough time.&lt;/p&gt;

&lt;h2&gt;
  
  
  How will I mitigate these risks?
&lt;/h2&gt;

&lt;p&gt;I think to mitigate those risks. It will be great to find more contributors to have an interest in oauth part and docker. Working as a group is much faster than working alone.&lt;/p&gt;

</description>
      <category>opensource</category>
    </item>
    <item>
      <title>Telescope 2.8 release</title>
      <dc:creator>Kevan Y</dc:creator>
      <pubDate>Tue, 15 Mar 2022 02:55:50 +0000</pubDate>
      <link>https://forem.com/pandanoxes/telescope-28-release-21gg</link>
      <guid>https://forem.com/pandanoxes/telescope-28-release-21gg</guid>
      <description>&lt;p&gt;Release 2.8 was one of the biggest releases. Telescope set a new record with 99 tasks completed. So close to 100, but we will eventually make it one day. &lt;/p&gt;

&lt;h2&gt;
  
  
  What I did:
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://github.com/Seneca-CDOT/telescope/issues/3030"&gt;Use oauth2-proxy with GitHub Auth Provider to secure Admin apps &lt;br&gt;
 #3030&lt;/a&gt; - This issue was to use oauth2-proxy to be our proxy with auth, to make it simple we want to secure some route, and only be accessible once authorize. &lt;br&gt;
For this issue, we wanted to hide Portainer under oauth2-proxy. &lt;br&gt;
I spend a couple of days doing research and trying oauth2-proxy in my local. I followed some sample of code &lt;a href="https://github.com/oauth2-proxy/oauth2-proxy/blob/master/contrib/local-environment/docker-compose.yaml"&gt;https://github.com/oauth2-proxy/oauth2-proxy/blob/master/contrib/local-environment/docker-compose.yaml&lt;/a&gt; and run it locally. Instead of using oidc I switched to GitHub.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;  &lt;span class="na"&gt;oauth2-proxy&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;bitnami/oauth2-proxy:7.2.1&lt;/span&gt;
    &lt;span class="na"&gt;container_name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;oauth2-proxy'&lt;/span&gt;
    &lt;span class="na"&gt;command&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;[&lt;/span&gt;
        &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;--provider=github'&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt;
        &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;--cookie-secure=false'&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt;
        &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;--cookie-secret=&amp;lt;Long_cookie&amp;gt;'&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt;
        &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;--upstream=&amp;lt;Redirect_to_after_login&amp;gt;'&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt;
        &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;--http-address=0.0.0.0:8080'&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt;
        &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;--skip-auth-regex=/forms/*'&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt;
        &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;--redirect-url=http://localhost:8085/oauth2/callback'&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt;
        &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;--email-domain=*'&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt;
        &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;--client-id=&amp;lt;Github_client_id&amp;gt;'&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt;
        &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;--client-secret=&amp;lt;Github_secret_id&amp;gt;'&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt;
      &lt;span class="pi"&gt;]&lt;/span&gt;
    &lt;span class="na"&gt;ports&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;8085:8080&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I also need to setup GitHub oauth app. Followed this instruction.&lt;br&gt;
&lt;a href="https://docs.github.com/en/developers/apps/building-oauth-apps/creating-an-oauth-app"&gt;https://docs.github.com/en/developers/apps/building-oauth-apps/creating-an-oauth-app&lt;/a&gt;&lt;br&gt;
Once I have oauth2-proxy working locally it was time to head in telescope repo and implement this.&lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--ReJoFfO6--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/cnl5qdrceme9j413fcei.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--ReJoFfO6--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/cnl5qdrceme9j413fcei.png" alt="Image description" width="540" height="520"&gt;&lt;/a&gt;&lt;br&gt;
One issue I noticed is that Portainer doesn't have anymore an option to enable no-auth after V.1. So we will have to login twice once in our &lt;code&gt;oauth2-proxy&lt;/code&gt; and another one in Portainer which is what we don't want.&lt;br&gt;
I had to find another option to implement oauth with Github provider in Portainer. After a bit of documentation reading. I found out that Portainer has a custom oauth and can be setup with Github. &lt;a href="https://docs.portainer.io/v/ce-2.11/admin/settings/authentication/oauth#github"&gt;see&lt;/a&gt; &lt;br&gt;
It was time to setup custom oauth for Portainer. First I needed &lt;a href="https://github.com/humphd"&gt;@humphd&lt;/a&gt; to setup Github oauth app in &lt;a href="https://github.com/Seneca-CDOT"&gt;Seneca-CDOT&lt;/a&gt;, after that, I just had to put the correct information following this image below.&lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--Q119vMDF--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ocvoqx17f73kb4jj5dmt.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Q119vMDF--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ocvoqx17f73kb4jj5dmt.png" alt="Image description" width="880" height="413"&gt;&lt;/a&gt;&lt;br&gt;
How the custom oauth in Portainer works, only the default admin can login through Internal authentication. All other users will need to login through Github.&lt;br&gt;
To give access to a GitHub User, you will need to add a new user and match the username to their Github username. Once that is created, user can login with their Github account.&lt;/p&gt;
&lt;h3&gt;
  
  
  Login flow
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Go to the portainer URL
&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--y_IC1Xp---/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/mqmwpqvhbhnw7wlfntue.png" alt="Image description" width="770" height="384"&gt;
&lt;/li&gt;
&lt;li&gt;Login with Github 
&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--YMZZqFNi--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/z5b5n1x86a7xax1uyua6.png" alt="Image description" width="491" height="570"&gt;
&lt;/li&gt;
&lt;li&gt;After authorize
&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--_2YtJhbb--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/h8xoh0pgg0ffgsb82qla.png" alt="Image description" width="880" height="446"&gt;
Conclusion of this, this issue what something simple but it required a bit of research.
At the end I didn't implement oauth2-proxy but it's fine this research will help in securing route for supabase.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://github.com/Seneca-CDOT/docker.cdot.systems/issues/3"&gt;Set up Authorization tokens for CI #3&lt;br&gt;
&lt;/a&gt; - This issue was to setup basic auth for our new Docker registry with &lt;a href="https://github.com/cesanta/docker_auth"&gt;docker_auth&lt;/a&gt;. &lt;br&gt;
The documentation was just enough, I found it hard to setup since there is not a lot of sample code.&lt;/p&gt;

&lt;p&gt;From reading from the docs we need a &lt;code&gt;auth_config.yml&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;server&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;addr&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;:5001'&lt;/span&gt; &lt;span class="c1"&gt;# Address to listen to&lt;/span&gt;
  &lt;span class="na"&gt;certificate&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;/etc/letsencrypt/live/docker.cdot.systems/fullchain.pem'&lt;/span&gt; &lt;span class="c1"&gt;# TLS Certificate&lt;/span&gt;
  &lt;span class="na"&gt;key&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;/etc/letsencrypt/live/docker.cdot.systems/privkey.pem'&lt;/span&gt; &lt;span class="c1"&gt;# TLS Key&lt;/span&gt;

&lt;span class="na"&gt;token&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;issuer&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;Docker&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;auth&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;issuer'&lt;/span&gt; &lt;span class="c1"&gt;# Issuer, must match issuer in the Registry config.&lt;/span&gt;
  &lt;span class="na"&gt;expiration&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;900&lt;/span&gt;

&lt;span class="na"&gt;users&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="c1"&gt;# Password is specified as a BCrypt hash. Use htpasswd to generate.&lt;/span&gt;
  &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;admin'&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt; &lt;span class="c1"&gt;# Setup an Admin account&lt;/span&gt;
    &lt;span class="na"&gt;password&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;'&lt;/span&gt; 
&lt;span class="err"&gt;  &lt;/span&gt;&lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;telescope-ci'&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt; &lt;span class="c1"&gt;# Setup an telescope-ci account for our CI&lt;/span&gt;
    &lt;span class="na"&gt;password&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;'&lt;/span&gt; 
&lt;span class="err"&gt;  &lt;/span&gt;&lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;'&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;{}&lt;/span&gt; &lt;span class="c1"&gt;# Setup account that doesn't required password&lt;/span&gt;


&lt;span class="na"&gt;acl&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;match&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;{&lt;/span&gt; &lt;span class="nv"&gt;account&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;admin'&lt;/span&gt; &lt;span class="pi"&gt;}&lt;/span&gt; &lt;span class="c1"&gt;# Setup rule for admin to have full permission&lt;/span&gt;
    &lt;span class="na"&gt;actions&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;*'&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
    &lt;span class="na"&gt;comment&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;Admin&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;has&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;full&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;access&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;to&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;everything.'&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;match&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;{&lt;/span&gt; &lt;span class="nv"&gt;account&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;telescope-ci'&lt;/span&gt; &lt;span class="pi"&gt;}&lt;/span&gt; &lt;span class="c1"&gt;# Setup rule for telescope-ci to have push and pull access.&lt;/span&gt;
    &lt;span class="na"&gt;actions&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;push'&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;pull'&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
    &lt;span class="na"&gt;comment&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;Telescope&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;CI&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;has&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;push&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;and&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;pull&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;access'&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;match&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;{&lt;/span&gt; &lt;span class="nv"&gt;account&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;'&lt;/span&gt; &lt;span class="pi"&gt;}&lt;/span&gt; &lt;span class="c1"&gt;# Setup rule for anyone else to have pull access.&lt;/span&gt;
    &lt;span class="na"&gt;actions&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;pull'&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
    &lt;span class="na"&gt;comment&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;Any&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;user&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;has&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;pull&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;access'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After this I have &lt;a href="https://github.com/TDDR"&gt;@TDDR&lt;/a&gt;, helped me out to setup the &lt;code&gt;config.yml&lt;/code&gt; for the registry based on some of the comments I put in the Pull Request.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;0.1&lt;/span&gt;

&lt;span class="c1"&gt;#Log&lt;/span&gt;
&lt;span class="na"&gt;log&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;level&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;info&lt;/span&gt; 
  &lt;span class="na"&gt;fields&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;service&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;registry&lt;/span&gt;

&lt;span class="c1"&gt;# Storage &lt;/span&gt;
&lt;span class="na"&gt;storage&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;cache&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;blobdescriptor&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;inmemory&lt;/span&gt;
  &lt;span class="na"&gt;filesystem&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;rootdirectory&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;/mnt/docker0storage/registry&lt;/span&gt;

&lt;span class="c1"&gt;# Address to listen to&lt;/span&gt;
&lt;span class="na"&gt;http&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;addr&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;:5000'&lt;/span&gt;

&lt;span class="c1"&gt;# Our auth&lt;/span&gt;
&lt;span class="na"&gt;auth&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;token&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;issuer&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;Docker&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;auth&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;issuer'&lt;/span&gt; &lt;span class="c1"&gt;# Issuer, must match issuer in the auth config.&lt;/span&gt;
    &lt;span class="na"&gt;realm&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;https://docker.cdot.systems/auth'&lt;/span&gt; &lt;span class="c1"&gt;# Our auth path&lt;/span&gt;
    &lt;span class="na"&gt;service&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;Docker&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;registry'&lt;/span&gt;
    &lt;span class="na"&gt;rootcertbundle&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;/etc/letsencrypt/live/docker.cdot.systems/fullchain.pem&lt;/span&gt; &lt;span class="c1"&gt;# TLS Certificate&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After with the help of &lt;a href="https://github.com/humphd"&gt;@humphd&lt;/a&gt; we added our docker_auth in our &lt;code&gt;docker-compose.yml&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;  &lt;span class="na"&gt;docker_auth&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;cesanta/docker_auth&lt;/span&gt;
    &lt;span class="na"&gt;volumes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;./config/docker_auth:/config:ro&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;/var/log/docker_auth:/logs&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;/etc/letsencrypt:/etc/letsencrypt&lt;/span&gt;
    &lt;span class="na"&gt;command&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;/config/auth_config.yml&lt;/span&gt;
    &lt;span class="na"&gt;restart&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;always&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I also had to look at the issue created in docker_auth repo to see if someone showed some steps to setup docker_auth under nginx. Thankfully to this &lt;a href="https://github.com/cesanta/docker_auth/issues/184"&gt;https://github.com/cesanta/docker_auth/issues/184&lt;/a&gt;. I was able to setup nginx for docker_auth.&lt;br&gt;
I just have to add this under our &lt;code&gt;nginx.conf&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight conf"&gt;&lt;code&gt;    &lt;span class="n"&gt;location&lt;/span&gt; /&lt;span class="n"&gt;auth&lt;/span&gt; {
      &lt;span class="n"&gt;proxy_pass&lt;/span&gt;                          &lt;span class="n"&gt;https&lt;/span&gt;://&lt;span class="n"&gt;docker_auth&lt;/span&gt;:&lt;span class="m"&gt;5001&lt;/span&gt;/&lt;span class="n"&gt;auth&lt;/span&gt;;
      &lt;span class="n"&gt;proxy_ssl_trusted_certificate&lt;/span&gt;       /&lt;span class="n"&gt;etc&lt;/span&gt;/&lt;span class="n"&gt;letsencrypt&lt;/span&gt;/&lt;span class="n"&gt;live&lt;/span&gt;/&lt;span class="n"&gt;docker&lt;/span&gt;.&lt;span class="n"&gt;cdot&lt;/span&gt;.&lt;span class="n"&gt;systems&lt;/span&gt;/&lt;span class="n"&gt;fullchain&lt;/span&gt;.&lt;span class="n"&gt;pem&lt;/span&gt;;
      &lt;span class="n"&gt;proxy_set_header&lt;/span&gt;  &lt;span class="n"&gt;Host&lt;/span&gt;              $&lt;span class="n"&gt;http_host&lt;/span&gt;;   &lt;span class="c"&gt;# required for docker client's sake
&lt;/span&gt;      &lt;span class="n"&gt;proxy_set_header&lt;/span&gt;  &lt;span class="n"&gt;X&lt;/span&gt;-&lt;span class="n"&gt;Real&lt;/span&gt;-&lt;span class="n"&gt;IP&lt;/span&gt;         $&lt;span class="n"&gt;remote_addr&lt;/span&gt;; &lt;span class="c"&gt;# pass on real client's IP
&lt;/span&gt;      &lt;span class="n"&gt;proxy_set_header&lt;/span&gt;  &lt;span class="n"&gt;X&lt;/span&gt;-&lt;span class="n"&gt;Forwarded&lt;/span&gt;-&lt;span class="n"&gt;For&lt;/span&gt;   $&lt;span class="n"&gt;proxy_add_x_forwarded_for&lt;/span&gt;;
      &lt;span class="n"&gt;proxy_set_header&lt;/span&gt;  &lt;span class="n"&gt;X&lt;/span&gt;-&lt;span class="n"&gt;Forwarded&lt;/span&gt;-&lt;span class="n"&gt;Proto&lt;/span&gt; $&lt;span class="n"&gt;scheme&lt;/span&gt;;
      &lt;span class="n"&gt;proxy_read_timeout&lt;/span&gt;                  &lt;span class="m"&gt;900&lt;/span&gt;;
    }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To test if that works. I had a call with &lt;a href="https://github.com/humphd"&gt;@humphd&lt;/a&gt; to test directly in the server at the same time fix stuff that wasn't working.&lt;/p&gt;

&lt;p&gt;In issues, I wasn't the only one contributing to it. With the help of &lt;a href="https://github.com/humphd"&gt;@humphd&lt;/a&gt; and &lt;a href="https://github.com/TDDR"&gt;@TDDR&lt;/a&gt;, we were able to implement this feature. &lt;/p&gt;

</description>
      <category>opensource</category>
    </item>
    <item>
      <title>Telescope 2.8 planning </title>
      <dc:creator>Kevan Y</dc:creator>
      <pubDate>Sun, 27 Feb 2022 01:35:33 +0000</pubDate>
      <link>https://forem.com/pandanoxes/telescope-28-planning-1h9f</link>
      <guid>https://forem.com/pandanoxes/telescope-28-planning-1h9f</guid>
      <description>&lt;p&gt;For Telescope 2.8 releases. We decided to host our own docker, first decided to move our repo during the study week to another organization to use the tier for hosting our docker with GitHub, we also tried to option to email Docker to get the free tier for open sources projects. But @humphd hasn't heard back from Docker. Lucky thanks to Chris, we were able to have our own server for telescope.&lt;br&gt;
There is several small tasks.&lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--lkzkbkas--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ire5vfbzt5sjabyvren4.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--lkzkbkas--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ire5vfbzt5sjabyvren4.png" alt="Image description" width="522" height="360"&gt;&lt;/a&gt;&lt;br&gt;
I assigned myself to the registry config, nginx config, outh2-proxy config, and GitHub Provider config with team, token access. I think it good enough issue to work on during the study week.&lt;br&gt;
I'm also parallel working on &lt;a href="https://github.com/Seneca-CDOT/telescope/issues/3030"&gt;Issue #3030&lt;/a&gt;, this issue is similar to setup docker with outh2-proxy but instead of docker I need to setup for portainer. &lt;br&gt;
The only Pull request I did for this week was &lt;a href="https://github.com/Seneca-CDOT/telescope/pull/3041"&gt;Pull Request #3041&lt;/a&gt;, to setup i18n for docusaurus. &lt;br&gt;
This week I didn't do much but next week is where the fun start.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Biggest release on telescope </title>
      <dc:creator>Kevan Y</dc:creator>
      <pubDate>Sun, 20 Feb 2022 16:18:24 +0000</pubDate>
      <link>https://forem.com/pandanoxes/biggest-release-on-telescope-1hmo</link>
      <guid>https://forem.com/pandanoxes/biggest-release-on-telescope-1hmo</guid>
      <description>&lt;p&gt;This week, telescope has its biggest release more than 80 items. We also reached our 3000 created issues on telescope. I'm still a small contributor to telescope but I'm happy that I'm being part of this achievement. &lt;/p&gt;

&lt;h2&gt;
  
  
  What I have done for release 2.7
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://github.com/Seneca-CDOT/telescope/issues/2791"&gt;Issue #2791&lt;/a&gt; - Fixed by &lt;a href="https://github.com/Seneca-CDOT/telescope/pull/2931"&gt;Pull Request #2931&lt;/a&gt;. This issue looks simple with a bunch of information to guide me through but during the process, it was harder than I thought. I end up just landing kong to be rerouted with treafik to &lt;code&gt;v1/supabase&lt;/code&gt;. Thanks for &lt;a href="https://github.com/humphd"&gt;@humphd&lt;/a&gt; helping me through this issue otherwise I will be stuck for eternity. I guess this time I reached my limit of what I can do. But since this is resolved and learned a bunch of new things. Now I have a new limit yet to be discovered. There is a follow-up issue to use nginx to expose supabase studio. The issue I uncounted is that supabase studio is exposed but the static assets not fetching in the correct route. &lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/Seneca-CDOT/telescope/issues/2803"&gt;Issue #2803&lt;/a&gt; - Fixed by &lt;a href="https://github.com/Seneca-CDOT/telescope/pull/2821"&gt;Pull Request #2821&lt;/a&gt;, this issue was about creating a base image that all our microservices can use to set up the base environment. This was a good issue to learn docker, with its basic CLI.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/Seneca-CDOT/telescope/issues/2732"&gt;Issue #2732&lt;/a&gt; - Fixed by &lt;a href="https://github.com/Seneca-CDOT/telescope/issues/2933"&gt;Pull Request #2933&lt;/a&gt;, &lt;a href="https://github.com/Seneca-CDOT/telescope/pull/2954"&gt;Pull Request #2954&lt;/a&gt;, and &lt;a href="https://github.com/Seneca-CDOT/telescope/pull/2986"&gt;Pull Request #2986&lt;/a&gt;. This issue was more reach + implementation how to ship our mobile app. We decided at the moment to ship into Expo for financial purposes since to create a developer account in app store or play store you need to pay a certain amount of fees each year. Later on, we discovered that IOS users would not able to use the app once hosted to Expo due to some Apple policy. So our app end up scoped to android.
I set up the CI for the release for mobile based on &lt;a href="https://github.com/expo/expo-github-action#configuration-options"&gt;Expo GitHub Action&lt;/a&gt;. It was first simple but uncounted some issue with the authentication. The secret token stored in our repo cannot be used for fork repo. So we decided to merge and see if it would work. Unfortunately, there was some more thing to do. I first try in on my side project and one thing I was missing is expo-updates packages. This package is only used for deployment with any automation deployment. Manual deployment doesn't require this package. But this wasn't the end of our issue, there is more issue due to our &lt;code&gt;metro.config.js&lt;/code&gt; file complaining about &lt;code&gt;require('@rnx-kit/metro-resolver-symlinks');&lt;/code&gt; and &lt;code&gt;require('@rnx-kit/metro-config');&lt;/code&gt;. I wasn't sure why we needed this config, but after removing it, and doing some testing locally I was able to run the app without any issue. So I pushed those changes. I also noticed Expo was complaining about the wrong dependency version. This is because Expo required some specific version while using a certain version of expo SDK. To fix that I run an &lt;code&gt;expo doctor&lt;/code&gt; to see what was the issue then run &lt;code&gt;expo update&lt;/code&gt; to update to the correct version, after that I make sure the app is running properly then pushed my change. In the end, our mobile app got published at &lt;a href="https://expo.dev/@humphd/Telescope?serviceType=classic&amp;amp;distribution=expo-go"&gt;https://expo.dev/@humphd/Telescope?serviceType=classic&amp;amp;distribution=expo-go&lt;/a&gt; &lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Off topic
&lt;/h2&gt;

&lt;p&gt;Back in last year October, I participated to the Hacktoberfest. And this week I received my T-shirt finally after several months of waiting.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--VWo6d0Mo--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/2xtgidxn7agskankwuwi.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--VWo6d0Mo--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/2xtgidxn7agskankwuwi.jpg" alt="Image description" width="880" height="1173"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>opensource</category>
    </item>
    <item>
      <title>My turn to be Sherriff </title>
      <dc:creator>Kevan Y</dc:creator>
      <pubDate>Sun, 13 Feb 2022 17:43:04 +0000</pubDate>
      <link>https://forem.com/pandanoxes/my-turn-to-be-sherriff-1h7h</link>
      <guid>https://forem.com/pandanoxes/my-turn-to-be-sherriff-1h7h</guid>
      <description>&lt;h2&gt;
  
  
  Sheriff roles
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Planning on Tuesday&lt;/li&gt;
&lt;li&gt;Triage on Thursday &lt;/li&gt;
&lt;li&gt;Assign Issue&lt;/li&gt;
&lt;li&gt;Review PR&lt;/li&gt;
&lt;li&gt;Make sure everyone is on track&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Experience being a Sheriff
&lt;/h2&gt;

&lt;p&gt;This is the first time I manage such a large group. On Tuesday, the meeting was more of an open-ended discussion about a current issue. I and Joel were leading the meeting. It was pretty hard, especially discussing a topic where I'm not familiar. I feel lost, and not worth enough to be the sheriff. This is also the first time that I'm able to speak that long. I usually spoke around 0-10 minutes in a 1-2 hours meeting. This time I spoke for the whole meeting. On Thursday, Joel was leading the triage meeting and I was taking note of all important stuff discussed during the meeting. &lt;br&gt;
One thing I learned is that no one knows every part of telescope, if we don't know a part of telescope, we should know who in the call has expertise on that part. So we can directly ask for detail, such as what is this issue about, how long it will probably take...&lt;br&gt;
Off meeting, we have to monitor slack and Github. Not gonna lie, it was pretty tough this week for me. I had one of my group members in PRJ that got Covid, and I was the only one in that week to implement most of the features for the frontend part. I feel this time I didn't do my job as a sheriff well enough compared to the others. But it's okay, we learn from mistakes and grow up. &lt;br&gt;
Also, this was the best time to practice my English skill for speaking part. &lt;/p&gt;

&lt;p&gt;Some of the issues I'm working &lt;br&gt;
&lt;a href="https://github.com/Seneca-CDOT/telescope/issues/2732"&gt;Issue #2732&lt;/a&gt; - Still ongoing, discover some limitations with Apple restriction. &lt;br&gt;
&lt;a href="https://github.com/Seneca-CDOT/telescope/issues/2791"&gt;Issue #2791&lt;/a&gt; - Almost done, just needed to figure out why Kong container crashed.&lt;br&gt;
&lt;a href="https://github.com/Seneca-CDOT/telescope/issues/2801"&gt;Issue #2801&lt;/a&gt; - PR in draft mode&lt;/p&gt;

</description>
      <category>opensource</category>
    </item>
    <item>
      <title>New knowledge </title>
      <dc:creator>Kevan Y</dc:creator>
      <pubDate>Sat, 05 Feb 2022 04:41:09 +0000</pubDate>
      <link>https://forem.com/pandanoxes/new-knowledge-40kb</link>
      <guid>https://forem.com/pandanoxes/new-knowledge-40kb</guid>
      <description>&lt;p&gt;This week I have been reading a lot of documentation. I got involved in Docker, Supabase, Renovate bot, Turborepo, Traefik, Nginx, and React-Native.&lt;/p&gt;

&lt;h2&gt;
  
  
  Docker
&lt;/h2&gt;

&lt;p&gt;This week I have been learning a lot about Docker. I watched a quick intro into docker. &lt;br&gt;
&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/gAkwW2tuIqE"&gt;
&lt;/iframe&gt;
&lt;br&gt;
I started to do the small tutorial of docker by following the &lt;a href="https://docs.docker.com/get-started/"&gt;get-started&lt;/a&gt; of Docker. &lt;br&gt;
Docker is a bit hard to learn, but it is just a matter of time. Once I get to use more and practice more, it will eventually become easier. The next step would be to learn Kubernetes.&lt;br&gt;
Some of the issue I'm working that related to Docker&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://github.com/Seneca-CDOT/telescope/issues/2745"&gt;Issue - 2745&lt;/a&gt; - Done&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/Seneca-CDOT/telescope/issues/2791"&gt;Issue - 2791&lt;/a&gt; - Ready&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/Seneca-CDOT/telescope/issues/2799"&gt;Issue - 2799&lt;/a&gt; - Ready&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/Seneca-CDOT/telescope/issues/2803"&gt;Issue - 2803&lt;/a&gt; - Ready&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/Seneca-CDOT/telescope/issues/2830"&gt;Issue - 2830&lt;/a&gt; - Ready&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://github.com/Seneca-CDOT/telescope/issues/2745"&gt;Issue - 2745&lt;/a&gt; was my first issue with Docker stuff. I was looking at some documentation about how to install &lt;code&gt;pnpm&lt;/code&gt; into the docker containers. I end up with &lt;a href="https://pnpm.io/cli/fetch"&gt;this&lt;/a&gt;. I tried the solution followed the snippet code, but it wasn't working. Also, it is an experimental command which means it might have some breaking change in the non-major version. So I used the simple and basic solution &lt;code&gt;RUN npm i -g pnpm&lt;/code&gt;. This would install &lt;code&gt;pnpm&lt;/code&gt; into the global node_modules package. &lt;br&gt;
To test if the container was built and working I ran &lt;code&gt;pnpm services:start&lt;/code&gt;. Later on, working on &lt;a href="https://github.com/Seneca-CDOT/telescope/issues/2803"&gt;Issue - 2803&lt;/a&gt; I discovered I could start only 1 microservices instead of all of them by doing &lt;code&gt;pnpm services:start image&lt;/code&gt; to start image microservice.  &lt;/p&gt;
&lt;h2&gt;
  
  
  Supabase
&lt;/h2&gt;

&lt;p&gt;Supabase is an open sources database. It's based on PostgreSQL, and adds more features to it.&lt;br&gt;
We can say it can be an alternative to Firebase. &lt;br&gt;
&lt;a href="https://supabase.com/"&gt;Read more&lt;/a&gt;&lt;br&gt;
I watched a good quick intro about it.&lt;br&gt;
&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/WiwfiVdfRIc"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;h2&gt;
  
  
  Renovate Bot
&lt;/h2&gt;

&lt;h2&gt;
  
  
  Turborepo
&lt;/h2&gt;

&lt;p&gt;Turborepo is a tool to manage repo. This is an amazing tool. It can cache things and only rerun stuff that changed in the code. Which makes the running process fast. It is a super useful and powerful tool for monorepo.&lt;br&gt;
&lt;a href="https://turborepo.org/docs"&gt;Read more&lt;/a&gt;&lt;br&gt;
Also here is a good video of what tool on average used for monorepo.&lt;br&gt;
&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/9iU_IE6vnJ8"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;h2&gt;
  
  
  Traefik / Nginx
&lt;/h2&gt;

&lt;p&gt;Feb 04 meeting I learned more about Traefik / Nginx. Nginx is a tool to reroute/ load balance, but since it doesn't know about Docker exposed port, we need to use Traefik that communicates with Nginx and Docker.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Basically 
User &amp;gt; Nginx &amp;gt; Traefik &amp;gt; Docker
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Why use Traefik / Nginx, is because we don't want to expose ports into the web, it would be bad for security, everyone in the world would try to hack into the system.&lt;br&gt;
&lt;a href="https://github.com/Seneca-CDOT/telescope/issues/2791"&gt;Issue - 2791&lt;/a&gt; - This issue I think I'm gonna tackle since it would be a good learning touch Traefik / Nginx and also Docker. &lt;/p&gt;

&lt;h2&gt;
  
  
  React-Native
&lt;/h2&gt;

&lt;p&gt;I recently read about a &lt;a href="https://pagepro.co/blog/publishing-expo-react-native-app-to-ios-and-android/"&gt;blog post&lt;/a&gt; of how to deploy a react native to IOS and Android. This would be useful for later on when telescope will be needed to be published into Play store and App store.&lt;br&gt;
Based on the blog contains, it seems pretty simple to build and publish React-native app. &lt;br&gt;
&lt;code&gt;expo build&lt;/code&gt; is the command to build and &lt;code&gt;expo upload:{andoid/ios}&lt;/code&gt; to publish.&lt;br&gt;
But before that, we need to config &lt;code&gt;App.json&lt;/code&gt; which defines our app name, icon, splash, and other configs for different systems. &lt;br&gt;
&lt;a href="https://github.com/Seneca-CDOT/telescope/issues/2760"&gt;Issue - 2760&lt;/a&gt; - I referred to &lt;a href="https://docs.expo.dev/guides/app-icons/"&gt;this documentation&lt;/a&gt; to complete this task. &lt;br&gt;
Finale result what it would looks like:&lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--_cIKbAa2--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/bpqq5hxo1jss329bjjxn.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--_cIKbAa2--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/bpqq5hxo1jss329bjjxn.png" alt="Image description" width="880" height="632"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>opensource</category>
    </item>
    <item>
      <title>Mid way before release 2.6</title>
      <dc:creator>Kevan Y</dc:creator>
      <pubDate>Sat, 29 Jan 2022 15:49:31 +0000</pubDate>
      <link>https://forem.com/pandanoxes/mid-way-before-release-26-15fe</link>
      <guid>https://forem.com/pandanoxes/mid-way-before-release-26-15fe</guid>
      <description>&lt;p&gt;A lot happened this week, on Tuesday meeting the sheriff, went through the task to-do for release 2.6, and on Thursday it was a triage of Pull requests and issues. During the triage, I go assigned to more issues, in the area of react native, docker, and a bit of front-end fix.&lt;br&gt;
Also, did my first release on an open sources project in &lt;a href="https://github.com/Seneca-CDOT/satellite"&gt;Satellite repo&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  What I have done for release 2.6
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Issue listed from my previous blog
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://github.com/Seneca-CDOT/telescope/issues/2678"&gt;Issue #2678&lt;/a&gt; - Fixed by &lt;a href="https://github.com/Seneca-CDOT/satellite/pull/25"&gt;Pull Request #25&lt;/a&gt;. This wasn't too difficult to do since it was just removing &lt;code&gt;@elastic/ecs-pino-format&lt;/code&gt;, &lt;code&gt;elastic-apm-node&lt;/code&gt;, and its code. Then update &lt;code&gt;jest&lt;/code&gt; for fixing deprecating dependencies.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/Seneca-CDOT/telescope/issues/2694"&gt;Issue #2694&lt;/a&gt; - Fixed by &lt;a href="https://github.com/Seneca-CDOT/satellite/pull/37"&gt;Pull Request #37&lt;/a&gt;. This one was a bit of research with &lt;code&gt;pnpm engine&lt;/code&gt; and &lt;code&gt;yml&lt;/code&gt;. Thanks to this &lt;a href="https://github.com/Seneca-CDOT/telescope/pull/2545"&gt;Pull request #2545&lt;/a&gt;. It helped me to complete this issue quickly. I also had to learn about yml file and ci, how it's configured. Documentation I read, &lt;a href="https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-nodejs-or-python"&gt;Github ci/cd&lt;/a&gt;, &lt;a href="https://github.com/marketplace/actions/setup-pnpm"&gt;Actions setup-pnpm&lt;/a&gt;, &lt;a href="https://github.com/marketplace/actions/setup-node-js-environment"&gt;Actions setup-node-js-environment&lt;/a&gt;, and &lt;a href="https://github.com/marketplace/actions/checkout"&gt;Actions checkout&lt;/a&gt;. &lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/Seneca-CDOT/telescope/issues/2499"&gt;Issue #2499&lt;/a&gt; - Fixed by &lt;a href="https://github.com/Seneca-CDOT/satellite/pull/26"&gt;Pull Request #26&lt;/a&gt;. Thanks to my cloud computing class. I had used what I learned from that class and transferred to contribute to this issue. This makes me feel happy and glad to have taken this course, that I was able to use what I learned from a class and used it for other things besides class assignments. &lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/Seneca-CDOT/telescope/issues/2497"&gt;Issue #2497&lt;/a&gt; - Fixed by &lt;a href="https://github.com/Seneca-CDOT/telescope/pull/2700"&gt;Pull Request #2700&lt;/a&gt;. This issue was similar to &lt;a href="https://github.com/Seneca-CDOT/satellite/pull/26"&gt;Pull Request #26&lt;/a&gt;, but for the date format, I had to read a bit of documentation &lt;a href="https://github.com/pinojs/pino-pretty"&gt;pino-pretty&lt;/a&gt;, and &lt;a href="https://github.com/felixge/node-dateformat"&gt;node-dateformat&lt;/a&gt;. Why &lt;a href="https://github.com/felixge/node-dateformat"&gt;node-dateformat&lt;/a&gt;, because it's what &lt;a href="https://github.com/pinojs/pino-pretty"&gt;pino-pretty&lt;/a&gt; uses for &lt;code&gt;translateTime&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/Seneca-CDOT/telescope/issues/2306"&gt;Issue #2306&lt;/a&gt; - Issue still under progress, this one is a bit hard to reproduce since I get blocked by Medium. I had a hard time getting the feed data from telescope. I talked with Duc, the one who created that issue, he also had trouble reproducing it. Since most of our users use dev.to as blog posts. This issue is not my priority and will be put in the backlog.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  What I have picked after my previous blog
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://github.com/Seneca-CDOT/satellite/issues/39"&gt;Issue #39&lt;/a&gt; - This was a hotfix fixed by &lt;a href="https://github.com/Seneca-CDOT/satellite/pull/40"&gt;Pull Request #40&lt;/a&gt;, telescope e2e was failing because in satellite repo we added &lt;code&gt;preinstall&lt;/code&gt; to only use &lt;code&gt;pnpm&lt;/code&gt; but docker was still using &lt;code&gt;npm&lt;/code&gt;, so it was failing there during the installation. I had to revert and do a release. The process to do a release was pretty simple thanks to this &lt;a href="https://github.com/Seneca-CDOT/satellite/issues/38"&gt;Issue #38&lt;/a&gt;, documented by AmasiaNalbandian. &lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/Seneca-CDOT/telescope/issues/2707"&gt;Issue #2707&lt;/a&gt; - In progress will be fixed by &lt;a href="https://github.com/Seneca-CDOT/telescope/pull/2751"&gt;Pull request #2751&lt;/a&gt;, this one was a bit tough to do, it was either grab the username from the regex and do a call to the API of GitHub to check if real username, but with that solution, we'll hit the API rate in a second. The second solution is less perfect but will work, it was to hardcode the list of reserved names, and in the filter only grab the ULR that doesn't match the reserved names. I had a nice talk with Andrew, the one who created that, and since we cannot filter all the GitHub names, it could be considered as &lt;a href="https://en.wikipedia.org/wiki/Ostrich_algorithm"&gt;The Ostrich algorithm&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/Seneca-CDOT/telescope/issues/2731"&gt;Issue #2731&lt;/a&gt; - This is still in progress and with some discussion with the group that does react native, it will be done by Hung.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/Seneca-CDOT/telescope/issues/2732"&gt;Issue #2732&lt;/a&gt; - Issue open for discussion about the deployment of the react native app.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/Seneca-CDOT/telescope/issues/2733"&gt;Issue #2733&lt;/a&gt; - Issue open for discussion, and mainly will be done by AmasiaNalbandian. I will assist in reviewing Pull request.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/Seneca-CDOT/telescope/issues/2734"&gt;Issue #2734&lt;/a&gt; - Issue open for discussion, and probably mainly will be done by AmasiaNalbandian and DukeManh. I will assist in reviewing Pull request.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/Seneca-CDOT/telescope/issues/2745"&gt;Issue #2745&lt;/a&gt; - I will be working on this one, I have a sort of working version in my local, and will create a Draft pull request for feedback since I'm not too familiar with docker. Used this &lt;a href="https://docs.docker.com/engine/reference/builder/"&gt;documentation&lt;/a&gt; to complete this issue.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;One of the best quote:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Never be afraid to fail. Be afraid of not learning from mistakes. &lt;br&gt;
-- W. Brett Wilson &lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Open source is the place where you make mistakes and learn from it to become a better developer. &lt;/p&gt;

</description>
      <category>opensource</category>
    </item>
    <item>
      <title>test post Kevan</title>
      <dc:creator>Kevan Y</dc:creator>
      <pubDate>Thu, 27 Jan 2022 03:34:28 +0000</pubDate>
      <link>https://forem.com/pandanoxes/test-post-2j66</link>
      <guid>https://forem.com/pandanoxes/test-post-2j66</guid>
      <description>&lt;p&gt;&lt;a href="https://github.com/Seneca-CDOT/telescope/issues/2707"&gt;https://github.com/Seneca-CDOT/telescope/issues/2707&lt;/a&gt;&lt;br&gt;
&lt;a href="https://github.com/Seneca-ICTOER/Intro2C/issues/168"&gt;issue&lt;/a&gt;&lt;br&gt;
&lt;a href="https://github.com/Kevan-Y/Kryptfer/"&gt;https://github.com/Kevan-Y/Kryptfer/&lt;/a&gt;&lt;br&gt;
&lt;a href="https://github.com/milvus-io/milvus"&gt;repo&lt;/a&gt;&lt;br&gt;
&lt;a href="https://github.com/Seneca-CDOT/telescope/pull/2750"&gt;https://github.com/Seneca-CDOT/telescope/pull/2750&lt;/a&gt;&lt;br&gt;
&lt;a href="https://github.com/ppy/osu/pull/16637"&gt;pull&lt;/a&gt;&lt;br&gt;
&lt;a href="https://github.com/Andrewnt219"&gt;https://github.com/Andrewnt219&lt;/a&gt;&lt;br&gt;
&lt;a href="https://github.com/manekenpix/"&gt;manekenpix&lt;/a&gt;&lt;br&gt;
&lt;a href="https://github.com/datocms/"&gt;https://github.com/datocms/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/issues"&gt;https://github.com/issues&lt;/a&gt;&lt;br&gt;
&lt;a href="https://github.com/marketplace"&gt;https://github.com/marketplace&lt;/a&gt;&lt;br&gt;
&lt;a href="https://github.com/features/codespaces"&gt;https://github.com/features/codespaces&lt;/a&gt;&lt;/p&gt;

</description>
    </item>
  </channel>
</rss>
