Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

zitadel #15

Open
wants to merge 15 commits into
base: main
Choose a base branch
from
13 changes: 13 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
"@angular/router": "^17.2.0",
"@angular/ssr": "^17.2.3",
"@netlify/functions": "^2.6.0",
"angular-oauth2-oidc": "^17.0.2",
"buffer": "^6.0.3",
"chart.js": "^4.3.0",
"express": "^4.19.2",
Expand Down
2 changes: 2 additions & 0 deletions src/app/app.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import { register } from 'swiper/element/bundle';
import { HeaderComponent } from './layout/header/header.component';
import { FooterComponent } from './layout/footer/footer.component';
import { AnalyticsService } from './services/analytics.service';
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Tip

Codebase Verification

The codebase includes checks for isPlatformBrowser(this.platformId) in both src/app/app.component.ts and src/app/pages/landingpage/landingpage.component.ts. However, there is no clear indication of environment-specific configurations for analytics initialization.

  • src/app/app.component.ts initializes tracking in ngAfterViewInit if the platform is a browser.
  • src/app/pages/landingpage/landingpage.component.ts fetches articles if the platform is a browser.

There is no explicit differentiation between production and other environments in the provided context.

  • src/app/app.component.ts
  • src/app/pages/landingpage/landingpage.component.ts
Analysis chain

The integration of AnalyticsService for tracking page views is implemented correctly. Ensure that the tracking is configured appropriately for different environments.

Also applies to: 24-24, 38-38, 58-60

Scripts Executed

The following scripts were executed for the analysis:


Script:

#!/bin/bash
# Description: Verify that the analytics initialization is configured for production environments.

# Test: Search for environment-specific configurations in the codebase. Expect: Configurations that differentiate between production and other environments.
rg --type typescript $'if \(isPlatformBrowser\(this.platformId\)\) \{'

Length of output: 106



Script:

#!/bin/bash
# Description: Verify that the analytics initialization is configured for production environments.

# Test: Search for environment-specific configurations in the codebase. Expect: Configurations that differentiate between production and other environments.
rg --type ts 'if \(isPlatformBrowser\(this.platformId\)\) \{'

Length of output: 302



Script:

#!/bin/bash
# Description: Review the relevant lines in the identified files to check for environment-specific configurations.

# Display the relevant lines in `src/app/app.component.ts`
rg --type ts --context 5 'if \(isPlatformBrowser\(this.platformId\)\) \{' src/app/app.component.ts

# Display the relevant lines in `src/app/pages/landingpage/landingpage.component.ts`
rg --type ts --context 5 'if \(isPlatformBrowser\(this.platformId\)\) \{' src/app/pages/landingpage/landingpage.component.ts

Length of output: 974

import { AuthenticationService } from './services/authentication.service';

@Component({
selector: 'app-root',
Expand All @@ -20,6 +21,7 @@ export class AppComponent implements OnInit, AfterViewInit {

constructor(@Inject(PLATFORM_ID) private platformId: object,
@Inject(DOCUMENT) private document: Document,
private auth: AuthenticationService,
private router: Router,
private analytics: AnalyticsService,
private metaTagService: Meta) {
Expand Down
14 changes: 14 additions & 0 deletions src/app/app.config.browser.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import { mergeApplicationConfig, ApplicationConfig } from '@angular/core';
import { appConfig } from './app.config';
import { OAuthStorage } from 'angular-oauth2-oidc';

const browserConfig: ApplicationConfig = {
providers: [
{
provide: OAuthStorage,
useValue: localStorage,
}
]
};

export const config = mergeApplicationConfig(appConfig, browserConfig);
34 changes: 34 additions & 0 deletions src/app/app.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,27 @@ import { provideClientHydration } from '@angular/platform-browser';
import { provideHttpClient, withFetch } from '@angular/common/http';
import { ArrowDownNarrowWide, ArrowDownWideNarrow, BookText, Box, Check, ChevronDown, ChevronLeft, ChevronRight, Codesandbox, Cpu, Database, DollarSign, Facebook, Github, Home, Hotel, Linkedin, LucideAngularModule, MemoryStick, PcCase, Search, Server, SquareKanban, Twitter, User, Building2, Heater, CandlestickChart, MapPinned, Scale, Ellipsis, Menu, Leaf, ShoppingCart, ChevronUp, ExternalLink, Info } from 'lucide-angular';
import { MarkdownModule } from 'ngx-markdown';
import { AuthConfig, OAuthModule } from 'angular-oauth2-oidc';
import { provideCharts, withDefaultRegisterables } from 'ng2-charts';

const ZITADEL_CLIENT_ID = import.meta.env['NG_APP_ZITADEL_CLIENT_ID'];
const ZITADEL_DOMAIN = import.meta.env['NG_APP_ZITADEL_DOMAIN'];
const ZITADEL_USERINFO_ENDPOINT = import.meta.env['NG_APP_ZITADEL_USERINFO_ENDPOINT'];
Palabola marked this conversation as resolved.
Show resolved Hide resolved
const DOMAIN_BASE_URL = import.meta.env['NG_APP_DOMAIN_BASE_URL'];

const authConfig: AuthConfig = {
scope: 'openid profile email offline_access',
responseType: 'code',
oidc: true,
clientId: ZITADEL_CLIENT_ID,
issuer: ZITADEL_DOMAIN,
redirectUri: `${DOMAIN_BASE_URL}auth/callback`,
postLogoutRedirectUri: `${DOMAIN_BASE_URL}`,
requireHttps: false, // required for running locally
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ensure requireHttps is set to true in production to enhance security by enforcing HTTPS.

tokenEndpoint: `${ZITADEL_DOMAIN}/oauth/v2/token`,
userinfoEndpoint: ZITADEL_USERINFO_ENDPOINT,
};
Comment on lines +12 to +28
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Document the OAuth configuration settings in the README.md to ensure they are easily understandable and maintainable.


export const appConfig: ApplicationConfig = {
providers: [
provideRouter(routes),
Expand Down Expand Up @@ -55,6 +74,21 @@ export const appConfig: ApplicationConfig = {
}),
),
importProvidersFrom(MarkdownModule.forRoot()),
importProvidersFrom(
OAuthModule.forRoot({
resourceServer: {
allowedUrls: [
`${ZITADEL_DOMAIN}/admin/v1`,
`${ZITADEL_DOMAIN}/management/v1`,
`${ZITADEL_DOMAIN}/auth/v1/`],
sendAccessToken: true,
},
})
),
{
provide: AuthConfig,
useValue: authConfig,
}
],

};
9 changes: 9 additions & 0 deletions src/app/app.routes.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { Routes } from '@angular/router';
import { LandingpageComponent } from './pages/landingpage/landingpage.component';
import { ServerListingComponent } from './pages/server-listing/server-listing.component';
import { authGuard } from './guards/auth.guard';

export const routes: Routes = [
{ path: '', component: LandingpageComponent },
Expand All @@ -11,5 +12,13 @@ export const routes: Routes = [
{ path: 'legal/tos', loadComponent: () => import('./pages/tos/tos.component').then(m => m.TOSComponent)},
{ path: 'datacenters', loadComponent: () => import('./pages/datacenters/datacenters.component').then(m => m.DatacentersComponent)},
{ path: 'vendors', loadComponent: () => import('./pages/vendors/vendors.component').then(m => m.VendorsComponent)},

{ path: 'auth/callback', loadComponent: () => import('./auth/callback/callback.component').then(m => m.CallbackComponent)},

{ path: 'dashboard',
loadComponent: () => import('./pages/my-spare-cores/my-spare-cores.component').then(m => m.MySpareCoresComponent),
canActivate: [authGuard]
},

{ path: '**', redirectTo: '' }
];
4 changes: 4 additions & 0 deletions src/app/auth/callback/callback.component.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
<div class="w-full">
<div class="content_section">
</div>
</div>
7 changes: 7 additions & 0 deletions src/app/auth/callback/callback.component.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
.content_section {
@apply bg-primary;
@apply text-white;

padding: 4rem 2rem;
height: 100vh;
}
23 changes: 23 additions & 0 deletions src/app/auth/callback/callback.component.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';

import { CallbackComponent } from './callback.component';

describe('CallbackComponent', () => {
let component: CallbackComponent;
let fixture: ComponentFixture<CallbackComponent>;

beforeEach(async () => {
await TestBed.configureTestingModule({
imports: [CallbackComponent]
})
.compileComponents();

fixture = TestBed.createComponent(CallbackComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});

it('should create', () => {
expect(component).toBeTruthy();
});
Palabola marked this conversation as resolved.
Show resolved Hide resolved
});
33 changes: 33 additions & 0 deletions src/app/auth/callback/callback.component.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import { Component, Inject, OnInit, PLATFORM_ID } from '@angular/core';
import { AuthenticationService } from '../../services/authentication.service';
import { Router, RouterModule } from '@angular/router';
import { isPlatformBrowser } from '@angular/common';

@Component({
selector: 'app-callback',
standalone: true,
imports: [RouterModule],
templateUrl: './callback.component.html',
styleUrl: './callback.component.scss'
})
export class CallbackComponent implements OnInit{

constructor(
@Inject(PLATFORM_ID) private platformId: object,
private authService: AuthenticationService,
private router: Router
) { }

ngOnInit() {

if(isPlatformBrowser(this.platformId)) {
this.authService.loginCodeFlow().then(() => {
const url = sessionStorage.getItem('prelogin_url') || '/';
sessionStorage.removeItem('prelogin_url');
this.router.navigateByUrl(url);
});
}

}

}
17 changes: 17 additions & 0 deletions src/app/guards/auth.guard.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import { TestBed } from '@angular/core/testing';
import { CanActivateFn } from '@angular/router';

import { authGuard } from './auth.guard';

describe('authGuard', () => {
const executeGuard: CanActivateFn = (...guardParameters) =>
TestBed.runInInjectionContext(() => authGuard(...guardParameters));

beforeEach(() => {
TestBed.configureTestingModule({});
});

it('should be created', () => {
expect(executeGuard).toBeTruthy();
});
});
22 changes: 22 additions & 0 deletions src/app/guards/auth.guard.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import { CanActivateFn } from '@angular/router';
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Convert imports to type-only imports to clarify their usage.

- import { CanActivateFn } from '@angular/router';
- import { AuthenticationService } from '../services/authentication.service';
+ import type { CanActivateFn } from '@angular/router';
+ import type { AuthenticationService } from '../services/authentication.service';

Committable suggestion was skipped due low confidence.

import { AuthenticationService } from '../services/authentication.service';
import { inject } from '@angular/core';
import { map, take } from 'rxjs';

export const authGuard: CanActivateFn = () => {

const authService = inject(AuthenticationService);

return authService.authedState.pipe(
take(1), // Otherwise the Observable doesn't complete!
map((isAuthenticated) => {
if (isAuthenticated) {
return true
} else {
authService.authenticate();
return authService.isLoggedIn();
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Consider simplifying the guard logic by removing the unnecessary else clause.

-      } else {
-        authService.authenticate();
-        return authService.isLoggedIn();
-      }

Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation.

Suggested change
} else {
authService.authenticate();
return authService.isLoggedIn();
}

})
);

};
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Simplify the guard logic by removing the unnecessary else clause.

-      } else {
-        authService.authenticate();
-        return authService.isLoggedIn();
-      }

Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation.

Suggested change
export const authGuard: CanActivateFn = () => {
const authService = inject(AuthenticationService);
return authService.authedState.pipe(
take(1), // Otherwise the Observable doesn't complete!
map((isAuthenticated) => {
if (isAuthenticated) {
return true
} else {
authService.authenticate();
return authService.isLoggedIn();
}
})
);
};
export const authGuard: CanActivateFn = () => {
const authService = inject(AuthenticationService);
return authService.authedState.pipe(
take(1), // Otherwise the Observable doesn't complete!
map((isAuthenticated) => {
if (isAuthenticated) {
return true
}
authService.authenticate();
return authService.isLoggedIn();
})
);
};

24 changes: 19 additions & 5 deletions src/app/layout/header/header.component.html
Original file line number Diff line number Diff line change
Expand Up @@ -19,27 +19,41 @@
Datacenters
</a>
</li>
<li class="hidden lg:flex">
<li *ngIf="!isLoggedIn()" class="hidden lg:flex">
<a class="navbar_link" routerLink="/vendors" >
<lucide-icon class="h-4 w-4" name="home"></lucide-icon>
Vendors
</a>
</li>
<li *ngIf="isLoggedIn()" class="hidden lg:flex">
<a class="navbar_link" routerLink="/dashboard" >
<lucide-icon class="h-4 w-4" name="home"></lucide-icon>
My Spare Cores
</a>
</li>
<li class="lg:hidden">
<lucide-icon
class="navbar_link cursor-pointer h-8 w-8"
data-dropdown-toggle="menu_options"
name="menu" >
</lucide-icon>
</li>
<!--
<li>
<button class="login_button text-sm items-center">
<li *ngIf="!isLoggedIn()">
<button
class="login_button text-sm items-center"
(click)="login()">
<lucide-icon name="user" class="h-4 w-4 mr-1"></lucide-icon>
Log in
</button>
</li>
-->
<li *ngIf="isLoggedIn()">
<button
class="login_button text-sm items-center"
(click)="logout()">
<lucide-icon name="user" class="h-4 w-4 mr-1"></lucide-icon>
Log out
</button>
</li>
</ul>
</div>
</div>
Expand Down
24 changes: 22 additions & 2 deletions src/app/layout/header/header.component.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,34 @@
import { Component } from '@angular/core';
import { RouterLink } from '@angular/router';
import { LucideAngularModule } from 'lucide-angular';
import { AuthenticationService } from '../../services/authentication.service';
import { CommonModule } from '@angular/common';
Comment on lines 3 to +5
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Review the import usage as they are only used as types.

Consider using TypeScript's import type to explicitly indicate that these imports are only used for type checking. This can help with clarity and potentially optimize bundling processes.

- import { AuthenticationService } from '../../services/authentication.service';
- import { CommonModule } from '@angular/common';
+ import type { AuthenticationService } from '../../services/authentication.service';
+ import type { CommonModule } from '@angular/common';

Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation.

Suggested change
import { LucideAngularModule } from 'lucide-angular';
import { AuthenticationService } from '../../services/authentication.service';
import { CommonModule } from '@angular/common';
import { LucideAngularModule } from 'lucide-angular';
import type { AuthenticationService } from '../../services/authentication.service';
import type { CommonModule } from '@angular/common';


@Component({
selector: 'app-header',
standalone: true,
imports: [LucideAngularModule, RouterLink],
imports: [LucideAngularModule, RouterLink, CommonModule],
templateUrl: './header.component.html',
styleUrl: './header.component.scss'
styleUrl: './header.component.scss',
// eslint-disable-next-line @angular-eslint/no-host-metadata-property
host: {ngSkipHydration: 'true'},
})
export class HeaderComponent {

constructor(
private authService: AuthenticationService
) { }

isLoggedIn() {
return this.authService.isLoggedIn();
}

login() {
this.authService.authenticate();
}
Palabola marked this conversation as resolved.
Show resolved Hide resolved

logout() {
this.authService.signout();
}

}
33 changes: 33 additions & 0 deletions src/app/pages/my-spare-cores/my-spare-cores.component.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
<div class="w-full bg-primary">
<div class="content pt-16 pb-16">
<app-breadcrumbs [segments]="breadcrumbs"></app-breadcrumbs>

<div class="flex flex-col gap-4 my-8">
<h1 class="text-white font-bold text-3xl">Cloud Compute Resources listing</h1>
<div class="text-white text-xl pr-16">
Explore, search and evaluate cloud compute resources and pricing in the table below. This comprehensive comparison includes diverse attributes like CPU count, detailed processor information, memory, GPU, storage, network speed and amount, available operating systems, and pricing models such as spot and on-demand. Use the sidebar for filtering the results, or enter your phrase in the “Search prompt” bar.
</div>
</div>

<div class="flex gap-8">
<div class="filter_bar bg-primary">
<div class="filters overflow-hidden bg-secondary">
</div>
</div>
<div class=" list_holder flex flex-col gap-4 limited-full">
<div class="top_buttons w-full flex justify-end gap-6 items-center" >

</div>
<div>
<div class="w-full overflow-x-auto relative" style="padding-left: 1px;">


</div>

</div>
</div>

</div>

</div>
</div>
Loading