This is an automated email from the ASF dual-hosted git repository.

shamrick pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/trafficcontrol.git


The following commit(s) were added to refs/heads/master by this push:
     new 814a979a7c tpv2 redirect to tpv1 (#7585)
814a979a7c is described below

commit 814a979a7c66fbd547a5253374689e63d185e8c6
Author: Kannan.G.B <[email protected]>
AuthorDate: Thu Jul 27 23:09:13 2023 +0530

    tpv2 redirect to tpv1 (#7585)
    
    * tpv2 redirect to tpv1
    
    * tpv1 url added from server side loading
    
    * tpv1url config added
    
    * tpv1url config added
    
    * lint error fix
    
    * localstorage
    
    * comments addressed
    
    * comments addressed
    
    * config changes for integration test
---
 .github/actions/tpv2-integration-tests/config.json |  1 +
 experimental/traffic-portal/server.config.ts       | 54 +++++++++++++++-------
 experimental/traffic-portal/server.ts              | 19 +++++++-
 .../traffic-portal/src/app/app.component.ts        | 19 +++++++-
 .../app/shared/navigation/navigation.service.ts    | 50 ++++++++++++++++++--
 .../tp-sidebar/tp-sidebar.component.html           | 21 +++++++--
 .../navigation/tp-sidebar/tp-sidebar.component.ts  | 11 +++++
 .../src/environments/environment.prod.ts           |  2 +-
 .../traffic-portal/src/environments/environment.ts |  2 +-
 9 files changed, 152 insertions(+), 27 deletions(-)

diff --git a/.github/actions/tpv2-integration-tests/config.json 
b/.github/actions/tpv2-integration-tests/config.json
index 2664c0cb6c..00d1287511 100644
--- a/.github/actions/tpv2-integration-tests/config.json
+++ b/.github/actions/tpv2-integration-tests/config.json
@@ -2,6 +2,7 @@
   "insecure": true,
   "port": 4200,
   "trafficOps": "https://localhost:6443";,
+  "tpv1Url": "https://localhost";,
   "useSSL": false,
   "browserFolder": "$GITHUB_WORKSPACE/$BROWSER_FOLDER"
 }
diff --git a/experimental/traffic-portal/server.config.ts 
b/experimental/traffic-portal/server.config.ts
index 12dcff7fdf..ce552ca83b 100644
--- a/experimental/traffic-portal/server.config.ts
+++ b/experimental/traffic-portal/server.config.ts
@@ -15,6 +15,7 @@
 import { execSync } from "child_process";
 import { existsSync, readFileSync } from "fs";
 import { join } from "path";
+import { hasProperty } from "src/app/utils";
 
 /**
  * ServerVersion contains versioning information for the server,
@@ -139,6 +140,8 @@ interface BaseConfig {
        version: ServerVersion;
        /** Path to the folder containing browser files. **/
        browserFolder: string;
+       /** The URL of the Traffic Portal V1. */
+       tpv1Url: URL;
 }
 
 /**
@@ -183,53 +186,65 @@ function isConfig(c: unknown): c is ServerConfig {
                throw new Error("'null' is not a valid configuration");
        }
 
-       if (Object.prototype.hasOwnProperty.call(c, "insecure")) {
-               if (typeof((c as {insecure: unknown}).insecure) !== "boolean") {
+       if (hasProperty(c, "insecure")) {
+               if (typeof(c.insecure) !== "boolean") {
                        throw new Error("'insecure' must be a boolean");
                }
        } else {
                (c as {insecure: boolean}).insecure = false;
        }
-       if (!Object.prototype.hasOwnProperty.call(c, "port")) {
+       if (!hasProperty(c, "port")) {
                throw new Error("'port' is required");
        }
-       if (typeof((c as {port: unknown}).port) !== "number") {
+       if (typeof(c.port) !== "number") {
                throw new Error("'port' must be a number");
        }
-       if (!Object.prototype.hasOwnProperty.call(c, "trafficOps")) {
+       if (!hasProperty(c, "trafficOps")){
                throw new Error("'trafficOps' is required");
        }
-       if (typeof((c as {trafficOps: unknown}).trafficOps) !== "string") {
+       if (typeof(c.trafficOps) !== "string") {
                throw new Error("'trafficOps' must be a string");
        }
-       if (!Object.prototype.hasOwnProperty.call(c, "browserFolder")) {
+       if(!hasProperty(c, "tpv1Url")){
+               throw new Error("'tpv1Url' is required");
+       }
+       if (typeof(c.tpv1Url) !== "string") {
+               throw new Error("'tpv1Url' must be a string");
+       }
+       if (!hasProperty(c, "browserFolder")) {
                throw new Error("'browserFolder' is required");
        }
-       if (typeof((c as {browserFolder: unknown}).browserFolder) !== "string") 
{
+       if (typeof(c.browserFolder) !== "string") {
                throw new Error("'browserFolder' must be a string");
        }
 
        try {
-               (c as {trafficOps: URL}).trafficOps = new URL((c as 
{trafficOps: string}).trafficOps);
+               c.trafficOps = new URL(c.trafficOps);
        } catch (e) {
                throw new Error(`'trafficOps' is not a valid URL: ${e}`);
        }
 
-       if (Object.prototype.hasOwnProperty.call(c, "useSSL")) {
-               if (typeof((c as {useSSL: unknown}).useSSL) !== "boolean") {
+       try {
+               c.tpv1Url = new URL(c.tpv1Url);
+       } catch (e) {
+               throw new Error(`'tpv1Url' is not a valid URL: ${e}`);
+       }
+
+       if (hasProperty(c, "useSSL")) {
+               if (typeof(c.useSSL) !== "boolean") {
                        throw new Error("'useSSL' must be a boolean");
                }
-               if ((c as {useSSL: boolean}).useSSL) {
-                       if (!Object.prototype.hasOwnProperty.call(c, 
"certPath")) {
+               if (c.useSSL) {
+                       if (!hasProperty(c, "certPath")) {
                                throw new Error("'certPath' is required to use 
SSL");
                        }
-                       if (typeof((c as {certPath: unknown}).certPath) !== 
"string") {
+                       if (typeof(c.certPath) !== "string") {
                                throw new Error("'certPath' must be a string");
                        }
-                       if (!Object.prototype.hasOwnProperty.call(c, 
"keyPath")) {
+                       if (!hasProperty(c, "keyPath")) {
                                throw new Error("'keyPath' is required to use 
SSL");
                        }
-                       if (typeof((c as {keyPath: unknown}).keyPath) !== 
"string") {
+                       if (typeof(c.keyPath) !== "string") {
                                throw new Error("'keyPath' must be a string");
                        }
                }
@@ -296,6 +311,7 @@ export function getVersion(path?: string): ServerVersion {
 /** The type of command line arguments to Traffic Portal. */
 interface Args {
        trafficOps?: URL;
+       tpv1Url?: URL;
        insecure: boolean;
        port: number;
        certPath?: string;
@@ -311,6 +327,7 @@ export const defaultConfig: ServerConfig = {
        insecure: false,
        port: 4200,
        trafficOps: new URL("https://example.com";),
+       tpv1Url: new URL("https://example.com";),
        version: { version: "" }
 };
 /**
@@ -372,6 +389,10 @@ export function getConfig(args: Args, ver: ServerVersion): 
ServerConfig {
                }
        }
 
+       if (args.tpv1Url) {
+               cfg.tpv1Url = args.tpv1Url;
+       }
+
        if (readFromFile && cfg.useSSL) {
                if (args.certPath) {
                        cfg.certPath = args.certPath;
@@ -392,6 +413,7 @@ export function getConfig(args: Args, ver: ServerVersion): 
ServerConfig {
                                keyPath: args.keyPath,
                                port: cfg.port,
                                trafficOps: cfg.trafficOps,
+                               tpv1Url: cfg.tpv1Url,
                                useSSL: true,
                                version: ver
                        };
diff --git a/experimental/traffic-portal/server.ts 
b/experimental/traffic-portal/server.ts
index f5f615d122..78702d2ddc 100644
--- a/experimental/traffic-portal/server.ts
+++ b/experimental/traffic-portal/server.ts
@@ -192,7 +192,10 @@ export function app(serverConfig: ServerConfig): 
express.Express {
 
        // All regular routes use the Universal engine
        server.get("*", (req, res) => {
-               res.render(indexHtml, {providers: [{provide: APP_BASE_HREF, 
useValue: req.baseUrl}], req});
+               res.render(indexHtml, {providers: [
+                       {provide: APP_BASE_HREF, useValue: req.baseUrl},
+                       {provide: "TP_V1_URL", useValue: config.tpv1Url}
+               ], req});
        });
 
        server.enable("trust proxy");
@@ -227,6 +230,20 @@ function run(): number {
                        }
                }
        });
+       parser.add_argument("-u", "--tpv1-url", {
+               dest: "tpv1Url",
+               help: "Specify the Traffic Portal v1 URL. (Default: uses the 
`TP_V1_URL` environment variable)",
+               type: (arg: string) => {
+                       try {
+                               return new URL(arg);
+                       } catch (e) {
+                               if (e instanceof TypeError) {
+                                       return new URL(`https://${arg}`);
+                               }
+                               throw e;
+                       }
+               }
+       });
        parser.add_argument("-k", "--insecure", {
                action: "store_true",
                help: "Skip Traffic Ops server certificate validation. This 
affects requests from Traffic Portal to Traffic Ops AND signature" +
diff --git a/experimental/traffic-portal/src/app/app.component.ts 
b/experimental/traffic-portal/src/app/app.component.ts
index 55007fd29e..601387e47f 100644
--- a/experimental/traffic-portal/src/app/app.component.ts
+++ b/experimental/traffic-portal/src/app/app.component.ts
@@ -12,12 +12,15 @@
 * limitations under the License.
 */
 
-import {Component, OnInit} from "@angular/core";
+import { isPlatformBrowser } from "@angular/common";
+import { Component, Inject, OnInit, Optional, PLATFORM_ID, TransferState, 
makeStateKey } from "@angular/core";
 import { Router } from "@angular/router";
 import { ResponseCurrentUser } from "trafficops-types";
 
 import { CurrentUserService } from 
"src/app/shared/current-user/current-user.service";
 
+export const LOCAL_TPV1_URL = "tp_v1_url";
+
 /**
  * The most basic component that contains everything else. This should be kept 
pretty simple.
  */
@@ -31,7 +34,19 @@ export class AppComponent implements OnInit {
        /** The currently logged-in user */
        public currentUser: ResponseCurrentUser | null = null;
 
-       constructor(private readonly router: Router, private readonly auth: 
CurrentUserService) {
+       constructor(private readonly router: Router, private readonly auth: 
CurrentUserService,
+               @Inject(PLATFORM_ID) private readonly platformId: object,
+               @Optional() @Inject("TP_V1_URL") public tpv1url: string,
+               private readonly transferState: TransferState) {
+               const storeKey = makeStateKey<string>("messageKey");
+
+               // get data from transferState if browser side
+               if (isPlatformBrowser(this.platformId)) {
+                       this.tpv1url = this.transferState.get(storeKey, 
"https://localhost";);
+                       window.localStorage.setItem(LOCAL_TPV1_URL, 
this.tpv1url);
+               } else { // server side: get provided tpv1 url and store in in 
transfer state
+                       this.transferState.set(storeKey, this.tpv1url);
+               }
        }
 
        /**
diff --git 
a/experimental/traffic-portal/src/app/shared/navigation/navigation.service.ts 
b/experimental/traffic-portal/src/app/shared/navigation/navigation.service.ts
index f76aa12b93..3130756f97 100644
--- 
a/experimental/traffic-portal/src/app/shared/navigation/navigation.service.ts
+++ 
b/experimental/traffic-portal/src/app/shared/navigation/navigation.service.ts
@@ -11,10 +11,12 @@
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
-import { Injectable } from "@angular/core";
+import { isPlatformBrowser } from "@angular/common";
+import { Inject, Injectable, PLATFORM_ID } from "@angular/core";
 import { ReplaySubject } from "rxjs";
 
 import { UserService } from "src/app/api";
+import { LOCAL_TPV1_URL } from "src/app/app.component";
 import { CurrentUserService } from 
"src/app/shared/current-user/current-user.service";
 
 /**
@@ -60,8 +62,15 @@ export class NavigationService {
 
        private readonly horizontalNavs: Map<string, HeaderNavigation>;
        private readonly verticalNavs: Map<string, HeaderNavigation>;
+       private readonly tpv1Url: string = "http:localhost:433";
 
-       constructor(private readonly auth: CurrentUserService, private readonly 
api: UserService) {
+       constructor(
+               private readonly auth: CurrentUserService,
+               private readonly api: UserService,
+               @Inject(PLATFORM_ID) private readonly platformId: object) {
+               if (isPlatformBrowser(this.platformId)) {
+                       this.tpv1Url = 
window.localStorage.getItem(LOCAL_TPV1_URL) ?? this.tpv1Url;
+               }
                this.horizontalNavs = new Map<string, HeaderNavigation>([
                        ["Home", {
                                routerLink: "/core",
@@ -153,11 +162,38 @@ export class NavigationService {
                                        name: "Cache Groups"
                                }],
                        name: "Servers"
+               }, {
+                       children: [
+                               {
+                                       href: `${this.tpv1Url}/cache-checks`,
+                                       name: "Cache Checks"
+                               },
+                               {
+                                       href: `${this.tpv1Url}/cache-stats`,
+                                       name: "Cache Stats"
+                               }
+                       ],
+                       name: "Monitor"
+               }, {
+                       children: [
+                               {
+                                       href: 
`${this.tpv1Url}/delivery-services`,
+                                       name: "Delivery Services"
+                               },
+                               {
+                                       href: 
`${this.tpv1Url}/delivery-service-requests`,
+                                       name: "Delivery Service Requests"
+                               }
+                       ],
+                       name: "Services"
                }, {
                        children: [
                                {
                                        href: "/core/types",
                                        name: "Types"
+                               }, {
+                                       href: `${this.tpv1Url}/origins`,
+                                       name: "Origins"
                                },
                                {
                                        href: "/core/parameters",
@@ -193,7 +229,15 @@ export class NavigationService {
                                {
                                        href: "/core/iso-gen",
                                        name: "Generate System ISO"
-                               }
+                               },
+                               {
+                                       href: `${this.tpv1Url}/jobs`,
+                                       name: "Invalidate Content"
+                               },
+                               {
+                                       href: `${this.tpv1Url}/notifications`,
+                                       name: "Notifications"
+                               },
                        ],
                        name: "Other"
                }]);
diff --git 
a/experimental/traffic-portal/src/app/shared/navigation/tp-sidebar/tp-sidebar.component.html
 
b/experimental/traffic-portal/src/app/shared/navigation/tp-sidebar/tp-sidebar.component.html
index a2fb6b3fbf..b28d6be4ce 100644
--- 
a/experimental/traffic-portal/src/app/shared/navigation/tp-sidebar/tp-sidebar.component.html
+++ 
b/experimental/traffic-portal/src/app/shared/navigation/tp-sidebar/tp-sidebar.component.html
@@ -17,9 +17,24 @@ limitations under the License.
                <div id="sidenav-container">
                        <mat-tree [dataSource]="dataSource" 
[treeControl]="treeCtrl" id="sidebar-nav-tree">
                                <mat-tree-node *matTreeNodeDef="let node" 
matTreeNodeToggle>
-                                       <a class="mat-tree-node" mat-menu-item 
[attr.aria-label]="'Navigate to ' + node.name" [routerLink]="node.href" 
[routerLinkActive]="['boldNode']" [routerLinkActiveOptions]="routeOptions">
-                                               {{node.name}}
-                                       </a>
+                                       <!-- load either redirect or relative 
path href -->
+                                       <div *ngIf="isAbsoluteURL(node.href); 
then absolute else relative"></div>
+                               
+                                       <!-- Checking whether href is relative 
URL -->
+                                       <ng-template #relative>
+                                               <a class="mat-tree-node" 
mat-menu-item [attr.aria-label]="'Navigate to ' + node.name" 
[routerLink]="node.href"
+                                                       
[routerLinkActive]="['boldNode']" [routerLinkActiveOptions]="routeOptions">
+                                                       {{node.name}}
+                                               </a>
+                                       </ng-template>
+                               
+                                       <!-- Checking whether href is absolute 
URL - For TPv1 redirect purpose -->
+                                       <ng-template #absolute>
+                                               <a class="mat-tree-node" 
mat-menu-item [attr.aria-label]="'Navigate to ' + node.name" [href]="node.href"
+                                                       target="_blank">
+                                                       {{node.name}}
+                                               </a>
+                                       </ng-template>
                                </mat-tree-node>
                                <mat-nested-tree-node *matTreeNodeDef="let 
node; when: hasChild">
                                        <div class="mat-tree-node" 
matTreeNodeToggle mat-menu-item [attr.aria-label]="'Toggle ' + node.name" >
diff --git 
a/experimental/traffic-portal/src/app/shared/navigation/tp-sidebar/tp-sidebar.component.ts
 
b/experimental/traffic-portal/src/app/shared/navigation/tp-sidebar/tp-sidebar.component.ts
index 9a723bc8bb..61fd89d8f0 100644
--- 
a/experimental/traffic-portal/src/app/shared/navigation/tp-sidebar/tp-sidebar.component.ts
+++ 
b/experimental/traffic-portal/src/app/shared/navigation/tp-sidebar/tp-sidebar.component.ts
@@ -187,4 +187,15 @@ export class TpSidebarComponent implements OnInit, 
AfterViewInit {
        public nodeHandle(node: TreeNavNode): string {
                return `${node.name}${node.href ?? ""}`;
        }
+
+       /**
+        * Determines whether href is absolute or not - for TPv2 to TPv1 
redirect
+        *
+        * @param href route string
+        * @returns true if href absolute
+        */
+       public isAbsoluteURL(href: string): boolean {
+               const regexPattern = /^(?:[a-z]+:)?\/\//i;
+               return regexPattern.test(href);
+       }
 }
diff --git a/experimental/traffic-portal/src/environments/environment.prod.ts 
b/experimental/traffic-portal/src/environments/environment.prod.ts
index 27807dd4fa..085d3abc54 100644
--- a/experimental/traffic-portal/src/environments/environment.prod.ts
+++ b/experimental/traffic-portal/src/environments/environment.prod.ts
@@ -21,5 +21,5 @@ import type { Environment } from "./environment.type";
 export const environment: Environment = {
        apiVersion: "4.0",
        customModule: false,
-       production: true
+       production: true,
 };
diff --git a/experimental/traffic-portal/src/environments/environment.ts 
b/experimental/traffic-portal/src/environments/environment.ts
index 325ba4fcf2..7fca62c2b7 100644
--- a/experimental/traffic-portal/src/environments/environment.ts
+++ b/experimental/traffic-portal/src/environments/environment.ts
@@ -26,5 +26,5 @@ export const environment: Environment = {
        apiVersion: "4.0",
        customModule: false,
        production: false,
-       useExhaustiveDates: true
+       useExhaustiveDates: true,
 };

Reply via email to