Compare commits

..

41 Commits

Author SHA1 Message Date
sercan
2c5cd60c0a (general) Updated version numbers and changelog 2021-06-03 13:25:07 +03:00
sercan
decb238f73 (dependencies) Updated various dependencies to their latest versions
(fuse/highlight) Updated the import path
2021-06-03 13:18:05 +03:00
sercan
ab3ad4fd2f (apps/scrumboard) Dark mode fixes and tweaks 2021-06-03 11:27:51 +03:00
sercan
c2dd77d7a3 (angular.json) Removed "e2e" entry, fixed the styles file path for "test" 2021-06-02 12:45:12 +03:00
sercan
a78b087a68 (apps/scrumboard) New version of the Scrumboard app 2021-06-02 11:42:22 +03:00
sercan
84d40427a1 (apps/ecommerce) Small tweaks
(apps/mailbox) Small tweaks
2021-06-02 11:41:47 +03:00
sercan
f295fd9061 (fuse/autogrow) BREAKING: Removed fuseAutogrow in favor of matTextareaAutosize since all of its problems solved, use [matTextareaAutosize] without any vertical padding on the textarea itself. 2021-05-31 17:14:03 +03:00
sercan
b98cfc1d37 (Angular Material) Increased default MatDialog border radius to 16px for better consistency 2021-05-31 16:12:08 +03:00
sercan
0ba5677c01 (Dependencies) Updated Angular & Angular Material to v12.0.2 2021-05-31 10:49:51 +03:00
sercan
96ef1281ae (Angular Material) Fixed: Density setting is not working for dark themes 2021-05-31 10:45:29 +03:00
sercan
466bf50de4 Increased the version number
Updated the changelog
2021-05-24 14:32:45 +03:00
sercan
95bc7dc4db (apps/ecommerce/inventory) Performance improvements, decreased the mockApi delay 2021-05-24 09:22:18 +03:00
sercan
cfca19dc68 (mockApi) Removed typings from data files 2021-05-23 07:11:58 +03:00
sercan
a0c20f8d59 (pages/settings) Fixed: Settings container component width is not filling the container 2021-05-22 21:14:42 +03:00
sercan
df9f2256cd Increased the version number
Updated the changelog
2021-05-21 12:02:05 +03:00
sercan
6bcd04b799 (eslint) Fixed linting issues 2021-05-21 11:48:42 +03:00
sercan
3c0e326113 (dependencies) Updated various packages to their latest versions 2021-05-21 11:40:50 +03:00
sercan
c7158377f7 Revert "(dependencies) Updated Angular & Angular Material to v12.0.1"
This reverts commit 105575d4
2021-05-20 22:46:40 +03:00
sercan
105575d40e (dependencies) Updated Angular & Angular Material to v12.0.1 2021-05-20 22:23:25 +03:00
sercan
f470313d72 (pages/activities) Couple data tweaks 2021-05-20 16:51:40 +03:00
sercan
60e9c65505 (pages/activities) Couple data and style tweaks 2021-05-20 16:48:38 +03:00
sercan
3b727fe859 (pages/activities) Added Activities page (timeline) 2021-05-20 15:30:14 +03:00
sercan
4694bb401d (layout/common) Added trackBy functions to ngFor loops in common components 2021-05-19 22:43:16 +03:00
sercan
ee86dc6245 (tailwind) Use TAILWIND_MODE environment variable to activate purge on build 2021-05-19 14:45:30 +03:00
sercan
3d09241c64 (fuse/animations) Fixed: Barrel exports
(FuseMasonry) Fixed: Barrel exports
(FuseUtilsService) Fixed: Barrel exports
(FuseValidators) Fixed: Barrel exports
2021-05-19 14:37:38 +03:00
sercan
e499c06884 (apps/mailbox) Small tweak on resolver's comment 2021-05-19 13:38:10 +03:00
sercan
eca618c95b (FuseNavigation) Fixed: If [routerLinkActiveOptions] is "undefined" initially, router throws an error and stops working 2021-05-19 13:37:37 +03:00
sercan
8524df013a (fuse/tailwind) Fixed: Barrel exports are wrong for FuseTailwindService 2021-05-19 10:57:40 +03:00
sercan
e4df408abe (FuseNavigation) Added support for new "isActiveMatchOptions" for Basic navigation items; https://github.com/angular/angular/pull/40303
(docs) Updated FuseNavigation documentation
2021-05-18 16:09:31 +03:00
sercan
fd859a8663 (comments) Fixed: The word 'data' replaced with 'mock-api' by mistake in the past causing a lot of comments to make no sense 2021-05-18 15:18:44 +03:00
sercan
59960af7a5 (MultiLang) Added multi language support using @ngneat/transloco
(docs) Added docs about multi language
2021-05-18 15:11:57 +03:00
sercan
74c4dc2ad8 (app.module.ts) Small tweaks on comments 2021-05-18 14:34:46 +03:00
sercan
f76f38b812 (FuseVerticalNavigation) Added missing return types 2021-05-18 14:12:38 +03:00
sercan
5c40e99518 (FuseNavigation) Use the generic return type for "getComponent"
(docs) Updated FuseNavigation docs
2021-05-18 13:10:39 +03:00
sercan
c1ca701e92 (FuseNavigation) Added a generic return type for "getComponent" method on FuseNavigationService 2021-05-18 13:08:02 +03:00
sercan
e00dda98bc (core) Separated the "auth" and "icon registry" to their own modules to keep the CoreModule simple 2021-05-18 11:44:42 +03:00
sercan
9edc62f703 (eslint) Activate explicit return types on functions and methods 2021-05-18 11:42:36 +03:00
sercan
f9c8e16778 (fuse/mock-api) Added a return type to the factory function 2021-05-17 15:21:08 +03:00
sercan
4a30e3482c (eslint) Removed e2e tsconfig path as there is no default e2e solution included into Angular since v12.0.0 2021-05-16 16:22:40 +03:00
sercan
837f444cc9 (overrides/angular-material) Use @apply whenever it's possible 2021-05-16 15:55:17 +03:00
sercan
d0876eb80c (overrides) Change the text and arrow color of mat-select on focus when it's used as a prefix or suffix in mat-form-field 2021-05-16 15:54:55 +03:00
188 changed files with 5859 additions and 2345 deletions

View File

@@ -16,8 +16,7 @@
],
"parserOptions": {
"project": [
"tsconfig.json",
"e2e/tsconfig.json"
"tsconfig.json"
],
"createDefaultProgram": true
},
@@ -44,6 +43,7 @@
}
],
"@typescript-eslint/dot-notation": "off",
"@typescript-eslint/explicit-function-return-type": "error",
"@typescript-eslint/explicit-member-accessibility": [
"off",
{

View File

@@ -2,6 +2,9 @@
// @ 3rd party credits
// -----------------------------------------------------------------------------------------------------
// Flags
https://github.com/Yummygum/flagpack-core
// Icons
Material - https://material.io/tools/icons
Feather - https://feathericons.com/

View File

@@ -120,7 +120,7 @@
"src/assets"
],
"styles": [
"src/styles.scss"
"src/styles/styles.scss"
],
"scripts": []
}
@@ -133,18 +133,6 @@
"src/**/*.html"
]
}
},
"e2e": {
"builder": "@angular-devkit/build-angular:protractor",
"options": {
"protractorConfig": "e2e/protractor.conf.js",
"devServerTarget": "fuse:serve"
},
"configurations": {
"production": {
"devServerTarget": "fuse:serve:production"
}
}
}
}
}

2355
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -1,6 +1,6 @@
{
"name": "@fuse/demo",
"version": "13.0.0",
"version": "13.0.3",
"license": "https://themeforest.net/licenses/standard",
"private": true,
"scripts": {
@@ -12,17 +12,17 @@
"e2e": "ng e2e"
},
"dependencies": {
"@angular/animations": "12.0.0",
"@angular/cdk": "12.0.0",
"@angular/common": "12.0.0",
"@angular/compiler": "12.0.0",
"@angular/core": "12.0.0",
"@angular/forms": "12.0.0",
"@angular/material": "12.0.0",
"@angular/material-moment-adapter": "12.0.0",
"@angular/platform-browser": "12.0.0",
"@angular/platform-browser-dynamic": "12.0.0",
"@angular/router": "12.0.0",
"@angular/animations": "12.0.2",
"@angular/cdk": "12.0.2",
"@angular/common": "12.0.2",
"@angular/compiler": "12.0.2",
"@angular/core": "12.0.2",
"@angular/forms": "12.0.2",
"@angular/material": "12.0.2",
"@angular/material-moment-adapter": "12.0.2",
"@angular/platform-browser": "12.0.2",
"@angular/platform-browser-dynamic": "12.0.2",
"@angular/router": "12.0.2",
"@fullcalendar/angular": "4.4.5-beta",
"@fullcalendar/core": "4.4.2",
"@fullcalendar/daygrid": "4.4.2",
@@ -31,13 +31,14 @@
"@fullcalendar/moment": "4.4.2",
"@fullcalendar/rrule": "4.4.2",
"@fullcalendar/timegrid": "4.4.2",
"apexcharts": "3.26.2",
"@ngneat/transloco": "2.21.0",
"apexcharts": "3.26.3",
"crypto-js": "3.3.0",
"highlight.js": "10.7.2",
"highlight.js": "11.0.0",
"lodash-es": "4.17.21",
"moment": "2.29.1",
"ng-apexcharts": "1.5.9",
"ngx-markdown": "11.1.3",
"ng-apexcharts": "1.5.10",
"ngx-markdown": "12.0.1",
"ngx-quill": "14.0.0",
"perfect-scrollbar": "1.5.1",
"quill": "1.3.7",
@@ -48,44 +49,42 @@
"zone.js": "0.11.4"
},
"devDependencies": {
"@angular-devkit/build-angular": "12.0.0",
"@angular-eslint/builder": "12.0.0",
"@angular-eslint/eslint-plugin": "12.0.0",
"@angular-eslint/eslint-plugin-template": "12.0.0",
"@angular-eslint/schematics": "12.0.0",
"@angular-eslint/template-parser": "12.0.0",
"@angular/cli": "12.0.0",
"@angular/compiler-cli": "12.0.0",
"@angular/language-service": "12.0.0",
"@tailwindcss/aspect-ratio": "0.2.0",
"@tailwindcss/line-clamp": "0.2.0",
"@tailwindcss/typography": "0.4.0",
"@angular-devkit/build-angular": "12.0.2",
"@angular-eslint/builder": "12.1.0",
"@angular-eslint/eslint-plugin": "12.1.0",
"@angular-eslint/eslint-plugin-template": "12.1.0",
"@angular-eslint/schematics": "12.1.0",
"@angular-eslint/template-parser": "12.1.0",
"@angular/cli": "12.0.2",
"@angular/compiler-cli": "12.0.2",
"@angular/language-service": "12.0.2",
"@tailwindcss/aspect-ratio": "0.2.1",
"@tailwindcss/line-clamp": "0.2.1",
"@tailwindcss/typography": "0.4.1",
"@types/chroma-js": "2.1.3",
"@types/crypto-js": "3.1.47",
"@types/highlight.js": "10.1.0",
"@types/jasmine": "3.6.11",
"@types/lodash": "4.14.169",
"@types/lodash": "4.14.170",
"@types/lodash-es": "4.17.4",
"@types/node": "12.20.13",
"@typescript-eslint/eslint-plugin": "4.23.0",
"@typescript-eslint/parser": "4.23.0",
"autoprefixer": "10.2.5",
"chroma-js": "2.1.1",
"eslint": "7.26.0",
"eslint-plugin-import": "2.23.0",
"eslint-plugin-jsdoc": "34.2.2",
"@types/node": "12.20.14",
"@typescript-eslint/eslint-plugin": "4.26.0",
"@typescript-eslint/parser": "4.26.0",
"autoprefixer": "10.2.6",
"chroma-js": "2.1.2",
"eslint": "7.27.0",
"eslint-plugin-import": "2.23.4",
"eslint-plugin-jsdoc": "35.1.2",
"eslint-plugin-prefer-arrow": "1.2.3",
"jasmine-core": "3.7.1",
"jasmine-spec-reporter": "5.0.2",
"karma": "6.3.2",
"karma": "6.3.3",
"karma-chrome-launcher": "3.1.0",
"karma-coverage": "2.0.3",
"karma-jasmine": "4.0.1",
"karma-jasmine-html-reporter": "1.6.0",
"lodash": "4.17.21",
"postcss": "8.2.15",
"protractor": "7.0.0",
"tailwindcss": "2.1.2",
"postcss": "8.3.0",
"tailwindcss": "2.1.4",
"typescript": "4.2.4"
}
}

View File

@@ -1 +1 @@
export * from './public-api';
export * from '@fuse/animations/public-api';

View File

@@ -1,8 +1,8 @@
import { expandCollapse } from './expand-collapse';
import { fadeIn, fadeInBottom, fadeInLeft, fadeInRight, fadeInTop, fadeOut, fadeOutBottom, fadeOutLeft, fadeOutRight, fadeOutTop } from './fade';
import { shake } from './shake';
import { slideInBottom, slideInLeft, slideInRight, slideInTop, slideOutBottom, slideOutLeft, slideOutRight, slideOutTop } from './slide';
import { zoomIn, zoomOut } from './zoom';
import { expandCollapse } from '@fuse/animations/expand-collapse';
import { fadeIn, fadeInBottom, fadeInLeft, fadeInRight, fadeInTop, fadeOut, fadeOutBottom, fadeOutLeft, fadeOutRight, fadeOutTop } from '@fuse/animations/fade';
import { shake } from '@fuse/animations/shake';
import { slideInBottom, slideInLeft, slideInRight, slideInTop, slideOutBottom, slideOutLeft, slideOutRight, slideOutTop } from '@fuse/animations/slide';
import { zoomIn, zoomOut } from '@fuse/animations/zoom';
export const fuseAnimations = [
expandCollapse,

View File

@@ -61,9 +61,9 @@ export class FuseDateRangeComponent implements ControlValueAccessor, OnInit, OnD
private _viewContainerRef: ViewContainerRef
)
{
this._onChange = () => {
this._onChange = (): void => {
};
this._onTouched = () => {
this._onTouched = (): void => {
};
this.dateFormat = 'DD/MM/YYYY';
this.timeFormat = '12';
@@ -361,7 +361,7 @@ export class FuseDateRangeComponent implements ControlValueAccessor, OnInit, OnD
this._unsubscribeAll.complete();
// @ TODO: Workaround until "angular/issues/20007" resolved
this.writeValue = () => {
this.writeValue = (): void => {
};
}

View File

@@ -1,5 +1,5 @@
import { Injectable } from '@angular/core';
import * as hljs from 'highlight.js';
import hljs from 'highlight.js';
@Injectable({
providedIn: 'root'

View File

@@ -1 +1 @@
export * from '@fuse/components/card/public-api';
export * from '@fuse/components/masonry/public-api';

View File

@@ -11,7 +11,7 @@
[ngClass]="{'fuse-horizontal-navigation-item-active-forced': item.active}"
[routerLink]="[item.link]"
[routerLinkActive]="'fuse-horizontal-navigation-item-active'"
[routerLinkActiveOptions]="{exact: item.exactMatch || false}">
[routerLinkActiveOptions]="isActiveMatchOptions">
<ng-container *ngTemplateOutlet="itemTemplate"></ng-container>
</div>
@@ -39,7 +39,7 @@
[ngClass]="{'fuse-horizontal-navigation-item-active-forced': item.active}"
[routerLink]="[item.link]"
[routerLinkActive]="'fuse-horizontal-navigation-item-active'"
[routerLinkActiveOptions]="{exact: item.exactMatch || false}"
[routerLinkActiveOptions]="isActiveMatchOptions"
(click)="item.function(item)">
<ng-container *ngTemplateOutlet="itemTemplate"></ng-container>
</div>

View File

@@ -1,9 +1,11 @@
import { ChangeDetectionStrategy, ChangeDetectorRef, Component, Input, OnDestroy, OnInit } from '@angular/core';
import { IsActiveMatchOptions } from '@angular/router';
import { Subject } from 'rxjs';
import { takeUntil } from 'rxjs/operators';
import { FuseHorizontalNavigationComponent } from '@fuse/components/navigation/horizontal/horizontal.component';
import { FuseNavigationService } from '@fuse/components/navigation/navigation.service';
import { FuseNavigationItem } from '@fuse/components/navigation/navigation.types';
import { FuseUtilsService } from '@fuse/services/utils/utils.service';
@Component({
selector : 'fuse-horizontal-navigation-basic-item',
@@ -16,6 +18,7 @@ export class FuseHorizontalNavigationBasicItemComponent implements OnInit, OnDes
@Input() item: FuseNavigationItem;
@Input() name: string;
isActiveMatchOptions: IsActiveMatchOptions;
private _fuseHorizontalNavigationComponent: FuseHorizontalNavigationComponent;
private _unsubscribeAll: Subject<any> = new Subject<any>();
@@ -24,9 +27,15 @@ export class FuseHorizontalNavigationBasicItemComponent implements OnInit, OnDes
*/
constructor(
private _changeDetectorRef: ChangeDetectorRef,
private _fuseNavigationService: FuseNavigationService
private _fuseNavigationService: FuseNavigationService,
private _fuseUtilsService: FuseUtilsService
)
{
// Set the equivalent of {exact: false} as default for active match options.
// We are not assigning the item.isActiveMatchOptions directly to the
// [routerLinkActiveOptions] because if it's "undefined" initially, the router
// will throw an error and stop working.
this.isActiveMatchOptions = this._fuseUtilsService.subsetMatchOptions;
}
// -----------------------------------------------------------------------------------------------------
@@ -38,9 +47,20 @@ export class FuseHorizontalNavigationBasicItemComponent implements OnInit, OnDes
*/
ngOnInit(): void
{
// Set the "isActiveMatchOptions" either from item's
// "isActiveMatchOptions" or the equivalent form of
// item's "exactMatch" option
this.isActiveMatchOptions =
this.item.isActiveMatchOptions ?? this.item.exactMatch
? this._fuseUtilsService.exactMatchOptions
: this._fuseUtilsService.subsetMatchOptions;
// Get the parent navigation component
this._fuseHorizontalNavigationComponent = this._fuseNavigationService.getComponent(this.name);
// Mark for check
this._changeDetectorRef.markForCheck();
// Subscribe to onRefreshed on the navigation component
this._fuseHorizontalNavigationComponent.onRefreshed.pipe(
takeUntil(this._unsubscribeAll)

View File

@@ -46,7 +46,7 @@ export class FuseNavigationService
*
* @param name
*/
getComponent(name: string): any
getComponent<T>(name: string): T
{
return this._componentRegistry.get(name);
}

View File

@@ -1,3 +1,5 @@
import { IsActiveMatchOptions } from '@angular/router';
export interface FuseNavigationItem
{
id?: string;
@@ -16,6 +18,7 @@ export interface FuseNavigationItem
link?: string;
externalLink?: boolean;
exactMatch?: boolean;
isActiveMatchOptions?: IsActiveMatchOptions;
function?: (item: FuseNavigationItem) => void;
classes?: {
title?: string;

View File

@@ -11,7 +11,7 @@
[ngClass]="{'fuse-vertical-navigation-item-active-forced': item.active}"
[routerLink]="[item.link]"
[routerLinkActive]="'fuse-vertical-navigation-item-active'"
[routerLinkActiveOptions]="{exact: item.exactMatch || false}">
[routerLinkActiveOptions]="isActiveMatchOptions">
<ng-container *ngTemplateOutlet="itemTemplate"></ng-container>
</a>
@@ -39,7 +39,7 @@
[ngClass]="{'fuse-vertical-navigation-item-active-forced': item.active}"
[routerLink]="[item.link]"
[routerLinkActive]="'fuse-vertical-navigation-item-active'"
[routerLinkActiveOptions]="{exact: item.exactMatch || false}"
[routerLinkActiveOptions]="isActiveMatchOptions"
(click)="item.function(item)">
<ng-container *ngTemplateOutlet="itemTemplate"></ng-container>
</a>

View File

@@ -1,4 +1,5 @@
import { ChangeDetectionStrategy, ChangeDetectorRef, Component, Input, OnDestroy, OnInit } from '@angular/core';
import { IsActiveMatchOptions } from '@angular/router';
import { Subject } from 'rxjs';
import { takeUntil } from 'rxjs/operators';
import { FuseVerticalNavigationComponent } from '@fuse/components/navigation/vertical/vertical.component';
@@ -17,6 +18,7 @@ export class FuseVerticalNavigationBasicItemComponent implements OnInit, OnDestr
@Input() item: FuseNavigationItem;
@Input() name: string;
isActiveMatchOptions: IsActiveMatchOptions;
private _fuseVerticalNavigationComponent: FuseVerticalNavigationComponent;
private _unsubscribeAll: Subject<any> = new Subject<any>();
@@ -29,6 +31,11 @@ export class FuseVerticalNavigationBasicItemComponent implements OnInit, OnDestr
private _fuseUtilsService: FuseUtilsService
)
{
// Set the equivalent of {exact: false} as default for active match options.
// We are not assigning the item.isActiveMatchOptions directly to the
// [routerLinkActiveOptions] because if it's "undefined" initially, the router
// will throw an error and stop working.
this.isActiveMatchOptions = this._fuseUtilsService.subsetMatchOptions;
}
// -----------------------------------------------------------------------------------------------------
@@ -40,9 +47,20 @@ export class FuseVerticalNavigationBasicItemComponent implements OnInit, OnDestr
*/
ngOnInit(): void
{
// Set the "isActiveMatchOptions" either from item's
// "isActiveMatchOptions" or the equivalent form of
// item's "exactMatch" option
this.isActiveMatchOptions =
this.item.isActiveMatchOptions ?? this.item.exactMatch
? this._fuseUtilsService.exactMatchOptions
: this._fuseUtilsService.subsetMatchOptions;
// Get the parent navigation component
this._fuseVerticalNavigationComponent = this._fuseNavigationService.getComponent(this.name);
// Mark for check
this._changeDetectorRef.markForCheck();
// Subscribe to onRefreshed on the navigation component
this._fuseVerticalNavigationComponent.onRefreshed.pipe(
takeUntil(this._unsubscribeAll)

View File

@@ -73,10 +73,10 @@ export class FuseVerticalNavigationComponent implements OnChanges, OnInit, After
private _fuseUtilsService: FuseUtilsService
)
{
this._handleAsideOverlayClick = () => {
this._handleAsideOverlayClick = (): void => {
this.closeAside();
};
this._handleOverlayClick = () => {
this._handleOverlayClick = (): void => {
this.close();
};
}

View File

@@ -1,114 +0,0 @@
import { ChangeDetectorRef, Directive, ElementRef, HostBinding, HostListener, Input, NgZone, OnChanges, OnDestroy, OnInit, SimpleChanges } from '@angular/core';
import { Subject } from 'rxjs';
@Directive({
selector: 'textarea[fuseAutogrow]',
exportAs: 'fuseAutogrow'
})
export class FuseAutogrowDirective implements OnChanges, OnInit, OnDestroy
{
// eslint-disable-next-line @angular-eslint/no-input-rename
@Input('fuseAutogrowVerticalPadding') padding: number = 8;
@HostBinding('rows') private _rows: number = 1;
private _height: string = 'auto';
private _unsubscribeAll: Subject<any> = new Subject<any>();
/**
* Constructor
*/
constructor(
private _elementRef: ElementRef,
private _changeDetectorRef: ChangeDetectorRef,
private _ngZone: NgZone
)
{
}
// -----------------------------------------------------------------------------------------------------
// @ Accessors
// -----------------------------------------------------------------------------------------------------
/**
* Host binding for component inline styles
*/
@HostBinding('style') get styleList(): any
{
return {
'height' : this._height,
'overflow': 'hidden',
'resize' : 'none'
};
}
// -----------------------------------------------------------------------------------------------------
// @ Decorated methods
// -----------------------------------------------------------------------------------------------------
/**
* Resize on 'input' and 'ngModelChange' events
*
* @private
*/
@HostListener('input')
@HostListener('ngModelChange')
private _resize(): void
{
// This doesn't need to trigger Angular's change detection by itself
this._ngZone.runOutsideAngular(() => {
setTimeout(() => {
// Set the height to 'auto' so we can correctly read the scrollHeight
this._height = 'auto';
// Detect the changes so the height is applied
this._changeDetectorRef.detectChanges();
// Get the scrollHeight and subtract the vertical padding
this._height = `${this._elementRef.nativeElement.scrollHeight - this.padding}px`;
// Detect the changes one more time to apply the final height
this._changeDetectorRef.detectChanges();
});
});
}
// -----------------------------------------------------------------------------------------------------
// @ Lifecycle hooks
// -----------------------------------------------------------------------------------------------------
/**
* On changes
*
* @param changes
*/
ngOnChanges(changes: SimpleChanges): void
{
// Padding
if ( 'fuseAutogrowVerticalPadding' in changes )
{
// Resize
this._resize();
}
}
/**
* On init
*/
ngOnInit(): void
{
// Resize for the first time
this._resize();
}
/**
* On destroy
*/
ngOnDestroy(): void
{
// Unsubscribe from all subscriptions
this._unsubscribeAll.next();
this._unsubscribeAll.complete();
}
}

View File

@@ -1,14 +0,0 @@
import { NgModule } from '@angular/core';
import { FuseAutogrowDirective } from '@fuse/directives/autogrow/autogrow.directive';
@NgModule({
declarations: [
FuseAutogrowDirective
],
exports : [
FuseAutogrowDirective
]
})
export class FuseAutogrowModule
{
}

View File

@@ -1 +0,0 @@
export * from '@fuse/directives/autogrow/public-api';

View File

@@ -1,2 +0,0 @@
export * from '@fuse/directives/autogrow/autogrow.directive';
export * from '@fuse/directives/autogrow/autogrow.module';

View File

@@ -389,7 +389,7 @@ export class FuseScrollbarDirective implements OnChanges, OnInit, OnDestroy
const cosParameter = (oldValue - value) / 2;
const step = (newTimestamp: number) => {
const step = (newTimestamp: number): void => {
scrollCount += Math.PI / (speed / (newTimestamp - oldTimestamp));
newValue = Math.round(value + cosParameter + cosParameter * Math.cos(scrollCount));

View File

@@ -51,7 +51,7 @@ export class FuseMockApiInterceptor implements HttpInterceptor
delay(handler.delay ?? this._defaultDelay ?? 0),
switchMap((response) => {
// If there is no response mock-api,
// If there is no response data,
// throw an error response
if ( !response )
{
@@ -64,7 +64,7 @@ export class FuseMockApiInterceptor implements HttpInterceptor
return throwError(response);
}
// Parse the response mock-api
// Parse the response data
const data = {
status: response[0],
body : response[1]

View File

@@ -29,7 +29,7 @@ export class FuseMockApiModule
{
provide : APP_INITIALIZER,
deps : [...mockApiServices],
useFactory: () => () => null,
useFactory: () => (): any => null,
multi : true
},
{

View File

@@ -1 +1 @@
export * from '@fuse/services/media-watcher/public-api';
export * from '@fuse/services/tailwind/public-api';

View File

@@ -1,2 +1,2 @@
export * from '@fuse/services/media-watcher/media-watcher.module';
export * from '@fuse/services/media-watcher/media-watcher.service';
export * from '@fuse/services/tailwind/tailwind.module';
export * from '@fuse/services/tailwind/tailwind.service';

View File

@@ -1 +1 @@
export * from '@fuse/services/config/public-api';
export * from '@fuse/services/utils/public-api';

View File

@@ -1,4 +1,5 @@
import { Injectable } from '@angular/core';
import { IsActiveMatchOptions } from '@angular/router';
@Injectable({
providedIn: 'root'
@@ -12,6 +13,36 @@ export class FuseUtilsService
{
}
// -----------------------------------------------------------------------------------------------------
// @ Accessors
// -----------------------------------------------------------------------------------------------------
/**
* Get the equivalent "IsActiveMatchOptions" options for "exact = true".
*/
get exactMatchOptions(): IsActiveMatchOptions
{
return {
paths : 'exact',
fragment : 'ignored',
matrixParams: 'ignored',
queryParams : 'exact'
};
}
/**
* Get the equivalent "IsActiveMatchOptions" options for "exact = false".
*/
get subsetMatchOptions(): IsActiveMatchOptions
{
return {
paths : 'subset',
fragment : 'ignored',
matrixParams: 'ignored',
queryParams : 'subset'
};
}
// -----------------------------------------------------------------------------------------------------
// @ Public methods
// -----------------------------------------------------------------------------------------------------

View File

@@ -178,11 +178,7 @@
/* Add hover and focus style on all buttons */
.mat-button-focus-overlay {
@apply bg-gray-400 bg-opacity-20 #{'!important'};
.dark & {
background-color: rgba(0, 0, 0, 0.05) !important;
}
@apply bg-gray-400 bg-opacity-20 dark:bg-black dark:bg-opacity-5 #{'!important'};
}
/* On palette colored buttons, use a darker color */
@@ -253,11 +249,7 @@
/* Add hover and focus styles */
.mat-button-focus-overlay {
@apply bg-gray-400 bg-opacity-20 #{'!important'};
.dark & {
background-color: rgba(0, 0, 0, 0.05) !important;
}
@apply bg-gray-400 bg-opacity-20 dark:bg-black dark:bg-opacity-5 #{'!important'};
}
/* On primary colored buttons, use the primary color as focus overlay */
@@ -330,19 +322,11 @@
/* Border color */
&:not(.mat-button-disabled) {
@apply border-gray-300 #{'!important'};
.dark & {
@apply border-gray-500 #{'!important'};
}
@apply border-gray-300 dark:border-gray-500 #{'!important'};
}
&.mat-button-disabled {
@apply border-gray-200 #{'!important'};
.dark & {
@apply border-gray-600 #{'!important'};
}
@apply border-gray-200 dark:border-gray-600 #{'!important'};
}
}
@@ -426,6 +410,13 @@
font-weight: 500 !important;
}
/* ----------------------------------------------------------------------------------------------------- */
/* @ Dialog
/* ----------------------------------------------------------------------------------------------------- */
.mat-dialog-container {
border-radius: 16px !important;
}
/* ----------------------------------------------------------------------------------------------------- */
/* @ Drawer
/* ----------------------------------------------------------------------------------------------------- */
@@ -542,13 +533,7 @@
border-radius: 6px;
padding: 0 16px;
border-width: 1px;
background-color: white;
@apply border-gray-300 shadow-sm #{'!important'};
.dark & {
background-color: rgba(0, 0, 0, 0.05) !important;
@apply border-gray-500 #{'!important'};
}
@apply shadow-sm bg-white border-gray-300 dark:bg-black dark:bg-opacity-5 dark:border-gray-500 #{'!important'};
.mat-form-field-prefix {
@@ -633,12 +618,28 @@
@apply icon-size-6;
}
/* Make mat-select usable as */
/* prefix and suffix */
/* Make mat-select usable as prefix and suffix */
.mat-select {
display: flex;
align-items: center;
&:focus {
.mat-select-trigger {
.mat-select-value {
@apply text-primary #{'!important'};
}
.mat-select-arrow-wrapper {
.mat-select-arrow {
border-top-color: var(--fuse-primary) !important;
}
}
}
}
.mat-select-trigger {
display: flex;
align-items: center;
@@ -663,6 +664,7 @@
.mat-select-arrow {
min-height: 0;
@apply text-gray-500 dark:text-gray-400 #{'!important'};
}
}
}
@@ -688,8 +690,8 @@
align-self: stretch;
min-height: 36px;
height: auto;
margin: 10px 0;
padding: 4px 6px 4px 0 !important;
margin: 14px 0;
padding: 0 6px 0 0;
transform: none;
}
@@ -1032,11 +1034,7 @@
.mat-form-field-prefix,
.mat-form-field-suffix {
@apply border-gray-300 bg-default #{'!important'};
.dark & {
@apply border-gray-500 #{'!important'};
}
@apply bg-default border-gray-300 dark:border-gray-500 #{'!important'};
}
}
}

View File

@@ -1,21 +1,24 @@
@use '~@angular/material' as mat;
@use "sass:map";
/** Include the core Angular Material styles */
/* Include the core Angular Material styles */
@include mat.core();
/** Configure the Angular Material typography */
@include mat.all-component-typographies(
mat.define-typography-config(
$font-family: theme('fontFamily.sans'),
$title: mat.define-typography-level(1.25rem, 2rem, 600),
$body-2: mat.define-typography-level(0.875rem, 1.5rem, 600),
$button: mat.define-typography-level(0.875rem, 0.875rem, 500),
$input: mat.define-typography-level(0.875rem, 1.2857142857, 400) // line-height: 20px
)
);
/* Create a base theme without color.
This will globally set the density and typography for all future color themes. */
@include mat.all-component-themes((
color: null,
density: -2,
typography: mat.define-typography-config(
$font-family: theme('fontFamily.sans'),
$title: mat.define-typography-level(1.25rem, 2rem, 600),
$body-2: mat.define-typography-level(0.875rem, 1.5rem, 600),
$button: mat.define-typography-level(0.875rem, 0.875rem, 500),
$input: mat.define-typography-level(0.875rem, 1.2857142857, 400) /* line-height: 20px */
)
));
/** Prepare the Background and Foreground maps */
/* Prepare the Background and Foreground maps */
$background-light: (
status-bar: #CBD5E1, /* blueGray.300 */
app-bar: #FFFFFF,
@@ -90,7 +93,7 @@ $foreground-dark: (
slider-off-active: #94A3B8 /* blueGray.400 */
);
/** Generate Primary, Accent and Warn palettes */
/* Generate Primary, Accent and Warn palettes */
$palettes: ();
@each $name in (primary, accent, warn) {
$palettes: map.merge($palettes, (#{$name}: (
@@ -126,7 +129,7 @@ $palettes: ();
)));
}
/** Generate Angular Material themes. Since we are using CSS Custom Properties,
/* Generate Angular Material themes. Since we are using CSS Custom Properties,
we don't have to generate a separate Angular Material theme for each color
set. We can just create one light and one dark theme and then switch the
CSS Custom Properties to dynamically switch the colors. */
@@ -144,11 +147,11 @@ body .light {
is-dark: map.get(map.get($base-light-theme, color), is-dark),
foreground: $foreground-light,
background: $background-light
),
density: -2
)
);
@include mat.all-component-themes($light-theme);
/* Use all-component-colors to only generate the colors */
@include mat.all-component-colors($light-theme);
}
body.dark,
@@ -165,9 +168,9 @@ body .dark {
is-dark: map.get(map.get($base-dark-theme, color), is-dark),
foreground: $foreground-dark,
background: $background-dark
),
density: -2
)
);
/* Use all-component-colors to only generate the colors */
@include mat.all-component-colors($dark-theme);
}

View File

@@ -1 +1 @@
export * from './public-api';
export * from '@fuse/validators/public-api';

View File

@@ -1 +1 @@
export * from './validators';
export * from '@fuse/validators/validators';

View File

@@ -1,3 +1,3 @@
import { Version } from '@fuse/version/version';
export const FUSE_VERSION = new Version('13.0.0').full;
export const FUSE_VERSION = new Version('13.0.3').full;

View File

@@ -27,18 +27,18 @@ const routerConfig: ExtraOptions = {
BrowserAnimationsModule,
RouterModule.forRoot(appRoutes, routerConfig),
// Fuse & Fuse Mock API
// Fuse, FuseConfig & FuseMockAPI
FuseModule,
FuseConfigModule.forRoot(appConfig),
FuseMockApiModule.forRoot(mockApiServices),
// Core
// Core module of your application
CoreModule,
// Layout
// Layout module of your application
LayoutModule,
// 3rd party modules
// 3rd party modules that require global configuration via forRoot
MarkdownModule.forRoot({})
],
bootstrap : [

View File

@@ -6,6 +6,7 @@ import { InitialDataResolver } from 'app/app.resolvers';
// @formatter:off
/* eslint-disable max-len */
/* eslint-disable @typescript-eslint/explicit-function-return-type */
export const appRoutes: Route[] = [
// Redirect empty path to '/dashboards/project'
@@ -91,12 +92,16 @@ export const appRoutes: Route[] = [
{path: 'help-center', loadChildren: () => import('app/modules/admin/apps/help-center/help-center.module').then(m => m.HelpCenterModule)},
{path: 'mailbox', loadChildren: () => import('app/modules/admin/apps/mailbox/mailbox.module').then(m => m.MailboxModule)},
{path: 'notes', loadChildren: () => import('app/modules/admin/apps/notes/notes.module').then(m => m.NotesModule)},
{path: 'scrumboard', loadChildren: () => import('app/modules/admin/apps/scrumboard/scrumboard.module').then(m => m.ScrumboardModule)},
{path: 'tasks', loadChildren: () => import('app/modules/admin/apps/tasks/tasks.module').then(m => m.TasksModule)},
]},
// Pages
{path: 'pages', children: [
// Activities
{path: 'activities', loadChildren: () => import('app/modules/admin/pages/activities/activities.module').then(m => m.ActivitiesModule)},
// Authentication
{path: 'authentication', loadChildren: () => import('app/modules/admin/pages/authentication/authentication.module').then(m => m.AuthenticationModule)},

View File

@@ -0,0 +1,21 @@
import { NgModule } from '@angular/core';
import { HTTP_INTERCEPTORS, HttpClientModule } from '@angular/common/http';
import { AuthService } from 'app/core/auth/auth.service';
import { AuthInterceptor } from 'app/core/auth/auth.interceptor';
@NgModule({
imports : [
HttpClientModule
],
providers: [
AuthService,
{
provide : HTTP_INTERCEPTORS,
useClass: AuthInterceptor,
multi : true
}
]
})
export class AuthModule
{
}

View File

@@ -1,21 +1,13 @@
import { NgModule, Optional, SkipSelf } from '@angular/core';
import { HTTP_INTERCEPTORS, HttpClientModule } from '@angular/common/http';
import { DomSanitizer } from '@angular/platform-browser';
import { MatIconRegistry } from '@angular/material/icon';
import { AuthService } from 'app/core/auth/auth.service';
import { AuthInterceptor } from 'app/core/auth/auth.interceptor';
import { AuthModule } from 'app/core/auth/auth.module';
import { IconsModule } from 'app/core/icons/icons.module';
import { TranslocoCoreModule } from 'app/core/transloco/transloco.module';
@NgModule({
imports : [
HttpClientModule
],
providers: [
AuthService,
{
provide : HTTP_INTERCEPTORS,
useClass: AuthInterceptor,
multi : true
}
imports: [
AuthModule,
IconsModule,
TranslocoCoreModule
]
})
export class CoreModule
@@ -24,8 +16,6 @@ export class CoreModule
* Constructor
*/
constructor(
private _domSanitizer: DomSanitizer,
private _matIconRegistry: MatIconRegistry,
@Optional() @SkipSelf() parentModule?: CoreModule
)
{
@@ -34,14 +24,5 @@ export class CoreModule
{
throw new Error('CoreModule has already been loaded. Import this module in the AppModule only.');
}
// Register icon sets
this._matIconRegistry.addSvgIconSet(this._domSanitizer.bypassSecurityTrustResourceUrl('assets/icons/material-twotone.svg'));
this._matIconRegistry.addSvgIconSetInNamespace('mat_outline', this._domSanitizer.bypassSecurityTrustResourceUrl('assets/icons/material-outline.svg'));
this._matIconRegistry.addSvgIconSetInNamespace('mat_solid', this._domSanitizer.bypassSecurityTrustResourceUrl('assets/icons/material-solid.svg'));
this._matIconRegistry.addSvgIconSetInNamespace('iconsmind', this._domSanitizer.bypassSecurityTrustResourceUrl('assets/icons/iconsmind.svg'));
this._matIconRegistry.addSvgIconSetInNamespace('feather', this._domSanitizer.bypassSecurityTrustResourceUrl('assets/icons/feather.svg'));
this._matIconRegistry.addSvgIconSetInNamespace('heroicons_outline', this._domSanitizer.bypassSecurityTrustResourceUrl('assets/icons/heroicons-outline.svg'));
this._matIconRegistry.addSvgIconSetInNamespace('heroicons_solid', this._domSanitizer.bypassSecurityTrustResourceUrl('assets/icons/heroicons-solid.svg'));
}
}

View File

@@ -0,0 +1,25 @@
import { NgModule } from '@angular/core';
import { DomSanitizer } from '@angular/platform-browser';
import { MatIconRegistry } from '@angular/material/icon';
@NgModule()
export class IconsModule
{
/**
* Constructor
*/
constructor(
private _domSanitizer: DomSanitizer,
private _matIconRegistry: MatIconRegistry
)
{
// Register icon sets
this._matIconRegistry.addSvgIconSet(this._domSanitizer.bypassSecurityTrustResourceUrl('assets/icons/material-twotone.svg'));
this._matIconRegistry.addSvgIconSetInNamespace('mat_outline', this._domSanitizer.bypassSecurityTrustResourceUrl('assets/icons/material-outline.svg'));
this._matIconRegistry.addSvgIconSetInNamespace('mat_solid', this._domSanitizer.bypassSecurityTrustResourceUrl('assets/icons/material-solid.svg'));
this._matIconRegistry.addSvgIconSetInNamespace('iconsmind', this._domSanitizer.bypassSecurityTrustResourceUrl('assets/icons/iconsmind.svg'));
this._matIconRegistry.addSvgIconSetInNamespace('feather', this._domSanitizer.bypassSecurityTrustResourceUrl('assets/icons/feather.svg'));
this._matIconRegistry.addSvgIconSetInNamespace('heroicons_outline', this._domSanitizer.bypassSecurityTrustResourceUrl('assets/icons/heroicons-outline.svg'));
this._matIconRegistry.addSvgIconSetInNamespace('heroicons_solid', this._domSanitizer.bypassSecurityTrustResourceUrl('assets/icons/heroicons-solid.svg'));
}
}

View File

@@ -0,0 +1,32 @@
import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { Observable } from 'rxjs';
import { Translation, TranslocoLoader } from '@ngneat/transloco';
@Injectable({
providedIn: 'root'
})
export class TranslocoHttpLoader implements TranslocoLoader
{
/**
* Constructor
*/
constructor(
private _httpClient: HttpClient)
{
}
// -----------------------------------------------------------------------------------------------------
// @ Public methods
// -----------------------------------------------------------------------------------------------------
/**
* Get translation
*
* @param lang
*/
getTranslation(lang: string): Observable<Translation>
{
return this._httpClient.get<Translation>(`/assets/i18n/${lang}.json`);
}
}

View File

@@ -0,0 +1,50 @@
import { Translation, TRANSLOCO_CONFIG, TRANSLOCO_LOADER, translocoConfig, TranslocoModule, TranslocoService } from '@ngneat/transloco';
import { APP_INITIALIZER, NgModule } from '@angular/core';
import { environment } from 'environments/environment';
import { TranslocoHttpLoader } from 'app/core/transloco/transloco.http-loader';
@NgModule({
exports : [
TranslocoModule
],
providers: [
{
// Provide the default Transloco configuration
provide : TRANSLOCO_CONFIG,
useValue: translocoConfig({
availableLangs : [
{
id : 'en',
label: 'English'
},
{
id : 'tr',
label: 'Turkish'
}
],
defaultLang : 'en',
reRenderOnLangChange: true,
prodMode : environment.production
})
},
{
// Provide the default Transloco loader
provide : TRANSLOCO_LOADER,
useClass: TranslocoHttpLoader
},
{
// Preload the default language before the app starts to prevent empty/jumping content
provide : APP_INITIALIZER,
deps : [TranslocoService],
useFactory: (translocoService: TranslocoService): any => (): Promise<Translation> => {
const defaultLang = translocoService.getDefaultLang();
translocoService.setActiveLang(defaultLang);
return translocoService.load(defaultLang).toPromise();
},
multi : true
}
]
})
export class TranslocoCoreModule
{
}

View File

@@ -0,0 +1,35 @@
<!-- Button -->
<button
mat-icon-button
[matMenuTriggerFor]="languages">
<ng-container *ngTemplateOutlet="flagImage; context: {$implicit: activeLang}"></ng-container>
</button>
<!-- Language menu -->
<mat-menu
[xPosition]="'before'"
#languages="matMenu">
<ng-container *ngFor="let lang of availableLangs; trackBy: trackByFn">
<button
mat-menu-item
(click)="setActiveLang(lang.id)">
<span class="flex items-center">
<ng-container *ngTemplateOutlet="flagImage; context: {$implicit: lang.id}"></ng-container>
<span class="ml-3">{{lang.label}}</span>
</span>
</button>
</ng-container>
</mat-menu>
<!-- Flag image template -->
<ng-template
let-lang
#flagImage>
<span class="relative w-6 shadow rounded-sm overflow-hidden">
<span class="absolute inset-0 ring-1 ring-inset ring-black ring-opacity-10"></span>
<img
class="w-full"
[src]="'assets/images/flags/' + flagCodes[lang].toUpperCase() + '.svg'"
[alt]="'Flag image for ' + lang">
</span>
</ng-template>

View File

@@ -0,0 +1,153 @@
import { ChangeDetectionStrategy, ChangeDetectorRef, Component, OnDestroy, OnInit, ViewEncapsulation } from '@angular/core';
import { take } from 'rxjs/operators';
import { AvailableLangs, TranslocoService } from '@ngneat/transloco';
import { FuseNavigationService, FuseVerticalNavigationComponent } from '@fuse/components/navigation';
@Component({
selector : 'language',
templateUrl : './language.component.html',
encapsulation : ViewEncapsulation.None,
changeDetection: ChangeDetectionStrategy.OnPush,
exportAs : 'language'
})
export class LanguageComponent implements OnInit, OnDestroy
{
availableLangs: AvailableLangs;
activeLang: string;
flagCodes: any;
/**
* Constructor
*/
constructor(
private _changeDetectorRef: ChangeDetectorRef,
private _fuseNavigationService: FuseNavigationService,
private _translocoService: TranslocoService
)
{
}
// -----------------------------------------------------------------------------------------------------
// @ Lifecycle hooks
// -----------------------------------------------------------------------------------------------------
/**
* On init
*/
ngOnInit(): void
{
// Get the available languages from transloco
this.availableLangs = this._translocoService.getAvailableLangs();
// Subscribe to language changes
this._translocoService.langChanges$.subscribe((activeLang) => {
// Get the active lang
this.activeLang = activeLang;
// Update the navigation
this._updateNavigation(activeLang);
});
// Set the country iso codes for languages for flags
this.flagCodes = {
'en': 'us',
'tr': 'tr'
};
}
/**
* On destroy
*/
ngOnDestroy(): void
{
}
// -----------------------------------------------------------------------------------------------------
// @ Public methods
// -----------------------------------------------------------------------------------------------------
/**
* Set the active lang
*
* @param lang
*/
setActiveLang(lang: string): void
{
// Set the active lang
this._translocoService.setActiveLang(lang);
}
/**
* Track by function for ngFor loops
*
* @param index
* @param item
*/
trackByFn(index: number, item: any): any
{
return item.id || index;
}
// -----------------------------------------------------------------------------------------------------
// @ Private methods
// -----------------------------------------------------------------------------------------------------
/**
* Update the navigation
*
* @param lang
* @private
*/
private _updateNavigation(lang: string): void
{
// For the demonstration purposes, we will only update the Dashboard names
// from the navigation but you can do a full swap and change the entire
// navigation data.
//
// You can import the data from a file or request it from your backend,
// it's up to you.
// Get the component -> navigation data -> item
const navComponent = this._fuseNavigationService.getComponent<FuseVerticalNavigationComponent>('mainNavigation');
// Return if the navigation component does not exist
if ( !navComponent )
{
return null;
}
// Get the flat navigation data
const navigation = navComponent.navigation;
// Get the Project dashboard item and update its title
const projectDashboardItem = this._fuseNavigationService.getItem('dashboards.project', navigation);
if ( projectDashboardItem )
{
this._translocoService.selectTranslate('Project').pipe(take(1))
.subscribe((translation) => {
// Set the title
projectDashboardItem.title = translation;
// Refresh the navigation component
navComponent.refresh();
});
}
// Get the Analytics dashboard item and update its title
const analyticsDashboardItem = this._fuseNavigationService.getItem('dashboards.analytics', navigation);
if ( analyticsDashboardItem )
{
this._translocoService.selectTranslate('Analytics').pipe(take(1))
.subscribe((translation) => {
// Set the title
analyticsDashboardItem.title = translation;
// Refresh the navigation component
navComponent.refresh();
});
}
}
}

View File

@@ -0,0 +1,24 @@
import { NgModule } from '@angular/core';
import { MatButtonModule } from '@angular/material/button';
import { MatIconModule } from '@angular/material/icon';
import { MatMenuModule } from '@angular/material/menu';
import { LanguageComponent } from 'app/layout/common/language/language.component';
import { SharedModule } from 'app/shared/shared.module';
@NgModule({
declarations: [
LanguageComponent
],
imports : [
MatButtonModule,
MatIconModule,
MatMenuModule,
SharedModule
],
exports : [
LanguageComponent
]
})
export class LanguageModule
{
}

View File

@@ -46,7 +46,7 @@
<!-- Content -->
<div class="relative flex flex-col flex-auto sm:max-h-120 divide-y overflow-y-auto bg-card">
<!-- Messages -->
<ng-container *ngFor="let message of messages">
<ng-container *ngFor="let message of messages; trackBy: trackByFn">
<div
class="flex group hover:bg-gray-50 dark:hover:bg-black dark:hover:bg-opacity-5"
[ngClass]="{'unread': !message.read}">

View File

@@ -155,6 +155,17 @@ export class MessagesComponent implements OnInit, OnChanges, OnDestroy
this._messagesService.delete(message.id).subscribe();
}
/**
* Track by function for ngFor loops
*
* @param index
* @param item
*/
trackByFn(index: number, item: any): any
{
return item.id || index;
}
// -----------------------------------------------------------------------------------------------------
// @ Private methods
// -----------------------------------------------------------------------------------------------------

View File

@@ -46,7 +46,7 @@
<!-- Content -->
<div class="relative flex flex-col flex-auto sm:max-h-120 divide-y overflow-y-auto bg-card">
<!-- Notifications -->
<ng-container *ngFor="let notification of notifications">
<ng-container *ngFor="let notification of notifications; trackBy: trackByFn">
<div
class="flex group hover:bg-gray-50 dark:hover:bg-black dark:hover:bg-opacity-5"
[ngClass]="{'unread': !notification.read}">

View File

@@ -155,6 +155,17 @@ export class NotificationsComponent implements OnChanges, OnInit, OnDestroy
this._notificationsService.delete(notification.id).subscribe();
}
/**
* Track by function for ngFor loops
*
* @param index
* @param item
*/
trackByFn(index: number, item: any): any
{
return item.id || index;
}
// -----------------------------------------------------------------------------------------------------
// @ Private methods
// -----------------------------------------------------------------------------------------------------

View File

@@ -31,7 +31,7 @@
*ngIf="results && !results.length">
No results found!
</mat-option>
<ng-container *ngFor="let result of results">
<ng-container *ngFor="let result of results; trackBy: trackByFn">
<mat-option
class="group relative h-14 px-6 py-0 sm:px-8 text-md"
[routerLink]="result.link">
@@ -73,7 +73,7 @@
*ngIf="results && !results.length">
No results found!
</mat-option>
<ng-container *ngFor="let result of results">
<ng-container *ngFor="let result of results; trackBy: trackByFn">
<mat-option
class="group relative h-14 px-5 py-0 text-md"
[routerLink]="result.link">

View File

@@ -200,4 +200,15 @@ export class SearchComponent implements OnChanges, OnInit, OnDestroy
// Close the search
this.opened = false;
}
/**
* Track by function for ngFor loops
*
* @param index
* @param item
*/
trackByFn(index: number, item: any): any
{
return item.id || index;
}
}

View File

@@ -1,6 +1,6 @@
import { NgModule } from '@angular/core';
import { RouterModule } from '@angular/router';
import { Overlay } from '@angular/cdk/overlay';
import { BlockScrollStrategy, Overlay } from '@angular/cdk/overlay';
import { MAT_AUTOCOMPLETE_SCROLL_STRATEGY, MatAutocompleteModule } from '@angular/material/autocomplete';
import { MatButtonModule } from '@angular/material/button';
import { MatFormFieldModule } from '@angular/material/form-field';
@@ -28,7 +28,7 @@ import { SearchComponent } from 'app/layout/common/search/search.component';
providers : [
{
provide : MAT_AUTOCOMPLETE_SCROLL_STRATEGY,
useFactory: (overlay: Overlay) => () => overlay.scrollStrategies.block(),
useFactory: (overlay: Overlay) => (): BlockScrollStrategy => overlay.scrollStrategies.block(),
deps : [Overlay]
}
]

View File

@@ -94,7 +94,7 @@
<!-- Shortcuts -->
<div class="grid grid-cols-2 grid-flow-row">
<!-- Shortcut -->
<ng-container *ngFor="let shortcut of shortcuts">
<ng-container *ngFor="let shortcut of shortcuts; trackBy: trackByFn">
<div class="relative group flex flex-col overflow-hidden bg-card border-r border-b even:border-r-0 hover:bg-gray-50 dark:hover:bg-black dark:hover:bg-opacity-5">
<ng-container *ngIf="mode === 'modify'">
<div

View File

@@ -176,7 +176,7 @@ export class ShortcutsComponent implements OnChanges, OnInit, OnDestroy
*/
save(): void
{
// Get the mock-api from the form
// Get the data from the form
const shortcut = this.shortcutForm.value;
// If there is an id, update it...
@@ -199,7 +199,7 @@ export class ShortcutsComponent implements OnChanges, OnInit, OnDestroy
*/
delete(): void
{
// Get the mock-api from the form
// Get the data from the form
const shortcut = this.shortcutForm.value;
// Delete
@@ -209,6 +209,17 @@ export class ShortcutsComponent implements OnChanges, OnInit, OnDestroy
this.mode = 'modify';
}
/**
* Track by function for ngFor loops
*
* @param index
* @param item
*/
trackByFn(index: number, item: any): any
{
return item.id || index;
}
// -----------------------------------------------------------------------------------------------------
// @ Private methods
// -----------------------------------------------------------------------------------------------------

View File

@@ -217,7 +217,7 @@ export class LayoutComponent implements OnInit, OnDestroy
const paths = route.pathFromRoot;
paths.forEach((path) => {
// Check if there is a 'layout' mock-api
// Check if there is a 'layout' data
if ( path.routeConfig && path.routeConfig.data && path.routeConfig.data.layout )
{
// Set the layout

View File

@@ -63,6 +63,7 @@
</ng-container>
<!-- Components -->
<div class="flex items-center pl-2 ml-auto space-x-2">
<language></language>
<fuse-fullscreen></fuse-fullscreen>
<search [appearance]="'bar'"></search>
<shortcuts [shortcuts]="data.shortcuts"></shortcuts>

View File

@@ -3,7 +3,7 @@ import { ActivatedRoute, Data, Router } from '@angular/router';
import { Subject } from 'rxjs';
import { takeUntil } from 'rxjs/operators';
import { FuseMediaWatcherService } from '@fuse/services/media-watcher';
import { FuseNavigationService } from '@fuse/components/navigation';
import { FuseNavigationService, FuseVerticalNavigationComponent } from '@fuse/components/navigation';
import { InitialData } from 'app/app.types';
@Component({
@@ -50,7 +50,7 @@ export class CenteredLayoutComponent implements OnInit, OnDestroy
*/
ngOnInit(): void
{
// Subscribe to the resolved route mock-api
// Subscribe to the resolved route data
this._activatedRoute.data.subscribe((data: Data) => {
this.data = data.initialData;
});
@@ -87,7 +87,7 @@ export class CenteredLayoutComponent implements OnInit, OnDestroy
toggleNavigation(name: string): void
{
// Get the navigation
const navigation = this._fuseNavigationService.getComponent(name);
const navigation = this._fuseNavigationService.getComponent<FuseVerticalNavigationComponent>(name);
if ( navigation )
{

View File

@@ -7,6 +7,7 @@ import { MatIconModule } from '@angular/material/icon';
import { MatMenuModule } from '@angular/material/menu';
import { FuseFullscreenModule } from '@fuse/components/fullscreen';
import { FuseNavigationModule } from '@fuse/components/navigation';
import { LanguageModule } from 'app/layout/common/language/language.module';
import { MessagesModule } from 'app/layout/common/messages/messages.module';
import { NotificationsModule } from 'app/layout/common/notifications/notifications.module';
import { SearchModule } from 'app/layout/common/search/search.module';
@@ -28,6 +29,7 @@ import { CenteredLayoutComponent } from 'app/layout/layouts/horizontal/centered/
MatMenuModule,
FuseFullscreenModule,
FuseNavigationModule,
LanguageModule,
MessagesModule,
NotificationsModule,
SearchModule,

View File

@@ -46,6 +46,7 @@
</ng-container>
<!-- Components -->
<div class="flex items-center pl-2 ml-auto space-x-2">
<language></language>
<fuse-fullscreen></fuse-fullscreen>
<search [appearance]="'bar'"></search>
<shortcuts [shortcuts]="data.shortcuts"></shortcuts>

View File

@@ -3,7 +3,7 @@ import { ActivatedRoute, Data, Router } from '@angular/router';
import { Subject } from 'rxjs';
import { takeUntil } from 'rxjs/operators';
import { FuseMediaWatcherService } from '@fuse/services/media-watcher';
import { FuseNavigationService } from '@fuse/components/navigation';
import { FuseNavigationService, FuseVerticalNavigationComponent } from '@fuse/components/navigation';
import { InitialData } from 'app/app.types';
@Component({
@@ -50,7 +50,7 @@ export class EnterpriseLayoutComponent implements OnInit, OnDestroy
*/
ngOnInit(): void
{
// Subscribe to the resolved route mock-api
// Subscribe to the resolved route data
this._activatedRoute.data.subscribe((data: Data) => {
this.data = data.initialData;
});
@@ -87,7 +87,7 @@ export class EnterpriseLayoutComponent implements OnInit, OnDestroy
toggleNavigation(name: string): void
{
// Get the navigation
const navigation = this._fuseNavigationService.getComponent(name);
const navigation = this._fuseNavigationService.getComponent<FuseVerticalNavigationComponent>(name);
if ( navigation )
{

View File

@@ -7,6 +7,7 @@ import { MatIconModule } from '@angular/material/icon';
import { MatMenuModule } from '@angular/material/menu';
import { FuseFullscreenModule } from '@fuse/components/fullscreen';
import { FuseNavigationModule } from '@fuse/components/navigation';
import { LanguageModule } from 'app/layout/common/language/language.module';
import { MessagesModule } from 'app/layout/common/messages/messages.module';
import { NotificationsModule } from 'app/layout/common/notifications/notifications.module';
import { SearchModule } from 'app/layout/common/search/search.module';
@@ -28,6 +29,7 @@ import { EnterpriseLayoutComponent } from 'app/layout/layouts/horizontal/enterpr
MatMenuModule,
FuseFullscreenModule,
FuseNavigationModule,
LanguageModule,
MessagesModule,
NotificationsModule,
SearchModule,

View File

@@ -52,6 +52,7 @@
</ng-container>
<!-- Components -->
<div class="flex items-center pl-2 ml-auto space-x-2">
<language></language>
<fuse-fullscreen></fuse-fullscreen>
<search [appearance]="'bar'"></search>
<shortcuts [shortcuts]="data.shortcuts"></shortcuts>

View File

@@ -3,7 +3,7 @@ import { ActivatedRoute, Data, Router } from '@angular/router';
import { Subject } from 'rxjs';
import { takeUntil } from 'rxjs/operators';
import { FuseMediaWatcherService } from '@fuse/services/media-watcher';
import { FuseNavigationService } from '@fuse/components/navigation';
import { FuseNavigationService, FuseVerticalNavigationComponent } from '@fuse/components/navigation';
import { InitialData } from 'app/app.types';
@Component({
@@ -50,7 +50,7 @@ export class MaterialLayoutComponent implements OnInit, OnDestroy
*/
ngOnInit(): void
{
// Subscribe to the resolved route mock-api
// Subscribe to the resolved route data
this._activatedRoute.data.subscribe((data: Data) => {
this.data = data.initialData;
});
@@ -87,7 +87,7 @@ export class MaterialLayoutComponent implements OnInit, OnDestroy
toggleNavigation(name: string): void
{
// Get the navigation
const navigation = this._fuseNavigationService.getComponent(name);
const navigation = this._fuseNavigationService.getComponent<FuseVerticalNavigationComponent>(name);
if ( navigation )
{

View File

@@ -7,6 +7,7 @@ import { MatIconModule } from '@angular/material/icon';
import { MatMenuModule } from '@angular/material/menu';
import { FuseFullscreenModule } from '@fuse/components/fullscreen';
import { FuseNavigationModule } from '@fuse/components/navigation';
import { LanguageModule } from 'app/layout/common/language/language.module';
import { MessagesModule } from 'app/layout/common/messages/messages.module';
import { NotificationsModule } from 'app/layout/common/notifications/notifications.module';
import { SearchModule } from 'app/layout/common/search/search.module';
@@ -28,6 +29,7 @@ import { MaterialLayoutComponent } from 'app/layout/layouts/horizontal/material/
MatMenuModule,
FuseFullscreenModule,
FuseNavigationModule,
LanguageModule,
MessagesModule,
NotificationsModule,
SearchModule,

View File

@@ -55,6 +55,7 @@
</ng-container>
<!-- Components -->
<div class="flex items-center pl-2 ml-auto space-x-2">
<language></language>
<fuse-fullscreen></fuse-fullscreen>
<search [appearance]="'bar'"></search>
<shortcuts [shortcuts]="data.shortcuts"></shortcuts>

View File

@@ -3,7 +3,7 @@ import { ActivatedRoute, Data, Router } from '@angular/router';
import { Subject } from 'rxjs';
import { takeUntil } from 'rxjs/operators';
import { FuseMediaWatcherService } from '@fuse/services/media-watcher';
import { FuseNavigationService } from '@fuse/components/navigation';
import { FuseNavigationService, FuseVerticalNavigationComponent } from '@fuse/components/navigation';
import { InitialData } from 'app/app.types';
@Component({
@@ -50,7 +50,7 @@ export class ModernLayoutComponent implements OnInit, OnDestroy
*/
ngOnInit(): void
{
// Subscribe to the resolved route mock-api
// Subscribe to the resolved route data
this._activatedRoute.data.subscribe((data: Data) => {
this.data = data.initialData;
});
@@ -87,7 +87,7 @@ export class ModernLayoutComponent implements OnInit, OnDestroy
toggleNavigation(name: string): void
{
// Get the navigation
const navigation = this._fuseNavigationService.getComponent(name);
const navigation = this._fuseNavigationService.getComponent<FuseVerticalNavigationComponent>(name);
if ( navigation )
{

View File

@@ -7,6 +7,7 @@ import { MatIconModule } from '@angular/material/icon';
import { MatMenuModule } from '@angular/material/menu';
import { FuseFullscreenModule } from '@fuse/components/fullscreen';
import { FuseNavigationModule } from '@fuse/components/navigation';
import { LanguageModule } from 'app/layout/common/language/language.module';
import { MessagesModule } from 'app/layout/common/messages/messages.module';
import { NotificationsModule } from 'app/layout/common/notifications/notifications.module';
import { SearchModule } from 'app/layout/common/search/search.module';
@@ -28,6 +29,7 @@ import { ModernLayoutComponent } from 'app/layout/layouts/horizontal/modern/mode
MatMenuModule,
FuseFullscreenModule,
FuseNavigationModule,
LanguageModule,
MessagesModule,
NotificationsModule,
SearchModule,

View File

@@ -36,6 +36,7 @@
</button>
<!-- Components -->
<div class="flex items-center pl-2 ml-auto space-x-2">
<language></language>
<fuse-fullscreen></fuse-fullscreen>
<search [appearance]="'bar'"></search>
<shortcuts [shortcuts]="data.shortcuts"></shortcuts>

View File

@@ -3,7 +3,7 @@ import { ActivatedRoute, Data, Router } from '@angular/router';
import { Subject } from 'rxjs';
import { takeUntil } from 'rxjs/operators';
import { FuseMediaWatcherService } from '@fuse/services/media-watcher';
import { FuseNavigationService } from '@fuse/components/navigation';
import { FuseNavigationService, FuseVerticalNavigationComponent } from '@fuse/components/navigation';
import { InitialData } from 'app/app.types';
@Component({
@@ -50,7 +50,7 @@ export class ClassicLayoutComponent implements OnInit, OnDestroy
*/
ngOnInit(): void
{
// Subscribe to the resolved route mock-api
// Subscribe to the resolved route data
this._activatedRoute.data.subscribe((data: Data) => {
this.data = data.initialData;
});
@@ -87,7 +87,7 @@ export class ClassicLayoutComponent implements OnInit, OnDestroy
toggleNavigation(name: string): void
{
// Get the navigation
const navigation = this._fuseNavigationService.getComponent(name);
const navigation = this._fuseNavigationService.getComponent<FuseVerticalNavigationComponent>(name);
if ( navigation )
{

View File

@@ -7,6 +7,7 @@ import { MatIconModule } from '@angular/material/icon';
import { MatMenuModule } from '@angular/material/menu';
import { FuseFullscreenModule } from '@fuse/components/fullscreen';
import { FuseNavigationModule } from '@fuse/components/navigation';
import { LanguageModule } from 'app/layout/common/language/language.module';
import { MessagesModule } from 'app/layout/common/messages/messages.module';
import { NotificationsModule } from 'app/layout/common/notifications/notifications.module';
import { SearchModule } from 'app/layout/common/search/search.module';
@@ -28,6 +29,7 @@ import { ClassicLayoutComponent } from 'app/layout/layouts/vertical/classic/clas
MatMenuModule,
FuseFullscreenModule,
FuseNavigationModule,
LanguageModule,
MessagesModule,
NotificationsModule,
SearchModule,

View File

@@ -66,6 +66,7 @@
</button>
<!-- Components -->
<div class="flex items-center pl-2 ml-auto space-x-2">
<language></language>
<fuse-fullscreen></fuse-fullscreen>
<search [appearance]="'bar'"></search>
<shortcuts [shortcuts]="data.shortcuts"></shortcuts>

View File

@@ -3,7 +3,7 @@ import { ActivatedRoute, Data, Router } from '@angular/router';
import { Subject } from 'rxjs';
import { takeUntil } from 'rxjs/operators';
import { FuseMediaWatcherService } from '@fuse/services/media-watcher';
import { FuseNavigationService } from '@fuse/components/navigation';
import { FuseNavigationService, FuseVerticalNavigationComponent } from '@fuse/components/navigation';
import { InitialData } from 'app/app.types';
@Component({
@@ -50,7 +50,7 @@ export class ClassyLayoutComponent implements OnInit, OnDestroy
*/
ngOnInit(): void
{
// Subscribe to the resolved route mock-api
// Subscribe to the resolved route data
this._activatedRoute.data.subscribe((data: Data) => {
this.data = data.initialData;
});
@@ -87,7 +87,7 @@ export class ClassyLayoutComponent implements OnInit, OnDestroy
toggleNavigation(name: string): void
{
// Get the navigation
const navigation = this._fuseNavigationService.getComponent(name);
const navigation = this._fuseNavigationService.getComponent<FuseVerticalNavigationComponent>(name);
if ( navigation )
{

View File

@@ -7,6 +7,7 @@ import { MatIconModule } from '@angular/material/icon';
import { MatMenuModule } from '@angular/material/menu';
import { FuseNavigationModule } from '@fuse/components/navigation';
import { FuseFullscreenModule } from '@fuse/components/fullscreen/fullscreen.module';
import { LanguageModule } from 'app/layout/common/language/language.module';
import { MessagesModule } from 'app/layout/common/messages/messages.module';
import { NotificationsModule } from 'app/layout/common/notifications/notifications.module';
import { SearchModule } from 'app/layout/common/search/search.module';
@@ -28,6 +29,7 @@ import { ClassyLayoutComponent } from 'app/layout/layouts/vertical/classy/classy
MatMenuModule,
FuseFullscreenModule,
FuseNavigationModule,
LanguageModule,
MessagesModule,
NotificationsModule,
SearchModule,

View File

@@ -31,6 +31,7 @@
</button>
<!-- Components -->
<div class="flex items-center pl-2 ml-auto space-x-2">
<language></language>
<fuse-fullscreen></fuse-fullscreen>
<search [appearance]="'bar'"></search>
<shortcuts [shortcuts]="data.shortcuts"></shortcuts>

View File

@@ -3,7 +3,7 @@ import { ActivatedRoute, Data, Router } from '@angular/router';
import { Subject } from 'rxjs';
import { takeUntil } from 'rxjs/operators';
import { FuseMediaWatcherService } from '@fuse/services/media-watcher';
import { FuseNavigationService } from '@fuse/components/navigation';
import { FuseNavigationService, FuseVerticalNavigationComponent } from '@fuse/components/navigation';
import { InitialData } from 'app/app.types';
@Component({
@@ -50,7 +50,7 @@ export class CompactLayoutComponent implements OnInit, OnDestroy
*/
ngOnInit(): void
{
// Subscribe to the resolved route mock-api
// Subscribe to the resolved route data
this._activatedRoute.data.subscribe((data: Data) => {
this.data = data.initialData;
});
@@ -87,7 +87,7 @@ export class CompactLayoutComponent implements OnInit, OnDestroy
toggleNavigation(name: string): void
{
// Get the navigation
const navigation = this._fuseNavigationService.getComponent(name);
const navigation = this._fuseNavigationService.getComponent<FuseVerticalNavigationComponent>(name);
if ( navigation )
{

View File

@@ -7,6 +7,7 @@ import { MatIconModule } from '@angular/material/icon';
import { MatMenuModule } from '@angular/material/menu';
import { FuseFullscreenModule } from '@fuse/components/fullscreen';
import { FuseNavigationModule } from '@fuse/components/navigation';
import { LanguageModule } from 'app/layout/common/language/language.module';
import { MessagesModule } from 'app/layout/common/messages/messages.module';
import { NotificationsModule } from 'app/layout/common/notifications/notifications.module';
import { SearchModule } from 'app/layout/common/search/search.module';
@@ -28,6 +29,7 @@ import { CompactLayoutComponent } from 'app/layout/layouts/vertical/compact/comp
MatMenuModule,
FuseFullscreenModule,
FuseNavigationModule,
LanguageModule,
MessagesModule,
NotificationsModule,
SearchModule,

View File

@@ -40,6 +40,7 @@
</div>
<!-- Components -->
<div class="flex items-center pl-2 ml-auto space-x-2">
<language></language>
<fuse-fullscreen></fuse-fullscreen>
<search [appearance]="'bar'"></search>
<shortcuts [shortcuts]="data.shortcuts"></shortcuts>

View File

@@ -3,7 +3,7 @@ import { ActivatedRoute, Data, Router } from '@angular/router';
import { Subject } from 'rxjs';
import { takeUntil } from 'rxjs/operators';
import { FuseMediaWatcherService } from '@fuse/services/media-watcher';
import { FuseNavigationService } from '@fuse/components/navigation';
import { FuseNavigationService, FuseVerticalNavigationComponent } from '@fuse/components/navigation';
import { InitialData } from 'app/app.types';
@Component({
@@ -51,7 +51,7 @@ export class DenseLayoutComponent implements OnInit, OnDestroy
*/
ngOnInit(): void
{
// Subscribe to the resolved route mock-api
// Subscribe to the resolved route data
this._activatedRoute.data.subscribe((data: Data) => {
this.data = data.initialData;
});
@@ -88,7 +88,7 @@ export class DenseLayoutComponent implements OnInit, OnDestroy
toggleNavigation(name: string): void
{
// Get the navigation
const navigation = this._fuseNavigationService.getComponent(name);
const navigation = this._fuseNavigationService.getComponent<FuseVerticalNavigationComponent>(name);
if ( navigation )
{

View File

@@ -7,6 +7,7 @@ import { MatIconModule } from '@angular/material/icon';
import { MatMenuModule } from '@angular/material/menu';
import { FuseFullscreenModule } from '@fuse/components/fullscreen';
import { FuseNavigationModule } from '@fuse/components/navigation';
import { LanguageModule } from 'app/layout/common/language/language.module';
import { MessagesModule } from 'app/layout/common/messages/messages.module';
import { NotificationsModule } from 'app/layout/common/notifications/notifications.module';
import { SearchModule } from 'app/layout/common/search/search.module';
@@ -28,6 +29,7 @@ import { DenseLayoutComponent } from 'app/layout/layouts/vertical/dense/dense.co
MatMenuModule,
FuseFullscreenModule,
FuseNavigationModule,
LanguageModule,
MessagesModule,
NotificationsModule,
SearchModule,

View File

@@ -45,6 +45,7 @@
</button>
<!-- Components -->
<div class="flex items-center pl-2 ml-auto space-x-2">
<language></language>
<fuse-fullscreen></fuse-fullscreen>
<search [appearance]="'bar'"></search>
<shortcuts [shortcuts]="data.shortcuts"></shortcuts>

View File

@@ -3,7 +3,7 @@ import { ActivatedRoute, Data, Router } from '@angular/router';
import { Subject } from 'rxjs';
import { takeUntil } from 'rxjs/operators';
import { FuseMediaWatcherService } from '@fuse/services/media-watcher';
import { FuseNavigationService } from '@fuse/components/navigation';
import { FuseNavigationService, FuseVerticalNavigationComponent } from '@fuse/components/navigation';
import { InitialData } from 'app/app.types';
@Component({
@@ -50,7 +50,7 @@ export class FuturisticLayoutComponent implements OnInit, OnDestroy
*/
ngOnInit(): void
{
// Subscribe to the resolved route mock-api
// Subscribe to the resolved route data
this._activatedRoute.data.subscribe((data: Data) => {
this.data = data.initialData;
});
@@ -87,7 +87,7 @@ export class FuturisticLayoutComponent implements OnInit, OnDestroy
toggleNavigation(name: string): void
{
// Get the navigation
const navigation = this._fuseNavigationService.getComponent(name);
const navigation = this._fuseNavigationService.getComponent<FuseVerticalNavigationComponent>(name);
if ( navigation )
{

View File

@@ -7,6 +7,7 @@ import { MatIconModule } from '@angular/material/icon';
import { MatMenuModule } from '@angular/material/menu';
import { FuseFullscreenModule } from '@fuse/components/fullscreen';
import { FuseNavigationModule } from '@fuse/components/navigation';
import { LanguageModule } from 'app/layout/common/language/language.module';
import { MessagesModule } from 'app/layout/common/messages/messages.module';
import { NotificationsModule } from 'app/layout/common/notifications/notifications.module';
import { SearchModule } from 'app/layout/common/search/search.module';
@@ -28,6 +29,7 @@ import { FuturisticLayoutComponent } from 'app/layout/layouts/vertical/futuristi
MatMenuModule,
FuseFullscreenModule,
FuseNavigationModule,
LanguageModule,
MessagesModule,
NotificationsModule,
SearchModule,

View File

@@ -32,6 +32,7 @@
</button>
<!-- Components -->
<div class="flex items-center pl-2 ml-auto space-x-2">
<language></language>
<fuse-fullscreen></fuse-fullscreen>
<search [appearance]="'bar'"></search>
<shortcuts [shortcuts]="data.shortcuts"></shortcuts>

View File

@@ -3,7 +3,7 @@ import { ActivatedRoute, Data, Router } from '@angular/router';
import { Subject } from 'rxjs';
import { takeUntil } from 'rxjs/operators';
import { FuseMediaWatcherService } from '@fuse/services/media-watcher';
import { FuseNavigationService } from '@fuse/components/navigation';
import { FuseNavigationService, FuseVerticalNavigationComponent } from '@fuse/components/navigation';
import { InitialData } from 'app/app.types';
@Component({
@@ -50,7 +50,7 @@ export class ThinLayoutComponent implements OnInit, OnDestroy
*/
ngOnInit(): void
{
// Subscribe to the resolved route mock-api
// Subscribe to the resolved route data
this._activatedRoute.data.subscribe((data: Data) => {
this.data = data.initialData;
});
@@ -87,7 +87,7 @@ export class ThinLayoutComponent implements OnInit, OnDestroy
toggleNavigation(name: string): void
{
// Get the navigation
const navigation = this._fuseNavigationService.getComponent(name);
const navigation = this._fuseNavigationService.getComponent<FuseVerticalNavigationComponent>(name);
if ( navigation )
{

View File

@@ -7,6 +7,7 @@ import { MatIconModule } from '@angular/material/icon';
import { MatMenuModule } from '@angular/material/menu';
import { FuseFullscreenModule } from '@fuse/components/fullscreen';
import { FuseNavigationModule } from '@fuse/components/navigation';
import { LanguageModule } from 'app/layout/common/language/language.module';
import { MessagesModule } from 'app/layout/common/messages/messages.module';
import { NotificationsModule } from 'app/layout/common/notifications/notifications.module';
import { SearchModule } from 'app/layout/common/search/search.module';
@@ -28,6 +29,7 @@ import { ThinLayoutComponent } from 'app/layout/layouts/vertical/thin/thin.compo
MatMenuModule,
FuseFullscreenModule,
FuseNavigationModule,
LanguageModule,
MessagesModule,
NotificationsModule,
SearchModule,

View File

@@ -295,12 +295,12 @@ export class ContactsMockApi
const reader = new FileReader();
// Resolve the promise on success
reader.onload = () => {
reader.onload = (): void => {
resolve(reader.result);
};
// Reject the promise on error
reader.onerror = (e) => {
reader.onerror = (e): void => {
reject(e);
};

View File

@@ -50,7 +50,7 @@ export class ECommerceInventoryMockApi
// @ Products - GET
// -----------------------------------------------------------------------------------------------------
this._fuseMockApiService
.onGet('api/apps/ecommerce/inventory/products', 625)
.onGet('api/apps/ecommerce/inventory/products', 300)
.reply(({request}) => {
// Get available queries

View File

@@ -0,0 +1,454 @@
import { Injectable } from '@angular/core';
import { assign, cloneDeep } from 'lodash-es';
import { FuseMockApiService, FuseMockApiUtils } from '@fuse/lib/mock-api';
import { boards as boardsData, cards as cardsData, labels as labelsData, lists as listsData, members as membersData } from 'app/mock-api/apps/scrumboard/data';
@Injectable({
providedIn: 'root'
})
export class ScrumboardMockApi
{
// Private
private _boards: any[] = boardsData;
private _cards: any[] = cardsData;
private _labels: any[] = labelsData;
private _lists: any[] = listsData;
private _members: any[] = membersData;
/**
* Constructor
*/
constructor(private _fuseMockApiService: FuseMockApiService)
{
// Register Mock API handlers
this.registerHandlers();
}
// -----------------------------------------------------------------------------------------------------
// @ Public methods
// -----------------------------------------------------------------------------------------------------
/**
* Register Mock API handlers
*/
registerHandlers(): void
{
// -----------------------------------------------------------------------------------------------------
// @ Boards - GET
// -----------------------------------------------------------------------------------------------------
this._fuseMockApiService
.onGet('api/apps/scrumboard/boards')
.reply(({request}) => {
// Clone the boards
let boards = cloneDeep(this._boards);
// Go through the boards and inject the members
boards = boards.map(board => ({
...board,
members: board.members.map(boardMember => this._members.find(member => boardMember === member.id))
}));
return [
200,
boards
];
});
// -----------------------------------------------------------------------------------------------------
// @ Board - GET
// -----------------------------------------------------------------------------------------------------
this._fuseMockApiService
.onGet('api/apps/scrumboard/board')
.reply(({request}) => {
// Get the id
const id = request.params.get('id');
// Find the board
const board = this._boards.find(item => item.id === id);
// Attach the board lists
board.lists = this._lists.filter(item => item.boardId === id).sort((a, b) => a.position - b.position);
// Grab all cards that belong to this board and attach labels to them
let cards = this._cards.filter(item => item.boardId === id);
cards = cards.map(card => (
{
...card,
labels: card.labels.map(cardLabelId => this._labels.find(label => label.id === cardLabelId))
}
));
// Attach the board cards into corresponding lists
board.lists.forEach((list, index, array) => {
array[index].cards = cards.filter(item => item.boardId === id && item.listId === list.id).sort((a, b) => a.position - b.position);
});
// Attach the board labels
board.labels = this._labels.filter(item => item.boardId === id);
return [
200,
cloneDeep(board)
];
});
// -----------------------------------------------------------------------------------------------------
// @ List - POST
// -----------------------------------------------------------------------------------------------------
this._fuseMockApiService
.onPost('api/apps/scrumboard/board/list')
.reply(({request}) => {
// Get the list
const newList = cloneDeep(request.body.list);
// Generate a new GUID
newList.id = FuseMockApiUtils.guid();
// Store the new list
this._lists.push(newList);
return [
200,
newList
];
});
// -----------------------------------------------------------------------------------------------------
// @ List - PATCH
// -----------------------------------------------------------------------------------------------------
this._fuseMockApiService
.onPatch('api/apps/scrumboard/board/list')
.reply(({request}) => {
// Get the list
const list = cloneDeep(request.body.list);
// Prepare the updated list
let updatedList = null;
// Find the list and update it
this._lists.forEach((item, index, lists) => {
if ( item.id === list.id )
{
// Update the list
lists[index] = assign({}, lists[index], list);
// Store the updated list
updatedList = lists[index];
}
});
return [
200,
updatedList
];
});
// -----------------------------------------------------------------------------------------------------
// @ Lists - PATCH
// -----------------------------------------------------------------------------------------------------
this._fuseMockApiService
.onPatch('api/apps/scrumboard/board/lists')
.reply(({request}) => {
// Get the lists
const lists = cloneDeep(request.body.lists);
// Prepare the updated lists
const updatedLists = [];
// Go through the lists
lists.forEach((item) => {
// Find the list
const index = this._lists.findIndex(list => item.id === list.id);
// Update the list
this._lists[index] = assign({}, this._lists[index], item);
// Store in the updated lists
updatedLists.push(item);
});
return [
200,
updatedLists
];
});
// -----------------------------------------------------------------------------------------------------
// @ List - DELETE
// -----------------------------------------------------------------------------------------------------
this._fuseMockApiService
.onDelete('api/apps/scrumboard/board/list')
.reply(({request}) => {
// Get the id
const id = request.params.get('id');
// Find the list and delete it
const index = this._lists.findIndex(item => item.id === id);
this._lists.splice(index, 1);
// Filter out the cards that belonged to the list to delete them
this._cards = this._cards.filter(card => card.listId !== id);
return [
200,
true
];
});
// -----------------------------------------------------------------------------------------------------
// @ Card - PUT
// -----------------------------------------------------------------------------------------------------
this._fuseMockApiService
.onPut('api/apps/scrumboard/board/card')
.reply(({request}) => {
// Get the card
const newCard = cloneDeep(request.body.card);
// Generate a new GUID
newCard.id = FuseMockApiUtils.guid();
// Unshift the new card
this._cards.push(newCard);
return [
200,
newCard
];
});
// -----------------------------------------------------------------------------------------------------
// @ Card - PATCH
// -----------------------------------------------------------------------------------------------------
this._fuseMockApiService
.onPatch('api/apps/scrumboard/board/card')
.reply(({request}) => {
// Get the id and card
const id = request.body.id;
const card = cloneDeep(request.body.card);
// Prepare the updated card
let updatedCard = null;
// Go through the labels and leave only ids of them
card.labels = card.labels.map(itemLabel => itemLabel.id);
// Find the card and update it
this._cards.forEach((item, index, cards) => {
if ( item.id === id )
{
// Update the card
cards[index] = assign({}, cards[index], card);
// Store the updated card
updatedCard = cloneDeep(cards[index]);
}
});
// Attach the labels of the card
updatedCard.labels = updatedCard.labels.map(cardLabelId => this._labels.find(label => label.id === cardLabelId));
return [
200,
updatedCard
];
});
// -----------------------------------------------------------------------------------------------------
// @ Cards - PATCH
// -----------------------------------------------------------------------------------------------------
this._fuseMockApiService
.onPatch('api/apps/scrumboard/board/cards')
.reply(({request}) => {
// Get the cards
const cards = cloneDeep(request.body.cards);
// Prepare the updated cards
const updatedCards = [];
// Go through the cards
cards.forEach((item) => {
// Find the card
const index = this._cards.findIndex(card => item.id === card.id);
// Go through the labels and leave only ids of them
item.labels = item.labels.map(itemLabel => itemLabel.id);
// Update the card
this._cards[index] = assign({}, this._cards[index], item);
// Attach the labels of the card
item.labels = item.labels.map(cardLabelId => this._labels.find(label => label.id === cardLabelId));
// Store in the updated cards
updatedCards.push(item);
});
return [
200,
updatedCards
];
});
// -----------------------------------------------------------------------------------------------------
// @ Card - DELETE
// -----------------------------------------------------------------------------------------------------
this._fuseMockApiService
.onDelete('api/apps/scrumboard/board/card')
.reply(({request}) => {
// Get the id
const id = request.params.get('id');
// Find the card and delete it
const index = this._cards.findIndex(item => item.id === id);
this._cards.splice(index, 1);
return [
200,
true
];
});
// -----------------------------------------------------------------------------------------------------
// @ Card Positions - PATCH
// -----------------------------------------------------------------------------------------------------
this._fuseMockApiService
.onPatch('api/apps/scrumboard/board/card/positions')
.reply(({request}) => {
// Get the cards
const cards = request.body.cards;
// Go through the cards
this._cards.forEach((card) => {
// Find this card's index within the cards array that comes with the request
// and assign that index as the new position number for the card
card.position = cards.findIndex(item => item.id === card.id && item.listId === card.listId && item.boardId === card.boardId);
});
// Clone the cards
const updatedCards = cloneDeep(this._cards);
return [
200,
updatedCards
];
});
// -----------------------------------------------------------------------------------------------------
// @ Labels - GET
// -----------------------------------------------------------------------------------------------------
this._fuseMockApiService
.onGet('api/apps/scrumboard/board/labels')
.reply(({request}) => {
// Get the board id
const boardId = request.params.get('boardId');
// Filter the labels
const labels = this._labels.filter(item => item.boardId === boardId);
return [
200,
cloneDeep(labels)
];
});
// -----------------------------------------------------------------------------------------------------
// @ Label - PUT
// -----------------------------------------------------------------------------------------------------
this._fuseMockApiService
.onPut('api/apps/scrumboard/board/label')
.reply(({request}) => {
// Get the label
const newLabel = cloneDeep(request.body.label);
// Generate a new GUID
newLabel.id = FuseMockApiUtils.guid();
// Unshift the new label
this._labels.unshift(newLabel);
return [
200,
newLabel
];
});
// -----------------------------------------------------------------------------------------------------
// @ Label - PATCH
// -----------------------------------------------------------------------------------------------------
this._fuseMockApiService
.onPatch('api/apps/scrumboard/board/label')
.reply(({request}) => {
// Get the id and label
const id = request.body.id;
const label = cloneDeep(request.body.label);
// Prepare the updated label
let updatedLabel = null;
// Find the label and update it
this._labels.forEach((item, index, labels) => {
if ( item.id === id )
{
// Update the label
labels[index] = assign({}, labels[index], label);
// Store the updated label
updatedLabel = labels[index];
}
});
return [
200,
updatedLabel
];
});
// -----------------------------------------------------------------------------------------------------
// @ Label - DELETE
// -----------------------------------------------------------------------------------------------------
this._fuseMockApiService
.onDelete('api/apps/scrumboard/board/label')
.reply(({request}) => {
// Get the id
const id = request.params.get('id');
// Find the label and delete it
const index = this._labels.findIndex(item => item.id === id);
this._labels.splice(index, 1);
// Get the cards that have the label
const cardsWithLabel = this._cards.filter(card => card.labels.indexOf(id) > -1);
// Iterate through them and remove the label
cardsWithLabel.forEach((card) => {
card.tags.splice(card.tags.indexOf(id), 1);
});
return [
200,
true
];
});
}
}

View File

@@ -0,0 +1,334 @@
/* eslint-disable */
import * as moment from 'moment';
export const boards = [
{
id : '2c82225f-2a6c-45d3-b18a-1132712a4234',
title : 'Admin Dashboard',
description : 'Roadmap for the new project',
icon : 'heroicons_outline:template',
lastActivity: moment().startOf('day').subtract(1, 'day').toISOString(),
members : [
'9c510cf3-460d-4a8c-b3be-bcc3db578c08',
'baa88231-0ee6-4028-96d5-7f187e0f4cd5',
'18bb18f3-ea7d-4465-8913-e8c9adf6f568'
]
},
{
id : '0168b519-3dab-4b46-b2ea-0e678e38a583',
title : 'Weekly Planning',
description : 'Job related tasks for the week',
icon : 'heroicons_outline:calendar',
lastActivity: moment().startOf('day').subtract(2, 'days').toISOString(),
members : [
'79ebb9ee-1e57-4706-810c-03edaec8f56d',
'319ecb5b-f99c-4ee4-81b2-3aeffd1d4735',
'5bf7ed5b-8b04-46b7-b364-005958b7d82e',
'd1f612e6-3e3b-481f-a8a9-f917e243b06e',
'fe0fec0d-002b-406f-87ab-47eb87ba577c',
'23a47d2c-c6cb-40cc-af87-e946a9df5028',
'6726643d-e8dc-42fa-83a6-b4ec06921a6b',
'0d1eb062-13d5-4286-b8d4-e0bea15f3d56'
]
},
{
id : 'bc7db965-3c4f-4233-abf5-69bd70c3c175',
title : 'Personal Tasks',
description : 'Personal tasks around the house',
icon : 'heroicons_outline:home',
lastActivity: moment().startOf('day').subtract(1, 'week').toISOString(),
members : [
'6f6a1c34-390b-4b2e-97c8-ff0e0d787839'
]
}
];
export const lists = [
{
id : 'a2df7786-519c-485a-a85f-c09a61cc5f37',
boardId : '2c82225f-2a6c-45d3-b18a-1132712a4234',
position: 65536,
title : 'To do'
},
{
id : '83ca2a34-65af-49c0-a42e-94a34003fcf2',
boardId : '2c82225f-2a6c-45d3-b18a-1132712a4234',
position: 131072,
title : 'In progress'
},
{
id : 'a85ea483-f8f7-42d9-a314-3fed6aac22ab',
boardId : '2c82225f-2a6c-45d3-b18a-1132712a4234',
position: 196608,
title : 'In review'
},
{
id : '34cbef38-5687-4813-bd66-141a6df6d832',
boardId : '2c82225f-2a6c-45d3-b18a-1132712a4234',
position: 262144,
title : 'Completed'
}
];
export const cards = [
{
id : 'e74e66e9-fe0f-441e-a8ce-28ed6eccc48d',
boardId : '2c82225f-2a6c-45d3-b18a-1132712a4234',
listId : 'a2df7786-519c-485a-a85f-c09a61cc5f37',
position : 65536,
title : 'Example that showcase all of the available bits on the card with a fairly long title compared to other cards',
description: 'Example that showcase all of the available bits on the card with a fairly long title compared to other cards. Example that showcase all of the available bits on the card with a fairly long title compared to other cards.',
labels : [
'e0175175-2784-48f1-a519-a1d2e397c9b3',
'51779701-818a-4a53-bc16-137c3bd7a564',
'e8364d69-9595-46ce-a0f9-ce428632a0ac',
'caff9c9b-a198-4564-b1f4-8b3df1d345bb',
'f9eeb436-13a3-4208-a239-0d555960a567'
],
dueDate : moment().subtract(10, 'days').startOf('day').toISOString()
},
{
id : 'ed58add1-45a7-41db-887d-3ca7ee7f2719',
boardId : '2c82225f-2a6c-45d3-b18a-1132712a4234',
listId : 'a2df7786-519c-485a-a85f-c09a61cc5f37',
position: 131072,
title : 'Do a research about most needed admin applications',
labels : [
'e0175175-2784-48f1-a519-a1d2e397c9b3'
],
dueDate : null
},
{
id : 'cd6897cb-acfd-4016-8b53-3f66a5b5fc68',
boardId : '2c82225f-2a6c-45d3-b18a-1132712a4234',
listId : 'a2df7786-519c-485a-a85f-c09a61cc5f37',
position: 196608,
title : 'Implement the Project dashboard',
labels : [
'caff9c9b-a198-4564-b1f4-8b3df1d345bb'
],
dueDate : moment().startOf('day').toISOString()
},
{
id : '6da8747f-b474-4c9a-9eba-5ef212285500',
boardId : '2c82225f-2a6c-45d3-b18a-1132712a4234',
listId : 'a2df7786-519c-485a-a85f-c09a61cc5f37',
position: 262144,
title : 'Implement the Analytics dashboard',
labels : [
'caff9c9b-a198-4564-b1f4-8b3df1d345bb'
],
dueDate : moment().subtract(1, 'day').startOf('day').toISOString()
},
{
id : '94fb1dee-dd83-4cca-acdd-02e96d3cc4f1',
boardId : '2c82225f-2a6c-45d3-b18a-1132712a4234',
listId : '83ca2a34-65af-49c0-a42e-94a34003fcf2',
position: 65536,
title : 'Analytics dashboard design',
labels : [
'e8364d69-9595-46ce-a0f9-ce428632a0ac'
],
dueDate : null
},
{
id : 'fc16f7d8-957d-43ed-ba85-20f99b5ce011',
boardId : '2c82225f-2a6c-45d3-b18a-1132712a4234',
listId : '83ca2a34-65af-49c0-a42e-94a34003fcf2',
position: 131072,
title : 'Project dashboard design',
labels : [
'e8364d69-9595-46ce-a0f9-ce428632a0ac'
],
dueDate : null
},
{
id : 'c0b32f1f-64ec-4f8d-8b11-a8dc809df331',
boardId : '2c82225f-2a6c-45d3-b18a-1132712a4234',
listId : 'a85ea483-f8f7-42d9-a314-3fed6aac22ab',
position: 65536,
title : 'JWT Auth implementation',
labels : [
'caff9c9b-a198-4564-b1f4-8b3df1d345bb'
],
dueDate : null
},
{
id : '532c2747-be79-464a-9897-6a682bf22b64',
boardId : '2c82225f-2a6c-45d3-b18a-1132712a4234',
listId : '34cbef38-5687-4813-bd66-141a6df6d832',
position: 65536,
title : 'Create low fidelity wireframes',
labels : [],
dueDate : null
},
{
id : '1d908efe-c830-476e-9e87-d06e30d89bc2',
boardId : '2c82225f-2a6c-45d3-b18a-1132712a4234',
listId : '34cbef38-5687-4813-bd66-141a6df6d832',
position: 131072,
title : 'Create high fidelity wireframes',
labels : [],
dueDate : moment().subtract(10, 'day').startOf('day').toISOString()
},
{
id : 'b1da11ed-7896-4826-962d-4b7b718896d4',
boardId : '2c82225f-2a6c-45d3-b18a-1132712a4234',
listId : '34cbef38-5687-4813-bd66-141a6df6d832',
position: 196608,
title : 'Collect information about most used admin layouts',
labels : [
'e0175175-2784-48f1-a519-a1d2e397c9b3'
],
dueDate : null
},
{
id : '3b7f3ceb-107f-42bc-a204-c268c9a56cb4',
boardId : '2c82225f-2a6c-45d3-b18a-1132712a4234',
listId : '34cbef38-5687-4813-bd66-141a6df6d832',
position: 262144,
title : 'Do a research about latest UI trends',
labels : [
'e0175175-2784-48f1-a519-a1d2e397c9b3'
],
dueDate : null
},
{
id : 'cd7f01c5-a941-4076-8cef-37da0354e643',
boardId : '2c82225f-2a6c-45d3-b18a-1132712a4234',
listId : '34cbef38-5687-4813-bd66-141a6df6d832',
position: 327680,
title : 'Learn more about UX',
labels : [
'e0175175-2784-48f1-a519-a1d2e397c9b3'
],
dueDate : null
}
];
export const labels = [
{
id : 'e0175175-2784-48f1-a519-a1d2e397c9b3',
boardId: '2c82225f-2a6c-45d3-b18a-1132712a4234',
title : 'Research'
},
{
id : '51779701-818a-4a53-bc16-137c3bd7a564',
boardId: '2c82225f-2a6c-45d3-b18a-1132712a4234',
title : 'Wireframing'
},
{
id : 'e8364d69-9595-46ce-a0f9-ce428632a0ac',
boardId: '2c82225f-2a6c-45d3-b18a-1132712a4234',
title : 'Design'
},
{
id : 'caff9c9b-a198-4564-b1f4-8b3df1d345bb',
boardId: '2c82225f-2a6c-45d3-b18a-1132712a4234',
title : 'Development'
},
{
id : 'f9eeb436-13a3-4208-a239-0d555960a567',
boardId: '2c82225f-2a6c-45d3-b18a-1132712a4234',
title : 'Bug'
}
];
export const members = [
{
id : '6f6a1c34-390b-4b2e-97c8-ff0e0d787839',
name : 'Angeline Vinson',
avatar: 'assets/images/avatars/female-01.jpg'
},
{
id : '4ce4be48-c8c0-468d-9df8-ddfda14cdb37',
name : 'Roseann Greer',
avatar: 'assets/images/avatars/female-02.jpg'
},
{
id : '9c510cf3-460d-4a8c-b3be-bcc3db578c08',
name : 'Lorraine Barnett',
avatar: 'assets/images/avatars/female-03.jpg'
},
{
id : '7ec887d9-b01a-4057-b5dc-aaed18637cc1',
name : 'Middleton Bradford',
avatar: 'assets/images/avatars/male-01.jpg'
},
{
id : '74975a82-addb-427b-9b43-4d2e03331b68',
name : 'Sue Hays',
avatar: 'assets/images/avatars/female-04.jpg'
},
{
id : '18bb18f3-ea7d-4465-8913-e8c9adf6f568',
name : 'Keith Neal',
avatar: 'assets/images/avatars/male-02.jpg'
},
{
id : 'baa88231-0ee6-4028-96d5-7f187e0f4cd5',
name : 'Wilkins Gilmore',
avatar: 'assets/images/avatars/male-03.jpg'
},
{
id : '0d1eb062-13d5-4286-b8d4-e0bea15f3d56',
name : 'Baldwin Stein',
avatar: 'assets/images/avatars/male-04.jpg'
},
{
id : '5bf7ed5b-8b04-46b7-b364-005958b7d82e',
name : 'Bobbie Cohen',
avatar: 'assets/images/avatars/female-05.jpg'
},
{
id : '93b1a72b-e2db-4f77-82d6-272047433508',
name : 'Melody Peters',
avatar: 'assets/images/avatars/female-06.jpg'
},
{
id : 'd1f612e6-3e3b-481f-a8a9-f917e243b06e',
name : 'Marquez Ryan',
avatar: 'assets/images/avatars/male-05.jpg'
},
{
id : '79ebb9ee-1e57-4706-810c-03edaec8f56d',
name : 'Roberta Briggs',
avatar: 'assets/images/avatars/female-07.jpg'
},
{
id : '6726643d-e8dc-42fa-83a6-b4ec06921a6b',
name : 'Robbie Buckley',
avatar: 'assets/images/avatars/female-08.jpg'
},
{
id : '8af617d7-898e-4992-beda-d5ac1d7ceda4',
name : 'Garcia Whitney',
avatar: 'assets/images/avatars/male-06.jpg'
},
{
id : 'bcff44c4-9943-4adc-9049-08b1d922a658',
name : 'Spencer Pate',
avatar: 'assets/images/avatars/male-07.jpg'
},
{
id : '54160ca2-29c9-4475-88a1-31a9307ad913',
name : 'Monica Mcdaniel',
avatar: 'assets/images/avatars/female-09.jpg'
},
{
id : '51286603-3a43-444e-9242-f51fe57d5363',
name : 'Mcmillan Durham',
avatar: 'assets/images/avatars/male-08.jpg'
},
{
id : '319ecb5b-f99c-4ee4-81b2-3aeffd1d4735',
name : 'Jeoine Hebert',
avatar: 'assets/images/avatars/female-10.jpg'
},
{
id : 'fe0fec0d-002b-406f-87ab-47eb87ba577c',
name : 'Susanna Kline',
avatar: 'assets/images/avatars/female-11.jpg'
},
{
id : '23a47d2c-c6cb-40cc-af87-e946a9df5028',
name : 'Suzette Singleton',
avatar: 'assets/images/avatars/female-12.jpg'
}
];

View File

@@ -1,8 +1,7 @@
/* eslint-disable */
import * as moment from 'moment';
import { Message } from 'app/layout/common/messages/messages.types';
export const messages: Message[] = [
export const messages = [
{
id : '832276cc-c5e9-4fcc-8e23-d38e2e267bc9',
image : 'assets/images/avatars/male-01.jpg',

View File

@@ -134,6 +134,13 @@ export const defaultNavigation: FuseNavigationItem[] = [
icon : 'heroicons_outline:pencil-alt',
link : '/apps/notes'
},
{
id : 'apps.scrumboard',
title: 'Scrumboard',
type : 'basic',
icon : 'heroicons_outline:view-boards',
link : '/apps/scrumboard'
},
{
id : 'apps.tasks',
title: 'Tasks',
@@ -141,7 +148,6 @@ export const defaultNavigation: FuseNavigationItem[] = [
icon : 'heroicons_outline:check-circle',
link : '/apps/tasks'
}
]
},
{
@@ -151,6 +157,13 @@ export const defaultNavigation: FuseNavigationItem[] = [
type : 'group',
icon : 'heroicons_outline:document',
children: [
{
id : 'pages.activities',
title: 'Activities',
type : 'basic',
icon : 'heroicons_outline:menu-alt-2',
link : '/pages/activities'
},
{
id : 'pages.authentication',
title : 'Authentication',
@@ -920,7 +933,7 @@ export const defaultNavigation: FuseNavigationItem[] = [
icon : 'heroicons_outline:speakerphone',
link : '/docs/changelog',
badge: {
title : '13.0.0',
title : '13.0.3',
classes: 'px-2 bg-yellow-300 text-black rounded-full'
}
},
@@ -1263,6 +1276,13 @@ export const futuristicNavigation: FuseNavigationItem[] = [
icon : 'heroicons_outline:pencil-alt',
link : '/apps/notes'
},
{
id : 'apps.scrumboard',
title: 'Scrumboard',
type : 'basic',
icon : 'heroicons_outline:view-boards',
link : '/apps/scrumboard'
},
{
id : 'apps.tasks',
title: 'Tasks',

View File

@@ -1,8 +1,7 @@
/* eslint-disable */
import * as moment from 'moment';
import { Notification } from 'app/layout/common/notifications/notifications.types';
export const notifications: Notification[] = [
export const notifications = [
{
id : '493190c9-5b61-4912-afe5-78c21f1044d7',
icon : 'heroicons_outline:star',

View File

@@ -1,7 +1,5 @@
/* eslint-disable */
import { Shortcut } from 'app/layout/common/shortcuts/shortcuts.types';
export const shortcuts: Shortcut[] = [
export const shortcuts = [
{
id : 'a1ae91d3-e2cb-459b-9be9-a184694f548b',
label : 'Changelog',

View File

@@ -1,5 +1,5 @@
/* eslint-disable */
export const user: any = {
export const user = {
id : 'cfaad35d-07a3-4447-a6c3-d8c3d54fd5df',
name : 'Brian Hughes',
email : 'hughes.brian@company.com',

View File

@@ -1,4 +1,5 @@
import { AcademyMockApi } from 'app/mock-api/apps/academy/api';
import { ActivitiesMockApi } from 'app/mock-api/pages/activities/api';
import { AnalyticsMockApi } from 'app/mock-api/dashboards/analytics/api';
import { AuthMockApi } from 'app/mock-api/common/auth/api';
import { CalendarMockApi } from 'app/mock-api/apps/calendar/api';
@@ -15,12 +16,14 @@ import { NotesMockApi } from 'app/mock-api/apps/notes/api';
import { NotificationsMockApi } from 'app/mock-api/common/notifications/api';
import { ProjectMockApi } from 'app/mock-api/dashboards/project/api';
import { SearchMockApi } from 'app/mock-api/common/search/api';
import { ScrumboardMockApi } from 'app/mock-api/apps/scrumboard/api';
import { ShortcutsMockApi } from 'app/mock-api/common/shortcuts/api';
import { TasksMockApi } from 'app/mock-api/apps/tasks/api';
import { UserMockApi } from 'app/mock-api/common/user/api';
export const mockApiServices = [
AcademyMockApi,
ActivitiesMockApi,
AnalyticsMockApi,
AuthMockApi,
CalendarMockApi,
@@ -37,6 +40,7 @@ export const mockApiServices = [
NotificationsMockApi,
ProjectMockApi,
SearchMockApi,
ScrumboardMockApi,
ShortcutsMockApi,
TasksMockApi,
UserMockApi

View File

@@ -0,0 +1,38 @@
import { Injectable } from '@angular/core';
import { cloneDeep } from 'lodash-es';
import { FuseMockApiService } from '@fuse/lib/mock-api';
import { activities as activitiesData } from 'app/mock-api/pages/activities/data';
@Injectable({
providedIn: 'root'
})
export class ActivitiesMockApi
{
private _activities: any = activitiesData;
/**
* Constructor
*/
constructor(private _fuseMockApiService: FuseMockApiService)
{
// Register Mock API handlers
this.registerHandlers();
}
// -----------------------------------------------------------------------------------------------------
// @ Public methods
// -----------------------------------------------------------------------------------------------------
/**
* Register Mock API handlers
*/
registerHandlers(): void
{
// -----------------------------------------------------------------------------------------------------
// @ Activities - GET
// -----------------------------------------------------------------------------------------------------
this._fuseMockApiService
.onGet('api/pages/activities')
.reply(() => [200, cloneDeep(this._activities)]);
}
}

View File

@@ -0,0 +1,88 @@
/* eslint-disable */
import * as moment from 'moment';
export const activities = [
{
id : '493190c9-5b61-4912-afe5-78c21f1044d7',
icon : 'heroicons_solid:star',
description : 'Your submission has been accepted',
date : moment().subtract(25, 'minutes').toISOString(), // 25 minutes ago
extraContent: `<div class="font-bold">Congratulations for your acceptance!</div><br>
<div>Hi Brian,<br>Your submission has been accepted and you are ready to move into the next phase. Once you are ready, reach out to me and we will ...</div>`
},
{
id : '6e3e97e5-effc-4fb7-b730-52a151f0b641',
image : 'assets/images/avatars/male-04.jpg',
description : '<strong>Leo Gill</strong> added you to <strong>Top Secret Project</strong> group and assigned you as a <strong>Project Manager</strong>',
date : moment().subtract(50, 'minutes').toISOString(), // 50 minutes ago
linkedContent: 'Top Secret Project',
link : '/dashboards/project',
useRouter : true
},
{
id : 'b91ccb58-b06c-413b-b389-87010e03a120',
icon : 'heroicons_solid:mail',
description : 'You have 15 unread mails across 3 mailboxes',
date : moment().subtract(3, 'hours').toISOString(), // 3 hours ago
linkedContent: 'Mailbox',
link : '/apps/mailbox',
useRouter : true
},
{
id : '541416c9-84a7-408a-8d74-27a43c38d797',
icon : 'heroicons_solid:refresh',
description : 'Your <strong>Docker container</strong> is ready to publish',
date : moment().subtract(5, 'hours').toISOString(), // 5 hours ago
linkedContent: 'Download the container',
link : '.',
useRouter : true
},
{
id : 'ef7b95a7-8e8b-4616-9619-130d9533add9',
image : 'assets/images/avatars/male-06.jpg',
description : '<strong>Roger Murray</strong> accepted your friend request',
date : moment().subtract(7, 'hours').toISOString(), // 7 hours ago
extraContent: `You have <span class="font-semibold">8</span> mutual friends.`
},
{
id : 'eb8aa470-635e-461d-88e1-23d9ea2a5665',
image : 'assets/images/avatars/female-04.jpg',
description: '<strong>Sophie Stone</strong> sent you a direct message',
date : moment().subtract(9, 'hours').toISOString() // 9 hours ago
},
{
id : 'b85c2338-cc98-4140-bbf8-c226ce4e395e',
icon : 'heroicons_solid:mail',
description : 'You have 3 new mails',
date : moment().subtract(1, 'day').toISOString(), // 1 day ago
extraContent : `<ol class="list-decimal list-inside space-y-2">
<li class="font-medium">Please review and sign the attached agreement</li>
<li class="font-medium">Delivery address confirmation</li>
<li class="font-medium">Previous clients and their invoices</li>
</ol>`,
linkedContent: 'Mailbox',
link : '/apps/mailbox',
useRouter : true
},
{
id : 'fd0f01b4-f3de-4333-add5-cd86850279f8',
image : 'assets/images/avatars/female-02.jpg',
description : '<strong>Tina Harris</strong> started a chat with you',
date : moment().subtract(1, 'day').toISOString(), // 1 day ago,
linkedContent: 'Go to Chat (Tina Harris)',
link : '/apps/chat/5636c0ba-fa47-42ca-9160-27340583041e',
useRouter : true
},
{
id : '8f8e1bf9-4661-4939-9e43-390957b60f42',
icon : 'heroicons_solid:star',
description: 'Your submission has been accepted and you are ready to sign-up for the final assigment which will be ready in 2 days',
date : moment().subtract(3, 'days').toISOString() // 3 days ago
},
{
id : '30af917b-7a6a-45d1-822f-9e7ad7f8bf69',
icon : 'heroicons_solid:refresh',
description: 'Your Vagrant container is ready to download',
date : moment().subtract(4, 'day').toISOString() // 4 days ago
}
];

View File

@@ -341,8 +341,8 @@
<mat-form-field class="fuse-mat-textarea fuse-mat-no-subscript flex-auto">
<textarea
matInput
cdkTextareaAutosize
[cdkAutosizeMinRows]="1"
matTextareaAutosize
[matAutosizeMinRows]="1"
[formControlName]="'description'"
[placeholder]="'Event description'">
</textarea>

View File

@@ -243,8 +243,8 @@ export class CalendarComponent implements OnInit, AfterViewInit, OnDestroy
day : 'numeric',
omitCommas: true
},
columnHeaderHtml : date => `<span class="fc-weekday">${moment(date).format('ddd')}</span>
<span class="fc-date">${moment(date).format('D')}</span>`,
columnHeaderHtml : (date): string => `<span class="fc-weekday">${moment(date).format('ddd')}</span>
<span class="fc-date">${moment(date).format('D')}</span>`,
slotDuration : '01:00:00',
slotLabelFormat : this.eventTimeFormat
},
@@ -271,7 +271,7 @@ export class CalendarComponent implements OnInit, AfterViewInit, OnDestroy
this.viewTitle = this._fullCalendarApi.view.title;
// Get the view's current start and end dates, add/subtract
// 60 days to create a ~150 days period to fetch the mock-api for
// 60 days to create a ~150 days period to fetch the data for
const viewStart = moment(this._fullCalendarApi.view.currentStart).subtract(60, 'days');
const viewEnd = moment(this._fullCalendarApi.view.currentEnd).add(60, 'days');

View File

@@ -265,7 +265,7 @@ export class CalendarService
// Return if remaining days is bigger than the number
// of days to prefetch. This means we were already been
// there and fetched the events mock-api so no need for doing
// there and fetched the events data so no need for doing
// it again.
if ( remainingDays >= this._numberOfDaysToPrefetch )
{
@@ -292,7 +292,7 @@ export class CalendarService
// Return if remaining days is bigger than the number
// of days to prefetch. This means we were already been
// there and fetched the events mock-api so no need for doing
// there and fetched the events data so no need for doing
// it again.
if ( remainingDays >= this._numberOfDaysToPrefetch )
{

View File

@@ -7,7 +7,6 @@ import { MatIconModule } from '@angular/material/icon';
import { MatInputModule } from '@angular/material/input';
import { MatMenuModule } from '@angular/material/menu';
import { MatSidenavModule } from '@angular/material/sidenav';
import { FuseAutogrowModule } from '@fuse/directives/autogrow';
import { SharedModule } from 'app/shared/shared.module';
import { chatRoutes } from 'app/modules/admin/apps/chat/chat.routing';
import { ChatComponent } from 'app/modules/admin/apps/chat/chat.component';
@@ -35,7 +34,6 @@ import { ProfileComponent } from 'app/modules/admin/apps/chat/profile/profile.co
MatInputModule,
MatMenuModule,
MatSidenavModule,
FuseAutogrowModule,
SharedModule
]
})

View File

@@ -17,7 +17,6 @@ import { MatSidenavModule } from '@angular/material/sidenav';
import { MatTableModule } from '@angular/material/table';
import { MatTooltipModule } from '@angular/material/tooltip';
import * as moment from 'moment';
import { FuseAutogrowModule } from '@fuse/directives/autogrow';
import { FuseFindByKeyPipeModule } from '@fuse/pipes/find-by-key';
import { SharedModule } from 'app/shared/shared.module';
import { contactsRoutes } from 'app/modules/admin/apps/contacts/contacts.routing';
@@ -49,7 +48,6 @@ import { ContactsListComponent } from 'app/modules/admin/apps/contacts/list/list
MatSidenavModule,
MatTableModule,
MatTooltipModule,
FuseAutogrowModule,
FuseFindByKeyPipeModule,
SharedModule
],

Some files were not shown because too many files have changed in this diff Show More