feat(settings): Added feature toggling. (TV-564)

Squashed commit of the following:

commit b67cced3bd44d1673173e5fa188d776d2d097fd4
Author: Erik Tiekstra <erik.tiekstra@arbetsformedlingen.se>
Date:   Fri Sep 10 11:59:37 2021 +0200

    Added feature toggling for routes and navigation
This commit is contained in:
Erik Tiekstra
2021-09-10 12:40:42 +02:00
parent 5b00453d97
commit d7318eb5ae
14 changed files with 154 additions and 62 deletions

View File

@@ -1,11 +1,14 @@
import { NgModule } from '@angular/core';
import { ExtraOptions, RouterModule, Routes } from '@angular/router';
import { Feature } from '@msfa-enums/feature.enum';
import { RoleEnum } from '@msfa-enums/role.enum';
import { environment } from '@msfa-environment';
import { AuthGuard } from '@msfa-guards/auth.guard';
import { OrganizationGuard } from '@msfa-guards/organization.guard';
import { RoleGuard } from '@msfa-guards/role.guard';
const activeFeatures: Feature[] = environment.activeFeatures;
const routes: Routes = [
{
path: '',
@@ -13,24 +16,6 @@ const routes: Routes = [
loadChildren: () => import('./pages/start/start.module').then(m => m.StartModule),
canActivate: [AuthGuard, OrganizationGuard],
},
{
path: 'administration',
data: { title: 'Administration', expectedRole: RoleEnum.MSFA_AuthAdmin },
loadChildren: () => import('./pages/administration/administration.module').then(m => m.AdministrationModule),
canActivate: [AuthGuard, OrganizationGuard, RoleGuard],
},
{
path: 'deltagare',
data: { title: 'Deltagare', expectedRole: RoleEnum.MSFA_ReportAndPlanning },
loadChildren: () => import('./pages/deltagare/deltagare.module').then(m => m.DeltagareModule),
canActivate: [AuthGuard, OrganizationGuard, RoleGuard],
},
{
path: 'nya-deltagare',
data: { title: 'Nya deltagare', expectedRole: RoleEnum.MSFA_ReceiveDeltagare },
loadChildren: () => import('./pages/avrop/avrop.module').then(m => m.AvropModule),
canActivate: [AuthGuard, OrganizationGuard, RoleGuard],
},
{
path: 'logga-ut',
data: { title: 'Logga ut' },
@@ -44,12 +29,6 @@ const routes: Routes = [
import('./pages/organization-picker/organization-picker.module').then(m => m.OrganizationPickerModule),
canActivate: [AuthGuard],
},
{
path: 'mitt-konto',
data: { title: 'Mitt konto' },
loadChildren: () => import('./pages/my-account/my-account.module').then(m => m.MyAccountModule),
canActivate: [AuthGuard, OrganizationGuard],
},
{
path: 'obehorig',
data: { title: 'Saknar behörighet' },
@@ -58,21 +37,59 @@ const routes: Routes = [
},
];
if (!environment.production) {
routes.push(
{
path: 'mock-login',
data: { title: 'Mock login' },
loadChildren: () => import('./pages/mock-login/mock-login.module').then(m => m.MockLoginModule),
},
{
path: 'releases',
data: { title: 'Releaser' },
loadChildren: () => import('./pages/releases/releases.module').then(m => m.ReleasesModule),
canActivate: [AuthGuard],
}
);
}
activeFeatures.forEach(feature => {
switch (feature) {
case Feature.ADMINISTRATION:
routes.push({
path: 'administration',
data: { title: 'Administration', expectedRole: RoleEnum.MSFA_AuthAdmin },
loadChildren: () => import('./pages/administration/administration.module').then(m => m.AdministrationModule),
canActivate: [AuthGuard, OrganizationGuard, RoleGuard],
});
break;
case Feature.AVROP:
routes.push({
path: 'nya-deltagare',
data: { title: 'Nya deltagare', expectedRole: RoleEnum.MSFA_ReceiveDeltagare },
loadChildren: () => import('./pages/avrop/avrop.module').then(m => m.AvropModule),
canActivate: [AuthGuard, OrganizationGuard, RoleGuard],
});
break;
case Feature.DELTAGARE:
routes.push({
path: 'deltagare',
data: { title: 'Deltagare', expectedRole: RoleEnum.MSFA_ReportAndPlanning },
loadChildren: () => import('./pages/deltagare/deltagare.module').then(m => m.DeltagareModule),
canActivate: [AuthGuard, OrganizationGuard, RoleGuard],
});
break;
case Feature.MY_ACCOUNT:
routes.push({
path: 'mitt-konto',
data: { title: 'Mitt konto' },
loadChildren: () => import('./pages/my-account/my-account.module').then(m => m.MyAccountModule),
canActivate: [AuthGuard, OrganizationGuard],
});
break;
case Feature.RELEASES:
routes.push({
path: 'releases',
data: { title: 'Releaser' },
loadChildren: () => import('./pages/releases/releases.module').then(m => m.ReleasesModule),
canActivate: [AuthGuard],
});
break;
case Feature.MOCK_LOGIN:
routes.push({
path: 'mock-login',
data: { title: 'Mock login' },
loadChildren: () => import('./pages/mock-login/mock-login.module').then(m => m.MockLoginModule),
});
break;
default:
break;
}
});
routes.push({
path: '**',

View File

@@ -5,13 +5,13 @@
</a>
</div>
<ul class="navigation__list msfa__hide-on-print" *ngIf="user">
<li class="navigation__item">
<li class="navigation__item" *ngIf="myAccountVisible">
<a routerLink="/mitt-konto" class="navigation__link">
<msfa-icon [icon]="iconType.USER" size="l"></msfa-icon>
<span class="navigation__text">{{ user.fullName }}</span>
</a>
</li>
<li *ngIf="selectedOrganization" class="navigation__item navigation__item--without-link">
<li *ngIf="selectedOrganization && myOrganizationVisible" class="navigation__item navigation__item--without-link">
<msfa-icon [icon]="iconType.BUILDING" size="l"></msfa-icon>
<span class="navigation__text">{{ selectedOrganization.name }}</span>
</li>

View File

@@ -1,5 +1,7 @@
import { ChangeDetectionStrategy, Component, Input } from '@angular/core';
import { Feature } from '@msfa-enums/feature.enum';
import { IconType } from '@msfa-enums/icon-type.enum';
import { environment } from '@msfa-environment';
import { Employee } from '@msfa-models/employee.model';
import { Organization } from '@msfa-models/organization.model';
@@ -13,4 +15,12 @@ export class NavigationComponent {
@Input() user: Employee;
@Input() selectedOrganization: Organization;
iconType = IconType;
activeFeatures: Feature[] = environment.activeFeatures;
get myAccountVisible(): boolean {
return this.activeFeatures.includes(Feature.MY_ACCOUNT);
}
get myOrganizationVisible(): boolean {
return this.activeFeatures.includes(Feature.MY_ORGANIZATION);
}
}

View File

@@ -11,20 +11,20 @@
Hem
</a>
</li>
<li class="sidebar__item" *ngIf="isReceiveDeltagare">
<li class="sidebar__item" *ngIf="avropVisible">
<a [routerLink]="['/nya-deltagare']" [routerLinkActive]="['sidebar__link--active']" class="sidebar__link">
<msfa-icon class="sidebar__icon" [icon]="iconType.CLIPBOARD" size="xl"></msfa-icon>
Nya deltagare
</a>
</li>
<li class="sidebar__item" *ngIf="isReportAndPlanning">
<li class="sidebar__item" *ngIf="deltagareVisible">
<a [routerLink]="['/deltagare']" [routerLinkActive]="['sidebar__link--active']" class="sidebar__link">
<msfa-icon class="sidebar__icon" [icon]="iconType.SOK_KANDIDAT" size="xl"></msfa-icon>
Deltagarlista
</a>
</li>
<li class="sidebar__item" *ngIf="isAuthAdmin">
<li class="sidebar__item" *ngIf="adminVisible">
<a [routerLink]="['/administration']" [routerLinkActive]="['sidebar__link--active']" class="sidebar__link">
<msfa-icon class="sidebar__icon" [icon]="iconType.SETTINGS" size="xl"></msfa-icon>
Administration

View File

@@ -1,6 +1,8 @@
import { ChangeDetectionStrategy, Component, Input } from '@angular/core';
import { Feature } from '@msfa-enums/feature.enum';
import { IconType } from '@msfa-enums/icon-type.enum';
import { RoleEnum } from '@msfa-enums/role.enum';
import { environment } from '@msfa-environment';
import { Role } from '@msfa-models/role.model';
@Component({
@@ -12,14 +14,24 @@ import { Role } from '@msfa-models/role.model';
export class SidebarComponent {
@Input() userRoles: Role[];
iconType = IconType;
activeFeatures: Feature[] = environment.activeFeatures;
get isAuthAdmin(): boolean {
return this.userRoles?.some(role => role.type === RoleEnum.MSFA_AuthAdmin);
get adminVisible(): boolean {
return (
this.activeFeatures.includes(Feature.ADMINISTRATION) &&
this.userRoles?.some(role => role.type === RoleEnum.MSFA_AuthAdmin)
);
}
get isReceiveDeltagare(): boolean {
return this.userRoles?.some(role => role.type === RoleEnum.MSFA_ReceiveDeltagare);
get avropVisible(): boolean {
return (
this.activeFeatures.includes(Feature.AVROP) &&
this.userRoles?.some(role => role.type === RoleEnum.MSFA_ReceiveDeltagare)
);
}
get isReportAndPlanning(): boolean {
return this.userRoles?.some(role => role.type === RoleEnum.MSFA_ReportAndPlanning);
get deltagareVisible(): boolean {
return (
this.activeFeatures.includes(Feature.DELTAGARE) &&
this.userRoles?.some(role => role.type === RoleEnum.MSFA_ReportAndPlanning)
);
}
}

View File

@@ -0,0 +1,9 @@
export enum Feature {
AVROP,
DELTAGARE,
ADMINISTRATION,
MY_ACCOUNT,
MY_ORGANIZATION,
RELEASES,
MOCK_LOGIN,
}

View File

@@ -0,0 +1,5 @@
export interface Ciam {
clientId: string;
loginUrl: string;
logoutUrl: string;
}

View File

@@ -1,3 +1,5 @@
import { Feature } from '@msfa-enums/feature.enum';
export interface Environment {
environment: 'api' | 'local' | 'acc' | 'prod';
clientId: string;
@@ -8,4 +10,5 @@ export interface Environment {
url: string;
headers: { [key: string]: string };
};
activeFeatures: Feature[];
}

View File

@@ -0,0 +1,12 @@
import { Feature } from '@msfa-enums/feature.enum';
export const ACTIVE_FEATURES_PROD: Feature[] = [Feature.ADMINISTRATION, Feature.MY_ACCOUNT, Feature.MY_ORGANIZATION];
export const ACTIVE_FEATURES_TEST: Feature[] = [
Feature.ADMINISTRATION,
Feature.MY_ACCOUNT,
Feature.DELTAGARE,
Feature.AVROP,
Feature.MY_ORGANIZATION,
Feature.RELEASES,
];

View File

@@ -0,0 +1,19 @@
import { Ciam } from '@msfa-models/ciam.model';
export const CIAM_TEST: Ciam = {
clientId: '5d08c2e4-763e-42f6-b858-24e4773bb83d',
loginUrl: 'https://ciam-test.arbetsformedlingen.se:8443/uas/oauth2/authorization?response_type=code&scope=openid',
logoutUrl: 'https://ciam-test.arbetsformedlingen.se:8443/uas/logout',
};
export const CIAM_PROD: Ciam = {
clientId: '71010833-e445-4bbc-926a-775247b7a6e3',
loginUrl: 'https://ciam.arbetsformedlingen.se/uas/oauth2/authorization?response_type=code&scope=openid',
logoutUrl: 'https://ciam.arbetsformedlingen.se/uas/logout',
};
export const CIAM_MOCK: Ciam = {
clientId: '',
loginUrl: '/mock-login',
logoutUrl: '/mock-login',
};

View File

@@ -1,13 +1,14 @@
import { Environment } from '@msfa-models/environment.model';
import { ACTIVE_FEATURES_PROD } from './active-features';
import { CIAM_TEST } from './ciam';
export const environment: Environment = {
environment: 'acc',
clientId: '5d08c2e4-763e-42f6-b858-24e4773bb83d',
loginUrl: 'https://ciam-test.arbetsformedlingen.se:8443/uas/oauth2/authorization?response_type=code&scope=openid',
logoutUrl: 'https://ciam-test.arbetsformedlingen.se:8443/uas/logout',
production: true,
api: {
url: '/api',
headers: {},
},
activeFeatures: [...ACTIVE_FEATURES_PROD],
...CIAM_TEST,
};

View File

@@ -1,13 +1,14 @@
import { Environment } from '@msfa-models/environment.model';
import { ACTIVE_FEATURES_TEST } from './active-features';
import { CIAM_TEST } from './ciam';
export const environment: Environment = {
environment: 'api',
clientId: '5d08c2e4-763e-42f6-b858-24e4773bb83d',
loginUrl: 'https://ciam-test.arbetsformedlingen.se:8443/uas/oauth2/authorization?response_type=code&scope=openid',
logoutUrl: 'https://ciam-test.arbetsformedlingen.se:8443/uas/logout',
production: false,
api: {
url: '/api',
headers: {},
},
activeFeatures: [...ACTIVE_FEATURES_TEST],
...CIAM_TEST,
};

View File

@@ -1,13 +1,14 @@
import { Environment } from '@msfa-models/environment.model';
import { ACTIVE_FEATURES_PROD } from './active-features';
import { CIAM_PROD } from './ciam';
export const environment: Environment = {
environment: 'prod',
clientId: '71010833-e445-4bbc-926a-775247b7a6e3',
loginUrl: 'https://ciam.arbetsformedlingen.se/uas/oauth2/authorization?response_type=code&scope=openid',
logoutUrl: 'https://ciam.arbetsformedlingen.se/uas/logout',
production: true,
api: {
url: '/api',
headers: {},
},
activeFeatures: [...ACTIVE_FEATURES_PROD],
...CIAM_PROD,
};

View File

@@ -1,13 +1,15 @@
import { Feature } from '@msfa-enums/feature.enum';
import { Environment } from '@msfa-models/environment.model';
import { ACTIVE_FEATURES_TEST } from './active-features';
import { CIAM_MOCK } from './ciam';
export const environment: Environment = {
environment: 'local',
clientId: '',
loginUrl: '/mock-login',
logoutUrl: '/mock-login',
production: false,
api: {
url: '/api',
headers: {},
},
activeFeatures: [...ACTIVE_FEATURES_TEST, Feature.MOCK_LOGIN],
...CIAM_MOCK,
};