refractor(breadcrumb): enhance breadcrumb (#129)
Enhance breadcrumb design and generation Fixes #106
This commit is contained in:
@@ -1,12 +1,14 @@
|
|||||||
<nav>
|
<nav class="breadcrumb-wrapper">
|
||||||
<div class="breadcrumb-wrapper">
|
<ul class="breadcrumb">
|
||||||
<ul>
|
<span class="breadcrumb-title">{{ breadcrumbs[breadcrumbs.length-1].label }}</span>
|
||||||
<li *ngFor="let breadcrumb of breadcrumbs; let last = last">
|
<span *ngIf="breadcrumbs.length-1 !== 0" class="separator">
|
||||||
<span *ngIf="!last">
|
<li *ngFor="let breadcrumb of breadcrumbs; let last = last" class="breadcrumb-label">
|
||||||
<a *ngIf="!last" [routerLink]="breadcrumb.url">{{breadcrumb.label}}</a> >
|
<span *ngIf="!last" class="breadcrumb-link">
|
||||||
|
<a *ngIf="breadcrumb.url" [routerLink]="breadcrumb.url">{{ breadcrumb.label }}</a>
|
||||||
|
<span *ngIf="!breadcrumb.url">{{ breadcrumb.label }}</span>
|
||||||
</span>
|
</span>
|
||||||
<span *ngIf="last">{{ breadcrumb.label }}</span>
|
<span *ngIf="last">{{ breadcrumb.label }}</span>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</span>
|
||||||
</div>
|
</ul>
|
||||||
</nav>
|
</nav>
|
||||||
|
|||||||
@@ -1,4 +1,48 @@
|
|||||||
li {
|
.breadcrumb-wrapper {
|
||||||
display: inline;
|
margin: 0 auto;
|
||||||
list-style-type: none;
|
max-width: 74rem;
|
||||||
|
width: 90%;
|
||||||
|
|
||||||
|
.breadcrumb {
|
||||||
|
list-style: none;
|
||||||
|
padding: 0;
|
||||||
|
margin: 1.5rem 0;
|
||||||
|
line-height: 40px;
|
||||||
|
|
||||||
|
.breadcrumb-title {
|
||||||
|
font-size: 1.25rem;
|
||||||
|
font-weight: 400;
|
||||||
|
}
|
||||||
|
|
||||||
|
.separator:before {
|
||||||
|
content: "";
|
||||||
|
border: 1.5px solid #000;
|
||||||
|
margin: 0 0.6rem;
|
||||||
|
font-size: 1.25rem;
|
||||||
|
font-weight: 400;
|
||||||
|
}
|
||||||
|
|
||||||
|
.breadcrumb-label {
|
||||||
|
display: inline;
|
||||||
|
font-size: 1rem;
|
||||||
|
|
||||||
|
.breadcrumb-link {
|
||||||
|
a {
|
||||||
|
text-decoration: none;
|
||||||
|
color: #0275d8;
|
||||||
|
}
|
||||||
|
a:hover {
|
||||||
|
text-decoration: underline;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.breadcrumb-link:after {
|
||||||
|
content: "/";
|
||||||
|
margin: 0 0.4rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,40 +22,63 @@ export class BreadcrumbComponent implements OnInit {
|
|||||||
generateBreadcrumbs() {
|
generateBreadcrumbs() {
|
||||||
const routeDataBreadcrumb = 'breadcrumb';
|
const routeDataBreadcrumb = 'breadcrumb';
|
||||||
const routeParamBreadcrumb = 'routeParamBreadcrumb';
|
const routeParamBreadcrumb = 'routeParamBreadcrumb';
|
||||||
|
const routeResolveBreadcrumb = 'routeResolveBreadcrumb';
|
||||||
|
const routeAddBreadcrumbLink = 'addBreadcrumbLink';
|
||||||
|
|
||||||
const onNavigationEnd = this.router.events.pipe(filter(event => event instanceof NavigationEnd));
|
const onNavigationEnd = this.router.events.pipe(filter(event => event instanceof NavigationEnd));
|
||||||
|
|
||||||
onNavigationEnd.subscribe(() => {
|
onNavigationEnd.subscribe(() => {
|
||||||
this.breadcrumbs = [];
|
this.breadcrumbs = [];
|
||||||
let currentRoute = this.activatedRoute.root;
|
let currentRoute = this.activatedRoute.root;
|
||||||
let url = '';
|
let currentUrl = '';
|
||||||
|
|
||||||
while (currentRoute.children.length > 0) {
|
while (currentRoute.children.length > 0) {
|
||||||
const childrenRoutes = currentRoute.children;
|
const childrenRoutes = currentRoute.children;
|
||||||
let breadcrumbLabel = 'Home';
|
let breadcrumbLabel: any;
|
||||||
|
let url: any;
|
||||||
|
|
||||||
childrenRoutes.forEach(route => {
|
childrenRoutes.forEach(route => {
|
||||||
currentRoute = route;
|
currentRoute = route;
|
||||||
|
breadcrumbLabel = false;
|
||||||
|
|
||||||
if (route.outlet !== 'primary') {
|
if (route.outlet !== 'primary') {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const routeURL = route.snapshot.url.map(segment => segment.path).join('/');
|
||||||
|
currentUrl += `/${routeURL}`;
|
||||||
|
|
||||||
|
if (currentUrl === '/') {
|
||||||
|
breadcrumbLabel = 'Home';
|
||||||
|
}
|
||||||
|
|
||||||
const hasData = (route.routeConfig && route.routeConfig.data);
|
const hasData = (route.routeConfig && route.routeConfig.data);
|
||||||
|
|
||||||
if (hasData) {
|
if (hasData) {
|
||||||
if (route.snapshot.data.hasOwnProperty(routeParamBreadcrumb)) {
|
if (route.snapshot.data.hasOwnProperty(routeResolveBreadcrumb) && route.snapshot.data[routeResolveBreadcrumb]) {
|
||||||
breadcrumbLabel = route.snapshot.params[route.snapshot.data[routeParamBreadcrumb]];
|
breadcrumbLabel = route.snapshot.data;
|
||||||
|
route.snapshot.data[routeResolveBreadcrumb].forEach((property: any) => {
|
||||||
|
breadcrumbLabel = breadcrumbLabel[property];
|
||||||
|
});
|
||||||
|
} else if (route.snapshot.data.hasOwnProperty(routeParamBreadcrumb) && route.snapshot.paramMap.get(route.snapshot.data[routeParamBreadcrumb])) {
|
||||||
|
breadcrumbLabel = route.snapshot.paramMap.get(route.snapshot.data[routeParamBreadcrumb]);
|
||||||
} else if (route.snapshot.data.hasOwnProperty(routeDataBreadcrumb)) {
|
} else if (route.snapshot.data.hasOwnProperty(routeDataBreadcrumb)) {
|
||||||
breadcrumbLabel = route.snapshot.data[routeDataBreadcrumb];
|
breadcrumbLabel = route.snapshot.data[routeDataBreadcrumb];
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
const routeURL = route.snapshot.url.map(segment => segment.path).join('/');
|
if (route.snapshot.data.hasOwnProperty(routeAddBreadcrumbLink)) {
|
||||||
url += `/${routeURL}`;
|
url = route.snapshot.data[routeAddBreadcrumbLink];
|
||||||
|
} else {
|
||||||
|
url = currentUrl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const breadcrumb: Breadcrumb = {
|
const breadcrumb: Breadcrumb = {
|
||||||
label: breadcrumbLabel,
|
label: breadcrumbLabel,
|
||||||
url: url
|
url: url
|
||||||
};
|
};
|
||||||
|
|
||||||
if (breadcrumb.url !== '//home') {
|
if (breadcrumbLabel) {
|
||||||
this.breadcrumbs.push(breadcrumb);
|
this.breadcrumbs.push(breadcrumb);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -18,9 +18,9 @@ const routes: Routes = [
|
|||||||
data: { title: extract('Home') }
|
data: { title: extract('Home') }
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: 'home/dashboard',
|
path: 'dashboard',
|
||||||
component: DashboardComponent,
|
component: DashboardComponent,
|
||||||
data: { title: extract('Dashboard') }
|
data: { title: extract('Dashboard'), breadcrumb: 'Dashboard' }
|
||||||
}
|
}
|
||||||
])
|
])
|
||||||
];
|
];
|
||||||
|
|||||||
@@ -2,38 +2,60 @@ import { NgModule } from '@angular/core';
|
|||||||
import { Routes, RouterModule } from '@angular/router';
|
import { Routes, RouterModule } from '@angular/router';
|
||||||
|
|
||||||
import { Route, extract } from '../core';
|
import { Route, extract } from '../core';
|
||||||
import { UserManagementComponent } from './user-management/user-management.component';
|
import { UsersComponent } from './users/users.component';
|
||||||
import { CreateUserComponent } from './create-user/create-user.component';
|
import { CreateUserComponent } from './users/create-user/create-user.component';
|
||||||
import { ViewUserComponent } from './view-user/view-user.component';
|
import { ViewUserComponent } from './users/view-user/view-user.component';
|
||||||
import { EditUserComponent } from './edit-user/edit-user.component';
|
import { EditUserComponent } from './users/edit-user/edit-user.component';
|
||||||
import { AppConfigurationComponent } from './app-configuration/app-configuration.component';
|
import { AppConfigurationComponent } from './app-configuration/app-configuration.component';
|
||||||
|
import { SelfServiceComponent } from './self-service.component';
|
||||||
|
import { ViewUserResolver } from './users/view-user/view-user.resolver';
|
||||||
|
|
||||||
const routes: Routes = [
|
const routes: Routes = [
|
||||||
Route.withShell([
|
Route.withShell([
|
||||||
{
|
{
|
||||||
path: 'self-service/users',
|
path: 'self-service',
|
||||||
component: UserManagementComponent,
|
component: SelfServiceComponent,
|
||||||
data: { title: extract('Self Service Users'), breadcrumb: 'Self Service Users' }
|
data: { title: extract('Self Service'), breadcrumb: 'Self Service', addBreadcrumbLink: false },
|
||||||
},
|
children: [
|
||||||
{
|
{
|
||||||
path: 'self-service/users/create',
|
path: 'users',
|
||||||
component: CreateUserComponent,
|
data: { title: extract('Self Service Users'), breadcrumb: 'Users' },
|
||||||
data: { title: extract('Create Self Service User'), breadcrumb: 'Self Service Users > Create' }
|
children: [
|
||||||
},
|
{
|
||||||
{
|
path: '',
|
||||||
path: 'self-service/users/view',
|
component: UsersComponent
|
||||||
component: ViewUserComponent,
|
},
|
||||||
data: { title: extract('View Self Service User'), breadcrumb: 'Self Service Users > View' },
|
{
|
||||||
},
|
path: 'create',
|
||||||
{
|
component: CreateUserComponent,
|
||||||
path: 'self-service/users/edit',
|
data: { title: extract('Create Self Service User'), breadcrumb: 'Create' }
|
||||||
component: EditUserComponent,
|
},
|
||||||
data: { title: extract('Edit Self Service User'), breadcrumb: 'Self Service Users > Edit' },
|
{
|
||||||
},
|
path: 'view/:id',
|
||||||
{
|
data: { title: extract('View Self Service User'), routeResolveBreadcrumb: ['user', 'username'] },
|
||||||
path: 'self-service/app-configuration',
|
resolve: {
|
||||||
component: AppConfigurationComponent,
|
user: ViewUserResolver
|
||||||
data: { title: extract('App Configuration'), breadcrumb: 'App Configuration' },
|
},
|
||||||
|
children: [
|
||||||
|
{
|
||||||
|
path: '',
|
||||||
|
component: ViewUserComponent
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: 'edit',
|
||||||
|
component: EditUserComponent,
|
||||||
|
data: { title: extract('Edit Self Service User'), breadcrumb: 'Edit', routeResolveBreadcrumb: false }
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: 'app-configuration',
|
||||||
|
component: AppConfigurationComponent,
|
||||||
|
data: { title: extract('App Configuration'), breadcrumb: 'App Configuration' },
|
||||||
|
}
|
||||||
|
]
|
||||||
}
|
}
|
||||||
])
|
])
|
||||||
];
|
];
|
||||||
@@ -41,6 +63,6 @@ const routes: Routes = [
|
|||||||
@NgModule({
|
@NgModule({
|
||||||
imports: [RouterModule.forChild(routes)],
|
imports: [RouterModule.forChild(routes)],
|
||||||
exports: [RouterModule],
|
exports: [RouterModule],
|
||||||
providers: []
|
providers: [ViewUserResolver]
|
||||||
})
|
})
|
||||||
export class SelfServiceRoutingModule { }
|
export class SelfServiceRoutingModule { }
|
||||||
|
|||||||
@@ -0,0 +1 @@
|
|||||||
|
<router-outlet></router-outlet>
|
||||||
+6
-6
@@ -1,20 +1,20 @@
|
|||||||
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
|
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
|
||||||
|
|
||||||
import { UserManagementComponent } from './user-management.component';
|
import { SelfServiceComponent } from './self-service.component';
|
||||||
|
|
||||||
describe('UserManagementComponent', () => {
|
describe('SelfServiceComponent', () => {
|
||||||
let component: UserManagementComponent;
|
let component: SelfServiceComponent;
|
||||||
let fixture: ComponentFixture<UserManagementComponent>;
|
let fixture: ComponentFixture<SelfServiceComponent>;
|
||||||
|
|
||||||
beforeEach(async(() => {
|
beforeEach(async(() => {
|
||||||
TestBed.configureTestingModule({
|
TestBed.configureTestingModule({
|
||||||
declarations: [ UserManagementComponent ]
|
declarations: [ SelfServiceComponent ]
|
||||||
})
|
})
|
||||||
.compileComponents();
|
.compileComponents();
|
||||||
}));
|
}));
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
fixture = TestBed.createComponent(UserManagementComponent);
|
fixture = TestBed.createComponent(SelfServiceComponent);
|
||||||
component = fixture.componentInstance;
|
component = fixture.componentInstance;
|
||||||
fixture.detectChanges();
|
fixture.detectChanges();
|
||||||
});
|
});
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
import { Component, OnInit } from '@angular/core';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'mifosx-self-service',
|
||||||
|
templateUrl: './self-service.component.html',
|
||||||
|
styleUrls: ['./self-service.component.scss']
|
||||||
|
})
|
||||||
|
export class SelfServiceComponent implements OnInit {
|
||||||
|
|
||||||
|
constructor() { }
|
||||||
|
|
||||||
|
ngOnInit() {
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -4,12 +4,13 @@ import { FormsModule } from '@angular/forms';
|
|||||||
|
|
||||||
import { CoreModule } from '../core/core.module';
|
import { CoreModule } from '../core/core.module';
|
||||||
import { SelfServiceRoutingModule } from './self-service-routing.module';
|
import { SelfServiceRoutingModule } from './self-service-routing.module';
|
||||||
import { UserManagementComponent } from './user-management/user-management.component';
|
import { CreateUserComponent } from './users/create-user/create-user.component';
|
||||||
import { CreateUserComponent } from './create-user/create-user.component';
|
import { ViewUserComponent } from './users/view-user/view-user.component';
|
||||||
import { ViewUserComponent } from './view-user/view-user.component';
|
import { EditUserComponent } from './users/edit-user/edit-user.component';
|
||||||
import { EditUserComponent } from './edit-user/edit-user.component';
|
|
||||||
import { AppConfigurationComponent } from './app-configuration/app-configuration.component';
|
import { AppConfigurationComponent } from './app-configuration/app-configuration.component';
|
||||||
import { SharedModule } from '../shared/shared.module';
|
import { SharedModule } from '../shared/shared.module';
|
||||||
|
import { SelfServiceComponent } from './self-service.component';
|
||||||
|
import { UsersComponent } from './users/users.component';
|
||||||
|
|
||||||
@NgModule({
|
@NgModule({
|
||||||
imports: [
|
imports: [
|
||||||
@@ -20,7 +21,8 @@ import { SharedModule } from '../shared/shared.module';
|
|||||||
SelfServiceRoutingModule
|
SelfServiceRoutingModule
|
||||||
],
|
],
|
||||||
declarations: [
|
declarations: [
|
||||||
UserManagementComponent,
|
SelfServiceComponent,
|
||||||
|
UsersComponent,
|
||||||
CreateUserComponent,
|
CreateUserComponent,
|
||||||
ViewUserComponent,
|
ViewUserComponent,
|
||||||
EditUserComponent,
|
EditUserComponent,
|
||||||
|
|||||||
@@ -25,4 +25,8 @@ export class UserService {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
getUser(): Observable<any> {
|
||||||
|
return this.http.disableApiPrefix().get('http://localhost:4200/assets/mock/user.mock.json');
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
+1
-1
@@ -15,7 +15,7 @@
|
|||||||
<!-- <mat-card-actions> -->
|
<!-- <mat-card-actions> -->
|
||||||
<!-- <button mat-raised-button color="primary"><mat-icon>lock_open</mat-icon> Activate</button> -->
|
<!-- <button mat-raised-button color="primary"><mat-icon>lock_open</mat-icon> Activate</button> -->
|
||||||
<!-- <button mat-raised-button color="primary"><mat-icon>lock</mat-icon> Deactivate</button> -->
|
<!-- <button mat-raised-button color="primary"><mat-icon>lock</mat-icon> Deactivate</button> -->
|
||||||
<button mat-raised-button color="primary" routerLink="/self-service/users/create"><mat-icon>add</mat-icon> Create User</button>
|
<button mat-raised-button color="primary" [routerLink]="['/self-service/users/create']"><mat-icon>add</mat-icon> Create User</button>
|
||||||
<!-- </mat-card-actions> -->
|
<!-- </mat-card-actions> -->
|
||||||
<!-- </mat-grid-tile> -->
|
<!-- </mat-grid-tile> -->
|
||||||
|
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
|
||||||
|
|
||||||
|
import { UsersComponent } from './users.component';
|
||||||
|
|
||||||
|
describe('UsersComponent', () => {
|
||||||
|
let component: UsersComponent;
|
||||||
|
let fixture: ComponentFixture<UsersComponent>;
|
||||||
|
|
||||||
|
beforeEach(async(() => {
|
||||||
|
TestBed.configureTestingModule({
|
||||||
|
declarations: [ UsersComponent ]
|
||||||
|
})
|
||||||
|
.compileComponents();
|
||||||
|
}));
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
fixture = TestBed.createComponent(UsersComponent);
|
||||||
|
component = fixture.componentInstance;
|
||||||
|
fixture.detectChanges();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should create', () => {
|
||||||
|
expect(component).toBeTruthy();
|
||||||
|
});
|
||||||
|
});
|
||||||
+5
-5
@@ -1,7 +1,7 @@
|
|||||||
import { Component, OnInit, ViewChild } from '@angular/core';
|
import { Component, OnInit, ViewChild } from '@angular/core';
|
||||||
import { SelectionModel } from '@angular/cdk/collections';
|
import { SelectionModel } from '@angular/cdk/collections';
|
||||||
import { MatPaginator, MatSort, MatTableDataSource } from '@angular/material';
|
import { MatPaginator, MatSort, MatTableDataSource } from '@angular/material';
|
||||||
import { UserService } from '../user.service';
|
import { UserService } from './user.service';
|
||||||
|
|
||||||
export interface User {
|
export interface User {
|
||||||
name: string;
|
name: string;
|
||||||
@@ -13,11 +13,11 @@ export interface User {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'mifosx-user-management',
|
selector: 'mifosx-users',
|
||||||
templateUrl: './user-management.component.html',
|
templateUrl: './users.component.html',
|
||||||
styleUrls: ['./user-management.component.scss']
|
styleUrls: ['./users.component.scss']
|
||||||
})
|
})
|
||||||
export class UserManagementComponent implements OnInit {
|
export class UsersComponent implements OnInit {
|
||||||
|
|
||||||
displayedColumns: string[] = ['select', 'name', 'id', 'email', 'status', 'officeName', 'staff'];
|
displayedColumns: string[] = ['select', 'name', 'id', 'email', 'status', 'officeName', 'staff'];
|
||||||
dataSource: any;
|
dataSource: any;
|
||||||
+1
-1
@@ -5,7 +5,7 @@
|
|||||||
</mat-card-header>
|
</mat-card-header>
|
||||||
|
|
||||||
<mat-card-actions align="right">
|
<mat-card-actions align="right">
|
||||||
<button mat-raised-button color="primary" routerLink="/self-service/users/edit"><mat-icon>edit</mat-icon> Edit</button>
|
<button mat-raised-button color="primary" [routerLink]="['/self-service/users/view/123456/edit']"><mat-icon>edit</mat-icon> Edit</button>
|
||||||
<button mat-raised-button color="primary" (click)="openDialog()"><mat-icon>settings</mat-icon> Change Password</button>
|
<button mat-raised-button color="primary" (click)="openDialog()"><mat-icon>settings</mat-icon> Change Password</button>
|
||||||
<button mat-raised-button color="primary"><mat-icon>lock</mat-icon> Deactivate</button>
|
<button mat-raised-button color="primary"><mat-icon>lock</mat-icon> Deactivate</button>
|
||||||
</mat-card-actions>
|
</mat-card-actions>
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
import { Injectable } from '@angular/core';
|
||||||
|
import { Resolve } from '@angular/router';
|
||||||
|
|
||||||
|
import { Observable, of } from 'rxjs';
|
||||||
|
import { UserService } from '../user.service';
|
||||||
|
|
||||||
|
@Injectable()
|
||||||
|
export class ViewUserResolver implements Resolve<Object> {
|
||||||
|
|
||||||
|
constructor(private userService: UserService) {}
|
||||||
|
|
||||||
|
resolve(): Observable<any> {
|
||||||
|
return this.userService.getUser();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -59,7 +59,7 @@ export class WebAppComponent implements OnInit {
|
|||||||
.subscribe(event => {
|
.subscribe(event => {
|
||||||
const title = event['title'];
|
const title = event['title'];
|
||||||
if (title) {
|
if (title) {
|
||||||
this.titleService.setTitle(this.translateService.instant(title));
|
this.titleService.setTitle(`${this.translateService.instant(title)} | Mifos X`);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,4 @@
|
|||||||
|
{
|
||||||
|
"id": 1,
|
||||||
|
"username": "abhaychawla"
|
||||||
|
}
|
||||||
+1
-1
@@ -2,7 +2,7 @@
|
|||||||
<html lang="en">
|
<html lang="en">
|
||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8"/>
|
<meta charset="utf-8"/>
|
||||||
<title>MifosX</title>
|
<title>Mifos X</title>
|
||||||
<base href="/"/>
|
<base href="/"/>
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no"/>
|
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no"/>
|
||||||
<meta name="apple-mobile-web-app-capable" content="yes">
|
<meta name="apple-mobile-web-app-capable" content="yes">
|
||||||
|
|||||||
Reference in New Issue
Block a user