autocomit
This commit is contained in:
+123
-123
@@ -12,139 +12,139 @@ export const routes: Routes = [
|
||||
loadComponent: () => import('./core/auth/login/login.component').then(m => m.LoginComponent)
|
||||
},
|
||||
{
|
||||
path: 'dashboard',
|
||||
canActivate: [authGuard],
|
||||
loadComponent: () => import('./features/dashboard/dashboard.component').then(m => m.DashboardComponent)
|
||||
},
|
||||
{
|
||||
path: 'business-units',
|
||||
path: '',
|
||||
canActivate: [authGuard],
|
||||
loadComponent: () => import('./core/layout/main-layout/main-layout.component').then(m => m.MainLayoutComponent),
|
||||
children: [
|
||||
{
|
||||
path: '',
|
||||
loadComponent: () => import('./features/business-units/business-unit-list/business-unit-list.component')
|
||||
.then(m => m.BusinessUnitListComponent)
|
||||
path: 'dashboard',
|
||||
loadComponent: () => import('./features/dashboard/dashboard.component').then(m => m.DashboardComponent)
|
||||
},
|
||||
{
|
||||
path: 'new',
|
||||
loadComponent: () => import('./features/business-units/business-unit-form/business-unit-form.component')
|
||||
.then(m => m.BusinessUnitFormComponent)
|
||||
path: 'business-units',
|
||||
children: [
|
||||
{
|
||||
path: '',
|
||||
loadComponent: () => import('./features/business-units/business-unit-list/business-unit-list.component')
|
||||
.then(m => m.BusinessUnitListComponent)
|
||||
},
|
||||
{
|
||||
path: 'new',
|
||||
loadComponent: () => import('./features/business-units/business-unit-form/business-unit-form.component')
|
||||
.then(m => m.BusinessUnitFormComponent)
|
||||
},
|
||||
{
|
||||
path: ':id',
|
||||
loadComponent: () => import('./features/business-units/business-unit-detail/business-unit-detail.component')
|
||||
.then(m => m.BusinessUnitDetailComponent)
|
||||
},
|
||||
{
|
||||
path: ':id/edit',
|
||||
loadComponent: () => import('./features/business-units/business-unit-form/business-unit-form.component')
|
||||
.then(m => m.BusinessUnitFormComponent)
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
path: ':id',
|
||||
loadComponent: () => import('./features/business-units/business-unit-detail/business-unit-detail.component')
|
||||
.then(m => m.BusinessUnitDetailComponent)
|
||||
path: 'applications',
|
||||
children: [
|
||||
{
|
||||
path: '',
|
||||
loadComponent: () => import('./features/applications/application-list/application-list.component')
|
||||
.then(m => m.ApplicationListComponent)
|
||||
},
|
||||
{
|
||||
path: 'new',
|
||||
loadComponent: () => import('./features/applications/application-form/application-form.component')
|
||||
.then(m => m.ApplicationFormComponent)
|
||||
},
|
||||
{
|
||||
path: ':id',
|
||||
loadComponent: () => import('./features/applications/application-detail/application-detail.component')
|
||||
.then(m => m.ApplicationDetailComponent)
|
||||
},
|
||||
{
|
||||
path: ':id/edit',
|
||||
loadComponent: () => import('./features/applications/application-form/application-form.component')
|
||||
.then(m => m.ApplicationFormComponent)
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
path: ':id/edit',
|
||||
loadComponent: () => import('./features/business-units/business-unit-form/business-unit-form.component')
|
||||
.then(m => m.BusinessUnitFormComponent)
|
||||
path: 'environments',
|
||||
children: [
|
||||
{
|
||||
path: '',
|
||||
loadComponent: () => import('./features/environments/environment-list/environment-list.component')
|
||||
.then(m => m.EnvironmentListComponent)
|
||||
},
|
||||
{
|
||||
path: 'new',
|
||||
loadComponent: () => import('./features/environments/environment-form/environment-form.component')
|
||||
.then(m => m.EnvironmentFormComponent)
|
||||
},
|
||||
{
|
||||
path: ':id',
|
||||
loadComponent: () => import('./features/environments/environment-detail/environment-detail.component')
|
||||
.then(m => m.EnvironmentDetailComponent)
|
||||
},
|
||||
{
|
||||
path: ':id/edit',
|
||||
loadComponent: () => import('./features/environments/environment-form/environment-form.component')
|
||||
.then(m => m.EnvironmentFormComponent)
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
path: 'persons',
|
||||
children: [
|
||||
{
|
||||
path: '',
|
||||
loadComponent: () => import('./features/persons/person-list/person-list.component')
|
||||
.then(m => m.PersonListComponent)
|
||||
},
|
||||
{
|
||||
path: 'new',
|
||||
loadComponent: () => import('./features/persons/person-form/person-form.component')
|
||||
.then(m => m.PersonFormComponent)
|
||||
},
|
||||
{
|
||||
path: ':id',
|
||||
loadComponent: () => import('./features/persons/person-detail/person-detail.component')
|
||||
.then(m => m.PersonDetailComponent)
|
||||
},
|
||||
{
|
||||
path: ':id/edit',
|
||||
loadComponent: () => import('./features/persons/person-form/person-form.component')
|
||||
.then(m => m.PersonFormComponent)
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
path: 'contacts',
|
||||
children: [
|
||||
{
|
||||
path: '',
|
||||
loadComponent: () => import('./features/contacts/contact-list/contact-list.component')
|
||||
.then(m => m.ContactListComponent)
|
||||
},
|
||||
{
|
||||
path: 'new',
|
||||
loadComponent: () => import('./features/contacts/contact-form/contact-form.component')
|
||||
.then(m => m.ContactFormComponent)
|
||||
},
|
||||
{
|
||||
path: ':id',
|
||||
loadComponent: () => import('./features/contacts/contact-detail/contact-detail.component')
|
||||
.then(m => m.ContactDetailComponent)
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
path: 'contact-roles',
|
||||
loadComponent: () => import('./features/contacts/contact-role-list/contact-role-list.component')
|
||||
.then(m => m.ContactRoleListComponent)
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
path: 'applications',
|
||||
canActivate: [authGuard],
|
||||
children: [
|
||||
{
|
||||
path: '',
|
||||
loadComponent: () => import('./features/applications/application-list/application-list.component')
|
||||
.then(m => m.ApplicationListComponent)
|
||||
},
|
||||
{
|
||||
path: 'new',
|
||||
loadComponent: () => import('./features/applications/application-form/application-form.component')
|
||||
.then(m => m.ApplicationFormComponent)
|
||||
},
|
||||
{
|
||||
path: ':id',
|
||||
loadComponent: () => import('./features/applications/application-detail/application-detail.component')
|
||||
.then(m => m.ApplicationDetailComponent)
|
||||
},
|
||||
{
|
||||
path: ':id/edit',
|
||||
loadComponent: () => import('./features/applications/application-form/application-form.component')
|
||||
.then(m => m.ApplicationFormComponent)
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
path: 'environments',
|
||||
canActivate: [authGuard],
|
||||
children: [
|
||||
{
|
||||
path: '',
|
||||
loadComponent: () => import('./features/environments/environment-list/environment-list.component')
|
||||
.then(m => m.EnvironmentListComponent)
|
||||
},
|
||||
{
|
||||
path: 'new',
|
||||
loadComponent: () => import('./features/environments/environment-form/environment-form.component')
|
||||
.then(m => m.EnvironmentFormComponent)
|
||||
},
|
||||
{
|
||||
path: ':id',
|
||||
loadComponent: () => import('./features/environments/environment-detail/environment-detail.component')
|
||||
.then(m => m.EnvironmentDetailComponent)
|
||||
},
|
||||
{
|
||||
path: ':id/edit',
|
||||
loadComponent: () => import('./features/environments/environment-form/environment-form.component')
|
||||
.then(m => m.EnvironmentFormComponent)
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
path: 'persons',
|
||||
canActivate: [authGuard],
|
||||
children: [
|
||||
{
|
||||
path: '',
|
||||
loadComponent: () => import('./features/persons/person-list/person-list.component')
|
||||
.then(m => m.PersonListComponent)
|
||||
},
|
||||
{
|
||||
path: 'new',
|
||||
loadComponent: () => import('./features/persons/person-form/person-form.component')
|
||||
.then(m => m.PersonFormComponent)
|
||||
},
|
||||
{
|
||||
path: ':id',
|
||||
loadComponent: () => import('./features/persons/person-detail/person-detail.component')
|
||||
.then(m => m.PersonDetailComponent)
|
||||
},
|
||||
{
|
||||
path: ':id/edit',
|
||||
loadComponent: () => import('./features/persons/person-form/person-form.component')
|
||||
.then(m => m.PersonFormComponent)
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
path: 'contacts',
|
||||
canActivate: [authGuard],
|
||||
children: [
|
||||
{
|
||||
path: '',
|
||||
loadComponent: () => import('./features/contacts/contact-list/contact-list.component')
|
||||
.then(m => m.ContactListComponent)
|
||||
},
|
||||
{
|
||||
path: 'new',
|
||||
loadComponent: () => import('./features/contacts/contact-form/contact-form.component')
|
||||
.then(m => m.ContactFormComponent)
|
||||
},
|
||||
{
|
||||
path: ':id',
|
||||
loadComponent: () => import('./features/contacts/contact-detail/contact-detail.component')
|
||||
.then(m => m.ContactDetailComponent)
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
path: 'contact-roles',
|
||||
canActivate: [authGuard],
|
||||
loadComponent: () => import('./features/contacts/contact-role-list/contact-role-list.component')
|
||||
.then(m => m.ContactRoleListComponent)
|
||||
}
|
||||
];
|
||||
|
||||
@@ -0,0 +1,37 @@
|
||||
<div class="main-layout">
|
||||
<!-- Sidebar Navigation -->
|
||||
<aside class="sidebar">
|
||||
<div class="sidebar-header">
|
||||
<h1>LDPv2</h1>
|
||||
<p class="subtitle">Lifecycle Data Platform</p>
|
||||
</div>
|
||||
|
||||
<nav class="sidebar-nav">
|
||||
<div
|
||||
*ngFor="let item of navItems"
|
||||
class="nav-item"
|
||||
[class.active]="isActive(item.route)"
|
||||
[style.border-left-color]="item.color"
|
||||
(click)="navigate(item.route)">
|
||||
<span class="nav-icon">{{ item.icon }}</span>
|
||||
<span class="nav-title">{{ item.title }}</span>
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
<div class="sidebar-footer">
|
||||
<div class="user-info" *ngIf="currentUser">
|
||||
<span class="user-icon">👤</span>
|
||||
<div class="user-details">
|
||||
<div class="username">{{ currentUser.username }}</div>
|
||||
<div class="role-badge">{{ currentUser.role }}</div>
|
||||
</div>
|
||||
</div>
|
||||
<button (click)="logout()" class="btn-logout">Logout</button>
|
||||
</div>
|
||||
</aside>
|
||||
|
||||
<!-- Main Content Area -->
|
||||
<main class="main-content">
|
||||
<router-outlet></router-outlet>
|
||||
</main>
|
||||
</div>
|
||||
@@ -0,0 +1,164 @@
|
||||
.main-layout {
|
||||
display: flex;
|
||||
height: 100vh;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.sidebar {
|
||||
width: 260px;
|
||||
background: linear-gradient(180deg, #667eea 0%, #764ba2 100%);
|
||||
color: white;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
box-shadow: 2px 0 10px rgba(0, 0, 0, 0.1);
|
||||
z-index: 100;
|
||||
}
|
||||
|
||||
.sidebar-header {
|
||||
padding: 2rem 1.5rem;
|
||||
border-bottom: 1px solid rgba(255, 255, 255, 0.1);
|
||||
|
||||
h1 {
|
||||
margin: 0 0 0.25rem 0;
|
||||
font-size: 1.75rem;
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
.subtitle {
|
||||
margin: 0;
|
||||
font-size: 0.75rem;
|
||||
opacity: 0.8;
|
||||
}
|
||||
}
|
||||
|
||||
.sidebar-nav {
|
||||
flex: 1;
|
||||
overflow-y: auto;
|
||||
padding: 1rem 0;
|
||||
|
||||
&::-webkit-scrollbar {
|
||||
width: 6px;
|
||||
}
|
||||
|
||||
&::-webkit-scrollbar-track {
|
||||
background: rgba(255, 255, 255, 0.1);
|
||||
}
|
||||
|
||||
&::-webkit-scrollbar-thumb {
|
||||
background: rgba(255, 255, 255, 0.3);
|
||||
border-radius: 3px;
|
||||
|
||||
&:hover {
|
||||
background: rgba(255, 255, 255, 0.4);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.nav-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 1rem 1.5rem;
|
||||
cursor: pointer;
|
||||
transition: all 0.2s ease;
|
||||
border-left: 4px solid transparent;
|
||||
margin: 0.25rem 0;
|
||||
|
||||
&:hover {
|
||||
background: rgba(255, 255, 255, 0.1);
|
||||
}
|
||||
|
||||
&.active {
|
||||
background: rgba(255, 255, 255, 0.2);
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.nav-icon {
|
||||
font-size: 1.5rem;
|
||||
margin-right: 1rem;
|
||||
width: 30px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.nav-title {
|
||||
font-size: 0.95rem;
|
||||
}
|
||||
}
|
||||
|
||||
.sidebar-footer {
|
||||
padding: 1rem 1.5rem;
|
||||
border-top: 1px solid rgba(255, 255, 255, 0.1);
|
||||
|
||||
.user-info {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.75rem;
|
||||
margin-bottom: 1rem;
|
||||
padding: 0.75rem;
|
||||
background: rgba(255, 255, 255, 0.1);
|
||||
border-radius: 8px;
|
||||
|
||||
.user-icon {
|
||||
font-size: 1.5rem;
|
||||
}
|
||||
|
||||
.user-details {
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
|
||||
.username {
|
||||
font-weight: 500;
|
||||
font-size: 0.9rem;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
.role-badge {
|
||||
font-size: 0.7rem;
|
||||
opacity: 0.8;
|
||||
text-transform: uppercase;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.btn-logout {
|
||||
width: 100%;
|
||||
background: rgba(255, 255, 255, 0.2);
|
||||
color: white;
|
||||
border: 1px solid rgba(255, 255, 255, 0.3);
|
||||
padding: 0.75rem;
|
||||
border-radius: 6px;
|
||||
cursor: pointer;
|
||||
font-weight: 500;
|
||||
transition: all 0.3s ease;
|
||||
|
||||
&:hover {
|
||||
background: rgba(255, 255, 255, 0.3);
|
||||
transform: translateY(-2px);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.main-content {
|
||||
flex: 1;
|
||||
overflow-y: auto;
|
||||
background: #f5f5f5;
|
||||
}
|
||||
|
||||
// Responsive
|
||||
@media (max-width: 768px) {
|
||||
.sidebar {
|
||||
position: fixed;
|
||||
left: -260px;
|
||||
height: 100vh;
|
||||
transition: left 0.3s ease;
|
||||
|
||||
&.open {
|
||||
left: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.main-content {
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,102 @@
|
||||
import { Component, OnInit } from '@angular/core';
|
||||
import { CommonModule } from '@angular/common';
|
||||
import { Router, RouterModule, NavigationEnd } from '@angular/router';
|
||||
import { AuthService } from '../../auth/auth.service';
|
||||
import { User } from '../../../shared/models/user.model';
|
||||
import { filter } from 'rxjs/operators';
|
||||
|
||||
interface NavItem {
|
||||
title: string;
|
||||
icon: string;
|
||||
route: string;
|
||||
color: string;
|
||||
}
|
||||
|
||||
@Component({
|
||||
selector: 'app-main-layout',
|
||||
standalone: true,
|
||||
imports: [CommonModule, RouterModule],
|
||||
templateUrl: './main-layout.component.html',
|
||||
styleUrls: ['./main-layout.component.scss']
|
||||
})
|
||||
export class MainLayoutComponent implements OnInit {
|
||||
currentUser: User | null = null;
|
||||
activeRoute: string = '';
|
||||
|
||||
navItems: NavItem[] = [
|
||||
{
|
||||
title: 'Dashboard',
|
||||
icon: '📊',
|
||||
route: '/dashboard',
|
||||
color: '#2196f3'
|
||||
},
|
||||
{
|
||||
title: 'Business Units',
|
||||
icon: '🏢',
|
||||
route: '/business-units',
|
||||
color: '#3f51b5'
|
||||
},
|
||||
{
|
||||
title: 'Applications',
|
||||
icon: '📱',
|
||||
route: '/applications',
|
||||
color: '#009688'
|
||||
},
|
||||
{
|
||||
title: 'Environments',
|
||||
icon: '🌍',
|
||||
route: '/environments',
|
||||
color: '#ff9800'
|
||||
},
|
||||
{
|
||||
title: 'Persons',
|
||||
icon: '👤',
|
||||
route: '/persons',
|
||||
color: '#e91e63'
|
||||
},
|
||||
{
|
||||
title: 'Contacts',
|
||||
icon: '👥',
|
||||
route: '/contacts',
|
||||
color: '#9c27b0'
|
||||
},
|
||||
{
|
||||
title: 'Contact Roles',
|
||||
icon: '🎭',
|
||||
route: '/contact-roles',
|
||||
color: '#607d8b'
|
||||
}
|
||||
];
|
||||
|
||||
constructor(
|
||||
private router: Router,
|
||||
private authService: AuthService
|
||||
) {}
|
||||
|
||||
ngOnInit(): void {
|
||||
this.currentUser = this.authService.getCurrentUser();
|
||||
this.activeRoute = this.router.url;
|
||||
|
||||
// Listen to route changes to update active route
|
||||
this.router.events.pipe(
|
||||
filter(event => event instanceof NavigationEnd)
|
||||
).subscribe((event: any) => {
|
||||
this.activeRoute = event.url;
|
||||
});
|
||||
}
|
||||
|
||||
isActive(route: string): boolean {
|
||||
if (route === '/dashboard') {
|
||||
return this.activeRoute === '/dashboard';
|
||||
}
|
||||
return this.activeRoute.startsWith(route);
|
||||
}
|
||||
|
||||
navigate(route: string): void {
|
||||
this.router.navigate([route]);
|
||||
}
|
||||
|
||||
logout(): void {
|
||||
this.authService.logout();
|
||||
}
|
||||
}
|
||||
@@ -1,95 +1,66 @@
|
||||
<div class="dashboard">
|
||||
<header class="dashboard-header">
|
||||
<div class="container">
|
||||
<div class="header-content">
|
||||
<div class="branding">
|
||||
<h1>LDPv2</h1>
|
||||
<p class="subtitle">Lifecycle Data Platform</p>
|
||||
</div>
|
||||
<div class="user-menu">
|
||||
<span class="user-info" *ngIf="currentUser">
|
||||
<span class="user-icon">👤</span>
|
||||
<span class="username">{{ currentUser.username }}</span>
|
||||
<span class="role-badge">{{ currentUser.role }}</span>
|
||||
</span>
|
||||
<button (click)="logout()" class="btn-logout">Logout</button>
|
||||
<div class="dashboard-content">
|
||||
<div class="dashboard-header">
|
||||
<h1>Welcome back, {{ currentUser?.username }}! 👋</h1>
|
||||
<p>Here's an overview of your application lifecycle data.</p>
|
||||
</div>
|
||||
|
||||
<section class="stats-section">
|
||||
<h2>Overview</h2>
|
||||
<div class="stats-grid">
|
||||
<div class="stat-card" *ngFor="let stat of stats" [style.border-left-color]="stat.color">
|
||||
<div class="stat-icon">{{ stat.icon }}</div>
|
||||
<div class="stat-content">
|
||||
<div class="stat-value">{{ stat.value }}</div>
|
||||
<div class="stat-label">{{ stat.label }}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</header>
|
||||
</section>
|
||||
|
||||
<main class="dashboard-main">
|
||||
<div class="container">
|
||||
<section class="welcome-section">
|
||||
<h2>Welcome back, {{ currentUser?.username }}! 👋</h2>
|
||||
<p>Manage your applications, environments, and business units from one place.</p>
|
||||
</section>
|
||||
|
||||
<section class="stats-section">
|
||||
<div class="stats-grid">
|
||||
<div class="stat-card" *ngFor="let stat of stats">
|
||||
<div class="stat-icon">{{ stat.icon }}</div>
|
||||
<div class="stat-content">
|
||||
<div class="stat-value">{{ stat.value }}</div>
|
||||
<div class="stat-label">{{ stat.label }}</div>
|
||||
</div>
|
||||
</div>
|
||||
<section class="activity-section">
|
||||
<h2>Recent Activity</h2>
|
||||
<div class="activity-list">
|
||||
<div class="activity-item" *ngFor="let activity of recentActivity">
|
||||
<div class="activity-icon">
|
||||
<span *ngIf="activity.action === 'Created'">✨</span>
|
||||
<span *ngIf="activity.action === 'Updated'">📝</span>
|
||||
<span *ngIf="activity.action === 'Deleted'">🗑️</span>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="features-section">
|
||||
<h3>Quick Access</h3>
|
||||
<div class="features-grid">
|
||||
<div
|
||||
class="feature-card"
|
||||
*ngFor="let feature of features"
|
||||
(click)="navigate(feature.route)"
|
||||
[style.border-left-color]="feature.color">
|
||||
<div class="feature-icon">{{ feature.icon }}</div>
|
||||
<div class="feature-content">
|
||||
<h4>{{ feature.title }}</h4>
|
||||
<p>{{ feature.description }}</p>
|
||||
</div>
|
||||
<div class="feature-arrow">→</div>
|
||||
<div class="activity-details">
|
||||
<div class="activity-main">
|
||||
<strong>{{ activity.action }}</strong> {{ activity.entity }}:
|
||||
<span class="entity-name">{{ activity.name }}</span>
|
||||
</div>
|
||||
<div class="activity-time">{{ activity.time }}</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="getting-started">
|
||||
<h3>Getting Started</h3>
|
||||
<div class="steps-grid">
|
||||
<div class="step-card">
|
||||
<div class="step-number">1</div>
|
||||
<h4>Create Business Units</h4>
|
||||
<p>Organize your applications by business units</p>
|
||||
<button (click)="navigate('/business-units')" class="btn-link">
|
||||
Go to Business Units →
|
||||
</button>
|
||||
</div>
|
||||
<div class="step-card">
|
||||
<div class="step-number">2</div>
|
||||
<h4>Add Applications</h4>
|
||||
<p>Register your applications and track their lifecycle</p>
|
||||
<button (click)="navigate('/applications')" class="btn-link">
|
||||
Go to Applications →
|
||||
</button>
|
||||
</div>
|
||||
<div class="step-card">
|
||||
<div class="step-number">3</div>
|
||||
<h4>Configure Environments</h4>
|
||||
<p>Set up deployment environments</p>
|
||||
<button (click)="navigate('/environments')" class="btn-link">
|
||||
Go to Environments →
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
</section>
|
||||
|
||||
<footer class="dashboard-footer">
|
||||
<div class="container">
|
||||
<p>LDPv2 - Lifecycle Data Platform v2 | © 2026</p>
|
||||
<section class="quick-tips">
|
||||
<h2>Quick Tips</h2>
|
||||
<div class="tips-grid">
|
||||
<div class="tip-card">
|
||||
<div class="tip-icon">💡</div>
|
||||
<div class="tip-content">
|
||||
<h3>Get Started</h3>
|
||||
<p>Use the sidebar to navigate between different sections of the application.</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="tip-card">
|
||||
<div class="tip-icon">🔍</div>
|
||||
<div class="tip-content">
|
||||
<h3>Search & Filter</h3>
|
||||
<p>Most lists support search and filtering to help you find what you need quickly.</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="tip-card">
|
||||
<div class="tip-icon">🎯</div>
|
||||
<div class="tip-content">
|
||||
<h3>Track Lifecycle</h3>
|
||||
<p>Monitor your applications' lifecycle from idea to decommission.</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</footer>
|
||||
</section>
|
||||
</div>
|
||||
|
||||
@@ -1,280 +1,184 @@
|
||||
.dashboard {
|
||||
min-height: 100vh;
|
||||
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.container {
|
||||
max-width: 1200px;
|
||||
.dashboard-content {
|
||||
padding: 2rem;
|
||||
max-width: 1400px;
|
||||
margin: 0 auto;
|
||||
padding: 0 2rem;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.dashboard-header {
|
||||
background: rgba(255, 255, 255, 0.1);
|
||||
backdrop-filter: blur(10px);
|
||||
padding: 1.5rem 0;
|
||||
box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
|
||||
margin-bottom: 2rem;
|
||||
|
||||
.header-content {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.branding h1 {
|
||||
color: white;
|
||||
h1 {
|
||||
font-size: 2rem;
|
||||
margin: 0;
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
.branding .subtitle {
|
||||
color: rgba(255, 255, 255, 0.8);
|
||||
margin: 0;
|
||||
font-size: 0.9rem;
|
||||
}
|
||||
|
||||
.user-menu {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 1rem;
|
||||
}
|
||||
|
||||
.user-info {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.5rem;
|
||||
color: white;
|
||||
|
||||
.user-icon { font-size: 1.5rem; }
|
||||
.username { font-weight: 500; }
|
||||
.role-badge {
|
||||
background: rgba(255, 255, 255, 0.2);
|
||||
padding: 0.25rem 0.75rem;
|
||||
border-radius: 12px;
|
||||
font-size: 0.75rem;
|
||||
text-transform: uppercase;
|
||||
}
|
||||
}
|
||||
|
||||
.btn-logout {
|
||||
background: rgba(255, 255, 255, 0.2);
|
||||
color: white;
|
||||
border: 1px solid rgba(255, 255, 255, 0.3);
|
||||
padding: 0.5rem 1.5rem;
|
||||
border-radius: 20px;
|
||||
cursor: pointer;
|
||||
font-weight: 500;
|
||||
transition: all 0.3s ease;
|
||||
|
||||
&:hover {
|
||||
background: rgba(255, 255, 255, 0.3);
|
||||
transform: translateY(-2px);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.dashboard-main {
|
||||
flex: 1;
|
||||
padding: 3rem 0;
|
||||
}
|
||||
|
||||
.welcome-section {
|
||||
text-align: center;
|
||||
color: white;
|
||||
margin-bottom: 3rem;
|
||||
|
||||
h2 {
|
||||
font-size: 2.5rem;
|
||||
margin: 0 0 1rem 0;
|
||||
font-weight: 700;
|
||||
margin: 0 0 0.5rem 0;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
p {
|
||||
font-size: 1.2rem;
|
||||
opacity: 0.9;
|
||||
margin: 0;
|
||||
color: #666;
|
||||
font-size: 1.1rem;
|
||||
}
|
||||
}
|
||||
|
||||
section {
|
||||
margin-bottom: 3rem;
|
||||
|
||||
h2 {
|
||||
font-size: 1.5rem;
|
||||
margin: 0 0 1.5rem 0;
|
||||
color: #333;
|
||||
}
|
||||
}
|
||||
|
||||
.stats-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
|
||||
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
|
||||
gap: 1.5rem;
|
||||
margin-bottom: 3rem;
|
||||
}
|
||||
|
||||
.stat-card {
|
||||
background: white;
|
||||
padding: 2rem;
|
||||
border-radius: 12px;
|
||||
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
|
||||
padding: 1.5rem;
|
||||
border-radius: 8px;
|
||||
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 1.5rem;
|
||||
transition: transform 0.3s ease;
|
||||
|
||||
&:hover { transform: translateY(-5px); }
|
||||
|
||||
.stat-icon { font-size: 3rem; }
|
||||
.stat-value {
|
||||
font-size: 2.5rem;
|
||||
font-weight: 700;
|
||||
color: #333;
|
||||
}
|
||||
.stat-label {
|
||||
color: #666;
|
||||
font-size: 0.9rem;
|
||||
}
|
||||
}
|
||||
|
||||
.features-section {
|
||||
margin-bottom: 3rem;
|
||||
|
||||
h3 {
|
||||
color: white;
|
||||
font-size: 1.8rem;
|
||||
margin-bottom: 1.5rem;
|
||||
font-weight: 600;
|
||||
}
|
||||
}
|
||||
|
||||
.features-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
|
||||
gap: 1.5rem;
|
||||
}
|
||||
|
||||
.feature-card {
|
||||
background: white;
|
||||
padding: 2rem;
|
||||
border-radius: 12px;
|
||||
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 1.5rem;
|
||||
cursor: pointer;
|
||||
transition: all 0.3s ease;
|
||||
gap: 1rem;
|
||||
border-left: 4px solid;
|
||||
transition: transform 0.2s ease, box-shadow 0.2s ease;
|
||||
|
||||
&:hover {
|
||||
transform: translateY(-5px);
|
||||
box-shadow: 0 8px 12px rgba(0, 0, 0, 0.15);
|
||||
transform: translateY(-4px);
|
||||
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
|
||||
}
|
||||
|
||||
.feature-icon { font-size: 3rem; }
|
||||
.feature-content {
|
||||
.stat-icon {
|
||||
font-size: 2.5rem;
|
||||
}
|
||||
|
||||
.stat-content {
|
||||
flex: 1;
|
||||
|
||||
h4 {
|
||||
margin: 0 0 0.5rem 0;
|
||||
.stat-value {
|
||||
font-size: 2rem;
|
||||
font-weight: 700;
|
||||
color: #333;
|
||||
font-size: 1.3rem;
|
||||
line-height: 1;
|
||||
}
|
||||
|
||||
p {
|
||||
margin: 0;
|
||||
.stat-label {
|
||||
color: #666;
|
||||
font-size: 0.9rem;
|
||||
margin-top: 0.25rem;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.feature-arrow {
|
||||
font-size: 1.5rem;
|
||||
color: #999;
|
||||
.activity-section {
|
||||
.activity-list {
|
||||
background: white;
|
||||
border-radius: 8px;
|
||||
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
|
||||
overflow: hidden;
|
||||
}
|
||||
}
|
||||
|
||||
.getting-started {
|
||||
h3 {
|
||||
color: white;
|
||||
font-size: 1.8rem;
|
||||
margin-bottom: 1.5rem;
|
||||
font-weight: 600;
|
||||
}
|
||||
}
|
||||
|
||||
.steps-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
|
||||
gap: 1.5rem;
|
||||
}
|
||||
|
||||
.step-card {
|
||||
background: rgba(255, 255, 255, 0.95);
|
||||
padding: 2rem;
|
||||
border-radius: 12px;
|
||||
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
|
||||
|
||||
.step-number {
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
||||
color: white;
|
||||
border-radius: 50%;
|
||||
.activity-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-weight: 700;
|
||||
font-size: 1.2rem;
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
gap: 1rem;
|
||||
padding: 1rem 1.5rem;
|
||||
border-bottom: 1px solid #f5f5f5;
|
||||
transition: background-color 0.2s ease;
|
||||
|
||||
h4 {
|
||||
color: #333;
|
||||
margin: 0 0 0.5rem 0;
|
||||
font-size: 1.2rem;
|
||||
}
|
||||
|
||||
p {
|
||||
color: #666;
|
||||
margin: 0 0 1rem 0;
|
||||
}
|
||||
|
||||
.btn-link {
|
||||
background: none;
|
||||
border: none;
|
||||
color: #667eea;
|
||||
font-weight: 500;
|
||||
cursor: pointer;
|
||||
padding: 0;
|
||||
transition: color 0.3s ease;
|
||||
&:last-child {
|
||||
border-bottom: none;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
color: #764ba2;
|
||||
text-decoration: underline;
|
||||
background-color: #f9f9f9;
|
||||
}
|
||||
|
||||
.activity-icon {
|
||||
font-size: 1.5rem;
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
background: #f5f5f5;
|
||||
border-radius: 50%;
|
||||
}
|
||||
|
||||
.activity-details {
|
||||
flex: 1;
|
||||
|
||||
.activity-main {
|
||||
color: #333;
|
||||
margin-bottom: 0.25rem;
|
||||
|
||||
.entity-name {
|
||||
color: #667eea;
|
||||
font-weight: 500;
|
||||
}
|
||||
}
|
||||
|
||||
.activity-time {
|
||||
color: #999;
|
||||
font-size: 0.85rem;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.dashboard-footer {
|
||||
background: rgba(0, 0, 0, 0.2);
|
||||
padding: 1.5rem 0;
|
||||
text-align: center;
|
||||
color: white;
|
||||
margin-top: auto;
|
||||
.quick-tips {
|
||||
.tips-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
|
||||
gap: 1.5rem;
|
||||
}
|
||||
|
||||
p {
|
||||
margin: 0;
|
||||
opacity: 0.8;
|
||||
.tip-card {
|
||||
background: white;
|
||||
padding: 1.5rem;
|
||||
border-radius: 8px;
|
||||
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
|
||||
display: flex;
|
||||
gap: 1rem;
|
||||
|
||||
.tip-icon {
|
||||
font-size: 2rem;
|
||||
}
|
||||
|
||||
.tip-content {
|
||||
flex: 1;
|
||||
|
||||
h3 {
|
||||
margin: 0 0 0.5rem 0;
|
||||
color: #333;
|
||||
font-size: 1.1rem;
|
||||
}
|
||||
|
||||
p {
|
||||
margin: 0;
|
||||
color: #666;
|
||||
font-size: 0.9rem;
|
||||
line-height: 1.5;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
.dashboard-header .header-content {
|
||||
flex-direction: column;
|
||||
gap: 1rem;
|
||||
.dashboard-content {
|
||||
padding: 1rem;
|
||||
}
|
||||
|
||||
.welcome-section h2 {
|
||||
font-size: 1.8rem;
|
||||
.dashboard-header h1 {
|
||||
font-size: 1.5rem;
|
||||
}
|
||||
|
||||
.stats-grid,
|
||||
.features-grid,
|
||||
.steps-grid {
|
||||
.tips-grid {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import { Component, OnInit } from '@angular/core';
|
||||
import { CommonModule } from '@angular/common';
|
||||
import { Router } from '@angular/router';
|
||||
import { AuthService } from '../../core/auth/auth.service';
|
||||
import { User } from '../../shared/models/user.model';
|
||||
|
||||
@@ -14,72 +13,27 @@ import { User } from '../../shared/models/user.model';
|
||||
export class DashboardComponent implements OnInit {
|
||||
currentUser: User | null = null;
|
||||
|
||||
features = [
|
||||
{
|
||||
title: 'Business Units',
|
||||
description: 'Manage organizational business units',
|
||||
icon: '🏢',
|
||||
route: '/business-units',
|
||||
color: '#3f51b5'
|
||||
},
|
||||
{
|
||||
title: 'Applications',
|
||||
description: 'Manage applications and their lifecycle',
|
||||
icon: '📱',
|
||||
route: '/applications',
|
||||
color: '#009688'
|
||||
},
|
||||
{
|
||||
title: 'Environments',
|
||||
description: 'Manage deployment environments',
|
||||
icon: '🌍',
|
||||
route: '/environments',
|
||||
color: '#ff9800'
|
||||
},
|
||||
{
|
||||
title: 'Persons',
|
||||
description: 'Manage individual contacts',
|
||||
icon: '👤',
|
||||
route: '/persons',
|
||||
color: '#e91e63'
|
||||
},
|
||||
{
|
||||
title: 'Contacts',
|
||||
description: 'Manage functional contacts and roles',
|
||||
icon: '👥',
|
||||
route: '/contacts',
|
||||
color: '#9c27b0'
|
||||
},
|
||||
{
|
||||
title: 'Contact Roles',
|
||||
description: 'View predefined contact roles',
|
||||
icon: '🎭',
|
||||
route: '/contact-roles',
|
||||
color: '#607d8b'
|
||||
}
|
||||
stats = [
|
||||
{ label: 'Business Units', value: '4', icon: '🏢', color: '#3f51b5' },
|
||||
{ label: 'Applications', value: '7', icon: '📱', color: '#009688' },
|
||||
{ label: 'Environments', value: '4', icon: '🌍', color: '#ff9800' },
|
||||
{ label: 'Persons', value: '4', icon: '👤', color: '#e91e63' },
|
||||
{ label: 'Contacts', value: '0', icon: '👥', color: '#9c27b0' },
|
||||
{ label: 'Contact Roles', value: '8', icon: '🎭', color: '#607d8b' }
|
||||
];
|
||||
|
||||
stats = [
|
||||
{ label: 'Business Units', value: '4', icon: '🏢' },
|
||||
{ label: 'Applications', value: '7', icon: '📱' },
|
||||
{ label: 'Environments', value: '4', icon: '🌍' },
|
||||
{ label: 'Persons', value: '4', icon: '👤' }
|
||||
recentActivity = [
|
||||
{ action: 'Created', entity: 'Application', name: 'Mobile App', time: '2 hours ago' },
|
||||
{ action: 'Updated', entity: 'Business Unit', name: 'Digital Services', time: '5 hours ago' },
|
||||
{ action: 'Created', entity: 'Person', name: 'John Doe', time: '1 day ago' },
|
||||
{ action: 'Updated', entity: 'Environment', name: 'PROD-EU', time: '2 days ago' }
|
||||
];
|
||||
|
||||
constructor(
|
||||
private router: Router,
|
||||
private authService: AuthService
|
||||
) {}
|
||||
|
||||
ngOnInit(): void {
|
||||
this.currentUser = this.authService.getCurrentUser();
|
||||
}
|
||||
|
||||
navigate(route: string): void {
|
||||
this.router.navigate([route]);
|
||||
}
|
||||
|
||||
logout(): void {
|
||||
this.authService.logout();
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user