Commit c77d822b by Ooh-Ao

permission

parent fda22490
......@@ -6,12 +6,13 @@ import { authen } from './shared/routes/auth.routes';
import { landingRoutingModule } from './components/pages/landing.routes';
import { landing } from './shared/routes/landing.routes';
import { LandingLayoutComponent } from './shared/layouts/landing-layout/landing-layout.component';
import { AuthGuard } from './shared/services/auth.guard';
import { authGuard } from './core/guards/auth.guard';
import { LoginComponent } from './authentication/login/login.component';
import { CoverComponent } from './components/authentication/reset-password/cover/cover.component';
import { HomeComponent } from './portal-manage/home/home.component';
import { FramelessLayoutComponent } from './shared/layouts/frameless-layout.component';
import { DashboardViewerComponent } from './portal-manage/dashboard-viewer/dashboard-viewer.component';
import { UnauthorizedComponent } from './core/components/unauthorized.component';
export const App_Route: Route[] = [
{ path: '', redirectTo: 'auth/login', pathMatch: 'full' },
......@@ -28,7 +29,7 @@ export const App_Route: Route[] = [
{
path: 'portal-manage',
component: ContentLayoutComponent, // Use the main layout
canActivate: [AuthGuard], // Assuming you want to protect these routes
canActivate: [authGuard], // Use the new functional guard
loadChildren: () => import('./portal-manage/portal-manage.routes').then(r => r.portalManageRoutes)
},
{
......@@ -45,4 +46,8 @@ export const App_Route: Route[] = [
path: 'home',
component: HomeComponent
},
{
path: 'unauthorized',
component: UnauthorizedComponent
},
]
\ No newline at end of file
import { Component } from '@angular/core';
@Component({
selector: 'app-unauthorized',
standalone: true,
imports: [],
template: `
<div style="text-align: center; margin-top: 50px;">
<h1>403 - Unauthorized</h1>
<p>You do not have permission to access this page.</p>
<a routerLink="/">Go to Homepage</a>
</div>
`,
})
export class UnauthorizedComponent {}
import { inject } from '@angular/core';
import { CanActivateFn, Router } from '@angular/router';
import { AuthService } from '../services/auth.service';
export const authGuard: CanActivateFn = (route, state) => {
const authService = inject(AuthService);
const router = inject(Router);
if (authService.isLoggedIn) {
return true;
}
// Redirect to the login page
return router.parseUrl('/auth/login');
};
import { inject } from '@angular/core';
import { CanActivateFn, Router, ActivatedRouteSnapshot } from '@angular/router';
import { CorePermissionService } from '../services/core-permission.service';
import { map, tap } from 'rxjs/operators';
export const moduleAccessGuard: CanActivateFn = (route: ActivatedRouteSnapshot, state) => {
const permissionService = inject(CorePermissionService);
const router = inject(Router);
// Get the module name from the route parameter :appName
const moduleName = route.params['appName'];
if (!moduleName) {
// If the path is not defined, deny access and redirect
return router.parseUrl('/unauthorized'); // Or to a default error page
}
return permissionService.canAccessModule(moduleName).pipe(
tap(canAccess => {
if (!canAccess) {
// If access is denied, redirect to an unauthorized page or home
router.navigate(['/unauthorized']);
}
})
);
};
import { Injectable } from '@angular/core';
import { HttpClient, HttpHeaders, HttpParams } from '@angular/common/http';
import { Observable, throwError } from 'rxjs';
import { catchError } from 'rxjs/operators';
import { environment } from '../../../environments/environment';
@Injectable({
providedIn: 'root'
})
export class ApiService {
private readonly apiUrl = environment.apiUrl;
constructor(private http: HttpClient) { }
private getHeaders(): HttpHeaders {
let headers = new HttpHeaders({
'Content-Type': 'application/json',
'Accept': 'application/json'
});
// In a real app, you would get the token from AuthService
const token = localStorage.getItem('authToken');
if (token) {
headers = headers.set('Authorization', `Bearer ${token}`);
}
return headers;
}
private formatErrors(error: any) {
// You can add more robust error handling/logging here
console.error('ApiService Error:', error);
return throwError(() => new Error('An error occurred. Please try again.'));
}
get<T>(path: string, params: HttpParams = new HttpParams()): Observable<T> {
return this.http.get<T>(`${this.apiUrl}${path}`, { headers: this.getHeaders(), params })
.pipe(catchError(this.formatErrors));
}
post<T>(path: string, body: object = {}): Observable<T> {
return this.http.post<T>(`${this.apiUrl}${path}`, JSON.stringify(body), { headers: this.getHeaders() })
.pipe(catchError(this.formatErrors));
}
put<T>(path: string, body: object = {}): Observable<T> {
return this.http.put<T>(`${this.apiUrl}${path}`, JSON.stringify(body), { headers: this.getHeaders() })
.pipe(catchError(this.formatErrors));
}
delete<T>(path: string): Observable<T> {
return this.http.delete<T>(`${this.apiUrl}${path}`, { headers: this.getHeaders() })
.pipe(catchError(this.formatErrors));
}
}
import { Injectable } from '@angular/core';
import { of, Observable } from 'rxjs';
import { delay, tap } from 'rxjs/operators';
@Injectable({
providedIn: 'root'
})
export class AuthService {
private _isLoggedIn = false;
private _userRoles: string[] = [];
// In a real app, you would check for a token in localStorage
constructor() {
const token = localStorage.getItem('authToken');
if (token) {
this._isLoggedIn = true;
// You might decode the token to get roles
this._userRoles = ['ADMIN', 'MYHR_PLUS_USER'];
}
}
get isLoggedIn(): boolean {
return this._isLoggedIn;
}
get userRoles(): string[] {
return this._userRoles;
}
login(): Observable<boolean> {
// Simulate an API call
return of(true).pipe(
delay(1000),
tap(() => {
this._isLoggedIn = true;
this._userRoles = ['ADMIN', 'MYHR_PLUS_USER']; // Example roles
localStorage.setItem('authToken', 'dummy-token');
})
);
}
logout(): void {
this._isLoggedIn = false;
this._userRoles = [];
localStorage.removeItem('authToken');
}
}
import { Injectable } from '@angular/core';
import { Observable, of } from 'rxjs';
import { map, catchError, shareReplay } from 'rxjs/operators';
import { ApiService } from './api.service';
@Injectable({
providedIn: 'root'
})
export class CorePermissionService {
private accessibleModules$: Observable<string[]> | undefined;
constructor(private apiService: ApiService) { }
/**
* Fetches the list of accessible modules for the current user from the backend.
* It caches the result to avoid repeated API calls.
*/
private getAccessibleModules(): Observable<string[]> {
if (!this.accessibleModules$) {
// The ApiService automatically sends the auth token.
// The backend is responsible for returning the list of modules this user can access.
this.accessibleModules$ = this.apiService.get<string[]>('/permissions/modules').pipe(
shareReplay(1), // Cache the successful response
catchError(() => {
this.clearPermissions(); // Clear cache on error
return of([]); // Return an empty array on error to prevent breaking the app
})
);
}
return this.accessibleModules$;
}
/**
* Checks if the user has access to a specific module.
* @param moduleName The name of the module (e.g., from the route path).
*/
canAccessModule(moduleName: string): Observable<boolean> {
return this.getAccessibleModules().pipe(
map(modules => modules.includes(moduleName))
);
}
/**
* Clears the cached permissions. Should be called on logout.
*/
clearPermissions(): void {
this.accessibleModules$ = undefined;
}
}
......@@ -75,5 +75,14 @@
<p class="card-description text-gray-600 text-sm">mySkill-X</p>
</a>
<a class="card bg-white rounded-xl p-8 text-center shadow-lg transition-all duration-300 ease-in-out transform hover:scale-105 hover:shadow-xl hover:bg-gradient-to-br from-gray-50 to-gray-100"
[routerLink]="['/portal-manage/permission-management']">
<div class="card-icon text-5xl text-gray-700 mb-4 transition-transform duration-300 ease-in-out group-hover:scale-110">
<img src="./assets/images/icons/widget.png" alt="Settings"
class="leading-[1.75] text-2xl !h-[5rem] align-middle flex justify-center mx-auto">
</div>
<p class="card-description text-gray-600 text-sm">Permission Management</p>
</a>
</div>
</div>
\ No newline at end of file
import { Component } from '@angular/core';
import { Router, RouterLink } from '@angular/router';
import { Router, RouterLink, RouterModule } from '@angular/router';
import { TokenService } from '../../shared/services/token.service';
@Component({
......@@ -7,7 +7,7 @@ import { TokenService } from '../../shared/services/token.service';
templateUrl: './home.component.html',
styleUrls: ['./home.component.scss'],
standalone: true,
// imports: [RouterLink]
imports: [RouterModule]
})
export class HomeComponent {
......
import { MyHrPermissionService } from './services/myhr-permission.service';
import { Component, OnInit } from '@angular/core';
import { CommonModule } from '@angular/common';
import { Observable } from 'rxjs';
@Component({
selector: 'app-hr-dashboard',
standalone: true,
imports: [CommonModule],
template: `
<div class="p-4">
<h1 class="text-2xl font-bold">MyHR+ Dashboard</h1>
<p>This is a dedicated component for the MyHR+ module.</p>
<div class="mt-4 p-4 border rounded-lg bg-gray-50">
<h2 class="text-lg font-semibold">HR Permissions Check</h2>
<p>Checking permissions using the module-specific <strong>MyHrPermissionService</strong>:</p>
<ul>
<li>Can view salary? <strong [class.text-green-600]="canViewSalary$ | async" [class.text-red-600]="!(canViewSalary$ | async)">{{ canViewSalary$ | async }}</strong></li>
<li>Can approve leave? <strong [class.text-green-600]="canApproveLeave$ | async" [class.text-red-600]="!(canApproveLeave$ | async)">{{ canApproveLeave$ | async }}</strong></li>
</ul>
<p class="text-sm text-gray-500 mt-2">This demonstrates that the component is correctly injecting and using its own scoped service.</p>
</div>
</div>
`,
})
export class HrDashboardComponent implements OnInit {
canViewSalary$!: Observable<boolean>;
canApproveLeave$!: Observable<boolean>;
constructor(private hrPermissions: MyHrPermissionService) {}
ngOnInit(): void {
this.canViewSalary$ = this.hrPermissions.canViewSalary();
this.canApproveLeave$ = this.hrPermissions.canApproveLeave();
}
}
import { Routes } from '@angular/router';
import { MyHrPermissionService } from './services/myhr-permission.service';
import { HrDashboardComponent } from './hr-dashboard.component';
export const MYHR_PLUS_ROUTES: Routes = [
{
path: '',
// By providing the service here, a new instance is created when this route is loaded.
// It is available to this component and all its children, but not outside this module.
providers: [MyHrPermissionService],
children: [
{
path: 'dashboard',
component: HrDashboardComponent
},
{
path: '',
redirectTo: 'dashboard',
pathMatch: 'full'
}
]
}
];
import { Injectable } from '@angular/core';
import { Observable, of } from 'rxjs';
/**
* This service is provided specifically within the MyHR+ module.
* It handles permissions and logic unique to the HR application.
*/
@Injectable()
export class MyHrPermissionService {
constructor() {
console.log('MyHrPermissionService instance created.');
}
/**
* Checks if the current user can view salary information.
* In a real app, this would involve more complex logic, possibly another API call.
* @returns Observable<boolean>
*/
canViewSalary(): Observable<boolean> {
// For demonstration, we'll return a hardcoded value.
// This logic would be specific to the HR module.
return of(true);
}
/**
* Checks if the current user has leave approval permissions.
* @returns Observable<boolean>
*/
canApproveLeave(): Observable<boolean> {
return of(false);
}
}
<div class="container mx-auto p-4" *ngIf="role$ | async as role">
<h1 class="text-2xl font-bold mb-1">{{ 'EDIT_PERMISSIONS' | translate }}</h1>
<h2 class="text-lg text-gray-600 mb-6">{{ 'ROLE' | translate }}: <span class="font-semibold">{{ role.name }}</span></h2>
<div class="bg-white rounded-lg shadow-md p-6">
<div class="grid grid-cols-1 md:grid-cols-2 gap-6">
<div *ngFor="let app of (applications$ | async)" class="flex items-center justify-between p-4 border rounded-lg hover:bg-gray-50 transition-colors">
<div>
<div class="font-semibold text-gray-800">{{ app.appName }}</div>
<div class="text-sm text-gray-500 mt-1">{{ app.description }}</div>
</div>
<mat-slide-toggle
[checked]="rolePermission.permissions[app.appId]"
(change)="onPermissionChange(app.appId, $event.checked)"
color="primary">
</mat-slide-toggle>
</div>
</div>
<div class="flex justify-end mt-8">
<button mat-stroked-button (click)="cancel()" class="mr-2">{{ 'CANCEL' | translate }}</button>
<button mat-flat-button color="primary" (click)="savePermissions()">{{ 'SAVE_CHANGES' | translate }}</button>
</div>
</div>
</div>
import { Component, OnInit } from '@angular/core';
import { ActivatedRoute, Router } from '@angular/router';
import { Observable } from 'rxjs';
import { map } from 'rxjs/operators';
import { AppPermission, Role, RolePermission } from '../permission.model';
import { PermissionService } from '../permission.service';
// Core Angular & Material imports
import { CommonModule } from '@angular/common';
import { FormsModule } from '@angular/forms';
import { MatSlideToggleModule } from '@angular/material/slide-toggle';
import { MatButtonModule } from '@angular/material/button';
// Translation
import { TranslateModule } from '@ngx-translate/core';
@Component({
selector: 'app-permission-edit',
standalone: true,
imports: [
CommonModule,
FormsModule,
MatSlideToggleModule,
MatButtonModule,
TranslateModule
],
templateUrl: './permission-edit.component.html',
styleUrls: ['./permission-edit.component.scss']
})
export class PermissionEditComponent implements OnInit {
roleId!: string;
role$!: Observable<Role | undefined>;
applications$!: Observable<AppPermission[]>;
rolePermission: RolePermission = { roleId: '', permissions: {} };
constructor(
private route: ActivatedRoute,
private router: Router,
private permissionService: PermissionService
) { }
ngOnInit(): void {
this.roleId = this.route.snapshot.paramMap.get('roleId')!;
this.rolePermission.roleId = this.roleId;
this.role$ = this.permissionService.getRoles().pipe(
map(roles => roles.find(r => r.id === this.roleId))
);
this.applications$ = this.permissionService.getApplications();
this.permissionService.getRolePermissions(this.roleId).subscribe(permissions => {
if (permissions) {
this.rolePermission = permissions;
}
});
}
onPermissionChange(appId: string, isChecked: boolean): void {
this.rolePermission.permissions[appId] = isChecked;
}
savePermissions(): void {
this.permissionService.updateRolePermission(this.rolePermission).subscribe(() => {
this.router.navigate(['/portal-manage/permission-management']);
});
}
cancel(): void {
this.router.navigate(['/portal-manage/permission-management']);
}
}
<div class="container mx-auto p-4">
<h1 class="text-2xl font-bold mb-4">{{ 'ROLE_BASED_ACCESS_CONTROL' | translate }}</h1>
<div *ngIf="roles$ | async as roles" class="mat-elevation-z8 bg-white rounded-lg overflow-hidden">
<table mat-table [dataSource]="roles" class="w-full">
<!-- Name Column -->
<ng-container matColumnDef="name">
<th mat-header-cell *matHeaderCellDef class="p-4 text-left text-sm font-semibold text-gray-600 uppercase tracking-wider">{{ 'ROLE_NAME' | translate }}</th>
<td mat-cell *matCellDef="let role" class="p-4 whitespace-nowrap text-sm text-gray-800"> {{role.name}} </td>
</ng-container>
<!-- Description Column -->
<ng-container matColumnDef="description">
<th mat-header-cell *matHeaderCellDef class="p-4 text-left text-sm font-semibold text-gray-600 uppercase tracking-wider">{{ 'DESCRIPTION' | translate }}</th>
<td mat-cell *matCellDef="let role" class="p-4 text-sm text-gray-500"> {{role.description}} </td>
</ng-container>
<!-- Actions Column -->
<ng-container matColumnDef="actions">
<th mat-header-cell *matHeaderCellDef class="p-4 text-left text-sm font-semibold text-gray-600 uppercase tracking-wider">{{ 'ACTIONS' | translate }}</th>
<td mat-cell *matCellDef="let role" class="p-4 whitespace-nowrap text-sm font-medium">
<button mat-icon-button color="primary" (click)="navigateToEdit(role.id)" [attr.aria-label]="'EDIT_PERMISSIONS' | translate">
<mat-icon>edit</mat-icon>
</button>
</td>
</ng-container>
<tr mat-header-row *matHeaderRowDef="displayedColumns"></tr>
<tr mat-row *matRowDef="let row; columns: displayedColumns;"></tr>
</table>
</div>
</div>
\ No newline at end of file
import { Component, OnInit } from '@angular/core';
import { Observable } from 'rxjs';
import { Role } from '../permission.model';
import { PermissionService } from '../permission.service';
import { Router, RouterModule } from '@angular/router';
// Core Angular & Material imports
import { CommonModule } from '@angular/common';
import { MatTableModule } from '@angular/material/table';
import { MatButtonModule } from '@angular/material/button';
import { MatIconModule } from '@angular/material/icon';
// Translation
import { TranslateModule } from '@ngx-translate/core';
@Component({
selector: 'app-permission-list',
standalone: true,
imports: [
CommonModule,
RouterModule,
MatTableModule,
MatButtonModule,
MatIconModule,
TranslateModule
],
templateUrl: './permission-list.component.html',
styleUrls: ['./permission-list.component.scss']
})
export class PermissionListComponent implements OnInit {
roles$!: Observable<Role[]>;
displayedColumns: string[] = ['name', 'description', 'actions'];
constructor(
private permissionService: PermissionService,
private router: Router
) { }
ngOnInit(): void {
this.roles$ = this.permissionService.getRoles();
}
navigateToEdit(roleId: string): void {
this.router.navigate(['/portal-manage/permission-management/edit', roleId]);
}
}
import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { RouterModule } from '@angular/router';
import { HttpClientModule } from '@angular/common/http';
import { PERMISSION_ROUTES } from './permission-management.routes';
import { PermissionService } from './permission.service';
@NgModule({
declarations: [],
imports: [
CommonModule,
HttpClientModule,
RouterModule.forChild(PERMISSION_ROUTES),
],
providers: [
PermissionService
]
})
export class PermissionManagementModule { }
\ No newline at end of file
import { Routes } from '@angular/router';
import { PermissionListComponent } from './permission-list/permission-list.component';
import { PermissionEditComponent } from './permission-edit/permission-edit.component';
export const PERMISSION_ROUTES: Routes = [
{
path: '',
component: PermissionListComponent,
pathMatch: 'full',
data: { title: 'Permission Management' }
},
{
path: 'edit/:roleId',
component: PermissionEditComponent,
data: { title: 'Edit Permissions' }
}
];
export interface Role {
id: string;
name: string;
description: string;
}
export interface AppPermission {
appId: string;
appName: string;
description: string;
}
export interface RolePermission {
roleId: string;
permissions: { [appId: string]: boolean };
}
import { TestBed } from '@angular/core/testing';
import { PermissionService } from './permission.service';
describe('PermissionService', () => {
let service: PermissionService;
beforeEach(() => {
TestBed.configureTestingModule({});
service = TestBed.inject(PermissionService);
});
it('should be created', () => {
expect(service).toBeTruthy();
});
});
import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { Observable, map } from 'rxjs';
import { Role, AppPermission, RolePermission } from './permission.model';
interface MockData {
roles: Role[];
applications: AppPermission[];
role_permissions: RolePermission[];
}
@Injectable()
export class PermissionService {
private dataUrl = 'assets/data/mock-permissions.json';
constructor(private http: HttpClient) { }
getRoles(): Observable<Role[]> {
return this.http.get<MockData>(this.dataUrl).pipe(
map(data => data.roles)
);
}
getApplications(): Observable<AppPermission[]> {
return this.http.get<MockData>(this.dataUrl).pipe(
map(data => data.applications)
);
}
getRolePermissions(roleId: string): Observable<RolePermission | undefined> {
return this.http.get<MockData>(this.dataUrl).pipe(
map(data => data.role_permissions.find(p => p.roleId === roleId))
);
}
// In a real app, this would make an HTTP PUT/POST request
// For this mock version, we just log it.
updateRolePermission(rolePermission: RolePermission): Observable<any> {
console.log('Saving permissions:', rolePermission);
// Simulate an HTTP response
return new Observable(observer => {
observer.next({ success: true });
observer.complete();
});
}
}
\ No newline at end of file
import { DatasetWidgetLinkerComponent } from './widget-management/dataset-widget-linker.component';
import { Routes } from '@angular/router';
import { DashboardManagementComponent } from './dashboard-management/dashboard-management.component';
import { DashboardViewerComponent } from './dashboard-viewer/dashboard-viewer.component';
import { WidgetListComponent } from './widget-management/widget-list.component';
import { WidgetFormComponent } from './widget-management/widget-form.component';
import { moduleAccessGuard } from '../core/guards/module-access.guard';
import { DatasetWidgetLinkerComponent } from './widget-management/dataset-widget-linker.component';
export const portalManageRoutes: Routes = [
// Route for the specific MyHR+ module, which has its own services and routing.
// This must come BEFORE the generic ':appName' routes.
{
path: 'myhr-plus',
canActivate: [moduleAccessGuard], // Use the same guard to check if user can access 'myhr-plus'
loadChildren: () => import('./myhr-plus/myhr-plus.routes').then(m => m.MYHR_PLUS_ROUTES)
},
{
path: 'permission-management',
canActivate: [moduleAccessGuard],
loadChildren: () => import('./permission-management/permission-management.routes').then(m => m.PERMISSION_ROUTES)
},
// --- Generic App Routes ---
// These routes are for simple apps that don't need special module-level services.
// Dynamic route for dashboard management per application
{
path: ':appName/dashboard-management',
component: DashboardManagementComponent,
canActivate: [moduleAccessGuard]
},
// Dynamic routes for widget warehouse per application
{
path: ':appName/widget-warehouse',
component: WidgetListComponent,
canActivate: [moduleAccessGuard]
},
{
path: ':appName/widget-warehouse/edit/:widgetId',
component: WidgetFormComponent,
canActivate: [moduleAccessGuard]
},
{
path: ':appName/widget-linker',
component: DatasetWidgetLinkerComponent,
canActivate: [moduleAccessGuard]
},
// Route for viewing a specific dashboard, remains unchanged
{
......
import { Injectable } from '@angular/core';
import { Observable, of } from 'rxjs';
import { DashboardModel, WidgetModel } from '../models/widgets.model';
import { HttpClient, HttpHeaders, HttpParams } from '@angular/common/http';
import { environment } from '../../../environments/environment';
import { ApiService } from '../../../app/core/services/api.service'; // Corrected import path
import { HttpParams } from '@angular/common/http'; // Keep HttpParams if still used
@Injectable({
providedIn: 'root'
})
export class DashboardDataService {
apiBaseUrl = environment.url + "dashboard"
constructor(private http: HttpClient) { }
constructor(private apiService: ApiService) { }
getDashboards(queryParams?: any): Observable<DashboardModel[]> {
let params = new HttpParams();
......@@ -18,30 +17,21 @@ export class DashboardDataService {
params = params.set(key, queryParams[key]);
});
}
return this.http.get<DashboardModel[]>(`${this.apiBaseUrl}/lists/search`, { params })
return this.apiService.get<DashboardModel[]>(`dashboard/lists/search`, params);
}
getDashboardById(id: string): Observable<DashboardModel | undefined> {
return this.http
.get<DashboardModel>(this.apiBaseUrl + "/" + id)
return this.apiService.get<DashboardModel>(`dashboard/${id}`);
}
// For now, these methods will operate on the in-memory mock data
// In a real application, these would call API endpoints for CUD operations
saveDashboard(dashboard: DashboardModel): Observable<DashboardModel> {
return this.http.post<any>(this.apiBaseUrl, dashboard);
return this.apiService.post<DashboardModel>('dashboard', dashboard);
}
deleteDashboard(dashboard: DashboardModel): Observable<void> {
const options = {
headers: new HttpHeaders({
"Content-Type": "application/json",
}),
body: dashboard
};
return this.http.delete<any>(this.apiBaseUrl, options);
// Assuming the backend expects the ID in the URL for DELETE
// If the backend expects the full object in the body for DELETE,
// you might need to adjust ApiService.delete or use apiService.post to a specific delete endpoint.
return this.apiService.delete<void>(`dashboard/${dashboard.dashboardId}`);
}
// Assuming widgets are managed as part of dashboards for now
// If widgets were separate entities, you'd have getWidgets, addWidget, etc.
}
{
"roles": [
{
"id": "admin",
"name": "Administrator",
"description": "Has access to all system features."
},
{
"id": "manager",
"name": "Manager",
"description": "Can view dashboards and manage their team."
},
{
"id": "user",
"name": "Standard User",
"description": "Can access basic features and view their own data."
}
],
"applications": [
{
"appId": "dashboard-management",
"appName": "Dashboard Management",
"description": "Allows creating, editing, and deleting dashboards."
},
{
"appId": "widget-management",
"appName": "Widget Management",
"description": "Allows creating, editing, and deleting widgets."
},
{
"appId": "company-management",
"appName": "Company Management",
"description": "Allows managing company profiles and settings."
},
{
"appId": "my-portal",
"appName": "My Portal",
"description": "Access to the main user portal view."
}
],
"role_permissions": [
{
"roleId": "admin",
"permissions": {
"dashboard-management": true,
"widget-management": true,
"company-management": true,
"my-portal": true
}
},
{
"roleId": "manager",
"permissions": {
"dashboard-management": false,
"widget-management": false,
"company-management": false,
"my-portal": true
}
},
{
"roleId": "user",
"permissions": {
"dashboard-management": false,
"widget-management": false,
"company-management": false,
"my-portal": true
}
}
]
}
......@@ -129,5 +129,13 @@
"Faculty ID" : "Faculty ID",
"Faculty Information" : "Faculty Information",
"Major ID" : "Major ID",
"Major Information" : "Major Information"
"Major Information" : "Major Information",
"PERMISSION_MANAGEMENT": "Permission Management",
"ROLE_BASED_ACCESS_CONTROL": "Role-Based Access Control",
"ROLE_NAME": "Role Name",
"DESCRIPTION": "Description",
"ACTIONS": "Actions",
"EDIT_PERMISSIONS": "Edit Permissions",
"ROLE": "Role",
"SAVE_CHANGES": "Save Changes"
}
......@@ -129,6 +129,13 @@
"Faculty ID" : "รหัสคณะ",
"Faculty Information" : "ข้อมูลคณะ",
"Major ID" : "รหัสสาขาวิชา",
"Major Information" : "ข้อมูลสาขาวิชา"
"Major Information" : "ข้อมูลสาขาวิชา",
"PERMISSION_MANAGEMENT": "การจัดการสิทธิ์",
"ROLE_BASED_ACCESS_CONTROL": "การควบคุมการเข้าถึงตามบทบาท",
"ROLE_NAME": "ชื่อบทบาท",
"DESCRIPTION": "คำอธิบาย",
"ACTIONS": "การกระทำ",
"EDIT_PERMISSIONS": "แก้ไขสิทธิ์",
"ROLE": "บทบาท",
"SAVE_CHANGES": "บันทึกการเปลี่ยนแปลง"
}
export const environment = {
production: true,
apiUrl: '/api' // Example API URL for production
};
production: true,
// baseUrl: window.location.origin + '/api',
baseUrl: 'https://myjob-uat.myhr.co.th/api',
baseUrls: 'https://mylearn-uat.myhr.co.th/api',
......
......@@ -3,6 +3,8 @@
// The list of file replacements can be found in `angular.json`.
export const environment = {
production: false,
apiUrl: 'http://localhost:3000/api', // Example API URL for development
baseUrl: 'https://myjob-uat.myhr.co.th/api',
baseUrls: 'https://mylearn-uat.myhr.co.th/api',
// baseScormUrl: 'http://localhost/vsscorm',
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment