mirror of
https://github.com/richard-loafle/fuse-angular.git
synced 2025-12-23 10:27:05 +00:00
Compare commits
35 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
47d9ddb08c | ||
|
|
4da3612d22 | ||
|
|
403a949d4a | ||
|
|
5b78a68116 | ||
|
|
214116e10d | ||
|
|
5962c80e8d | ||
|
|
ff086b1ed0 | ||
|
|
efdfa6418a | ||
|
|
c1c9904b9d | ||
|
|
39650d3cc9 | ||
|
|
bafa9adc01 | ||
|
|
bb9023f9df | ||
|
|
66096718e0 | ||
|
|
945d0a2240 | ||
|
|
9005f08ac7 | ||
|
|
89f5a4ec69 | ||
|
|
ca7b4c7e5d | ||
|
|
bb57ec2324 | ||
|
|
11ad2c89df | ||
|
|
fc1e7b02b0 | ||
|
|
446bfe4139 | ||
|
|
2c5cd60c0a | ||
|
|
decb238f73 | ||
|
|
ab3ad4fd2f | ||
|
|
c2dd77d7a3 | ||
|
|
a78b087a68 | ||
|
|
84d40427a1 | ||
|
|
f295fd9061 | ||
|
|
b98cfc1d37 | ||
|
|
0ba5677c01 | ||
|
|
96ef1281ae | ||
|
|
466bf50de4 | ||
|
|
95bc7dc4db | ||
|
|
cfca19dc68 | ||
|
|
a0c20f8d59 |
14
angular.json
14
angular.json
@@ -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"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
4346
package-lock.json
generated
4346
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
84
package.json
84
package.json
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@fuse/demo",
|
||||
"version": "13.0.1",
|
||||
"version": "13.1.0",
|
||||
"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.4",
|
||||
"@angular/cdk": "12.0.4",
|
||||
"@angular/common": "12.0.4",
|
||||
"@angular/compiler": "12.0.4",
|
||||
"@angular/core": "12.0.4",
|
||||
"@angular/forms": "12.0.4",
|
||||
"@angular/material": "12.0.4",
|
||||
"@angular/material-moment-adapter": "12.0.4",
|
||||
"@angular/platform-browser": "12.0.4",
|
||||
"@angular/platform-browser-dynamic": "12.0.4",
|
||||
"@angular/router": "12.0.4",
|
||||
"@fullcalendar/angular": "4.4.5-beta",
|
||||
"@fullcalendar/core": "4.4.2",
|
||||
"@fullcalendar/daygrid": "4.4.2",
|
||||
@@ -31,62 +31,60 @@
|
||||
"@fullcalendar/moment": "4.4.2",
|
||||
"@fullcalendar/rrule": "4.4.2",
|
||||
"@fullcalendar/timegrid": "4.4.2",
|
||||
"@ngneat/transloco": "2.20.1",
|
||||
"apexcharts": "3.26.3",
|
||||
"@ngneat/transloco": "2.21.0",
|
||||
"apexcharts": "3.27.1",
|
||||
"crypto-js": "3.3.0",
|
||||
"highlight.js": "10.7.2",
|
||||
"highlight.js": "11.0.1",
|
||||
"lodash-es": "4.17.21",
|
||||
"moment": "2.29.1",
|
||||
"ng-apexcharts": "1.5.10",
|
||||
"ngx-markdown": "12.0.0",
|
||||
"ng-apexcharts": "1.5.12",
|
||||
"ngx-markdown": "12.0.1",
|
||||
"ngx-quill": "14.0.0",
|
||||
"perfect-scrollbar": "1.5.1",
|
||||
"quill": "1.3.7",
|
||||
"rrule": "2.6.8",
|
||||
"rxjs": "6.6.7",
|
||||
"tslib": "2.2.0",
|
||||
"tslib": "2.3.0",
|
||||
"web-animations-js": "2.3.2",
|
||||
"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.4",
|
||||
"@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.4",
|
||||
"@angular/compiler-cli": "12.0.4",
|
||||
"@angular/language-service": "12.0.4",
|
||||
"@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.24.0",
|
||||
"@typescript-eslint/parser": "4.24.0",
|
||||
"autoprefixer": "10.2.5",
|
||||
"@types/node": "12.20.15",
|
||||
"@typescript-eslint/eslint-plugin": "4.26.1",
|
||||
"@typescript-eslint/parser": "4.26.1",
|
||||
"autoprefixer": "10.2.6",
|
||||
"chroma-js": "2.1.2",
|
||||
"eslint": "7.26.0",
|
||||
"eslint-plugin-import": "2.23.2",
|
||||
"eslint-plugin-jsdoc": "34.8.2",
|
||||
"eslint": "7.28.0",
|
||||
"eslint-plugin-import": "2.23.4",
|
||||
"eslint-plugin-jsdoc": "35.2.0",
|
||||
"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.4",
|
||||
"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.3.0",
|
||||
"protractor": "7.0.0",
|
||||
"tailwindcss": "2.1.2",
|
||||
"postcss": "8.3.3",
|
||||
"tailwindcss": "2.1.4",
|
||||
"typescript": "4.2.4"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,12 @@
|
||||
<!-- Button -->
|
||||
<button
|
||||
mat-icon-button
|
||||
[matTooltip]="'Toggle Fullscreen'"
|
||||
[matTooltip]="tooltip || 'Toggle Fullscreen'"
|
||||
(click)="toggleFullscreen()">
|
||||
<mat-icon [svgIcon]="'heroicons_outline:arrows-expand'"></mat-icon>
|
||||
<ng-container [ngTemplateOutlet]="iconTpl || defaultIconTpl"></ng-container>
|
||||
</button>
|
||||
|
||||
<!-- Default icon -->
|
||||
<ng-template #defaultIconTpl>
|
||||
<mat-icon [svgIcon]="'heroicons_outline:arrows-expand'"></mat-icon>
|
||||
</ng-template>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { ChangeDetectionStrategy, Component, Inject, OnInit, ViewEncapsulation } from '@angular/core';
|
||||
import { ChangeDetectionStrategy, Component, Inject, Input, OnInit, TemplateRef, ViewEncapsulation } from '@angular/core';
|
||||
import { DOCUMENT } from '@angular/common';
|
||||
import { FSDocument, FSDocumentElement } from '@fuse/components/fullscreen/fullscreen.types';
|
||||
|
||||
@@ -11,6 +11,8 @@ import { FSDocument, FSDocumentElement } from '@fuse/components/fullscreen/fulls
|
||||
})
|
||||
export class FuseFullscreenComponent implements OnInit
|
||||
{
|
||||
@Input() iconTpl: TemplateRef<any>;
|
||||
@Input() tooltip: string;
|
||||
private _fsDoc: FSDocument;
|
||||
private _fsDocEl: FSDocumentElement;
|
||||
private _isFullscreen: boolean = false;
|
||||
|
||||
@@ -3,15 +3,17 @@ import { MatButtonModule } from '@angular/material/button';
|
||||
import { MatIconModule } from '@angular/material/icon';
|
||||
import { MatTooltipModule } from '@angular/material/tooltip';
|
||||
import { FuseFullscreenComponent } from '@fuse/components/fullscreen/fullscreen.component';
|
||||
import { CommonModule } from '@angular/common';
|
||||
|
||||
@NgModule({
|
||||
declarations: [
|
||||
FuseFullscreenComponent
|
||||
],
|
||||
imports : [
|
||||
imports: [
|
||||
MatButtonModule,
|
||||
MatIconModule,
|
||||
MatTooltipModule
|
||||
MatTooltipModule,
|
||||
CommonModule
|
||||
],
|
||||
exports : [
|
||||
FuseFullscreenComponent
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { Injectable } from '@angular/core';
|
||||
import * as hljs from 'highlight.js';
|
||||
import hljs from 'highlight.js';
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root'
|
||||
|
||||
@@ -19,7 +19,8 @@
|
||||
<a
|
||||
class="fuse-horizontal-navigation-item"
|
||||
*ngIf="item.link && item.externalLink && !item.function && !item.disabled"
|
||||
[href]="item.link">
|
||||
[href]="item.link"
|
||||
[target]="item.target || '_self'">
|
||||
<ng-container *ngTemplateOutlet="itemTemplate"></ng-container>
|
||||
</a>
|
||||
|
||||
@@ -49,6 +50,7 @@
|
||||
class="fuse-horizontal-navigation-item"
|
||||
*ngIf="item.link && item.externalLink && item.function && !item.disabled"
|
||||
[href]="item.link"
|
||||
[target]="item.target || '_self'"
|
||||
(click)="item.function(item)"
|
||||
mat-menu-item>
|
||||
<ng-container *ngTemplateOutlet="itemTemplate"></ng-container>
|
||||
|
||||
@@ -17,6 +17,12 @@ export interface FuseNavigationItem
|
||||
disabled?: boolean;
|
||||
link?: string;
|
||||
externalLink?: boolean;
|
||||
target?:
|
||||
| '_blank'
|
||||
| '_self'
|
||||
| '_parent'
|
||||
| '_top'
|
||||
| string;
|
||||
exactMatch?: boolean;
|
||||
isActiveMatchOptions?: IsActiveMatchOptions;
|
||||
function?: (item: FuseNavigationItem) => void;
|
||||
|
||||
@@ -19,7 +19,8 @@
|
||||
<a
|
||||
class="fuse-vertical-navigation-item"
|
||||
*ngIf="item.link && item.externalLink && !item.function && !item.disabled"
|
||||
[href]="item.link">
|
||||
[href]="item.link"
|
||||
[target]="item.target || '_self'">
|
||||
<ng-container *ngTemplateOutlet="itemTemplate"></ng-container>
|
||||
</a>
|
||||
|
||||
@@ -49,6 +50,7 @@
|
||||
class="fuse-vertical-navigation-item"
|
||||
*ngIf="item.link && item.externalLink && item.function && !item.disabled"
|
||||
[href]="item.link"
|
||||
[target]="item.target || '_self'"
|
||||
(click)="item.function(item)">
|
||||
<ng-container *ngTemplateOutlet="itemTemplate"></ng-container>
|
||||
</a>
|
||||
|
||||
@@ -335,6 +335,7 @@ fuse-vertical-navigation {
|
||||
}
|
||||
|
||||
> .fuse-vertical-navigation-item-children {
|
||||
margin-top: 6px;
|
||||
|
||||
> *:last-child {
|
||||
padding-bottom: 6px;
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
{
|
||||
}
|
||||
@@ -1 +0,0 @@
|
||||
export * from '@fuse/directives/autogrow/public-api';
|
||||
@@ -1,2 +0,0 @@
|
||||
export * from '@fuse/directives/autogrow/autogrow.directive';
|
||||
export * from '@fuse/directives/autogrow/autogrow.module';
|
||||
@@ -410,6 +410,13 @@
|
||||
font-weight: 500 !important;
|
||||
}
|
||||
|
||||
/* ----------------------------------------------------------------------------------------------------- */
|
||||
/* @ Dialog
|
||||
/* ----------------------------------------------------------------------------------------------------- */
|
||||
.mat-dialog-container {
|
||||
border-radius: 16px !important;
|
||||
}
|
||||
|
||||
/* ----------------------------------------------------------------------------------------------------- */
|
||||
/* @ Drawer
|
||||
/* ----------------------------------------------------------------------------------------------------- */
|
||||
@@ -683,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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
import { Version } from '@fuse/version/version';
|
||||
|
||||
export const FUSE_VERSION = new Version('13.0.1').full;
|
||||
export const FUSE_VERSION = new Version('13.1.0').full;
|
||||
|
||||
@@ -1,9 +1,11 @@
|
||||
import { Injectable } from '@angular/core';
|
||||
import { HttpClient } from '@angular/common/http';
|
||||
import { ActivatedRouteSnapshot, Resolve, RouterStateSnapshot } from '@angular/router';
|
||||
import { forkJoin, Observable } from 'rxjs';
|
||||
import { map } from 'rxjs/operators';
|
||||
import { InitialData } from 'app/app.types';
|
||||
import { MessagesService } from 'app/layout/common/messages/messages.service';
|
||||
import { NavigationService } from 'app/core/navigation/navigation.service';
|
||||
import { NotificationsService } from 'app/layout/common/notifications/notifications.service';
|
||||
import { ShortcutsService } from 'app/layout/common/shortcuts/shortcuts.service';
|
||||
import { UserService } from 'app/core/user/user.service';
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root'
|
||||
@@ -13,7 +15,13 @@ export class InitialDataResolver implements Resolve<any>
|
||||
/**
|
||||
* Constructor
|
||||
*/
|
||||
constructor(private _httpClient: HttpClient)
|
||||
constructor(
|
||||
private _messagesService: MessagesService,
|
||||
private _navigationService: NavigationService,
|
||||
private _notificationsService: NotificationsService,
|
||||
private _shortcutsService: ShortcutsService,
|
||||
private _userService: UserService
|
||||
)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -27,29 +35,15 @@ export class InitialDataResolver implements Resolve<any>
|
||||
* @param route
|
||||
* @param state
|
||||
*/
|
||||
resolve(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<InitialData>
|
||||
resolve(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<any>
|
||||
{
|
||||
// Fork join multiple API endpoint calls to wait all of them to finish
|
||||
return forkJoin([
|
||||
this._httpClient.get<any>('api/common/messages'),
|
||||
this._httpClient.get<any>('api/common/navigation'),
|
||||
this._httpClient.get<any>('api/common/notifications'),
|
||||
this._httpClient.get<any>('api/common/shortcuts'),
|
||||
this._httpClient.get<any>('api/common/user')
|
||||
]).pipe(
|
||||
map(([messages, navigation, notifications, shortcuts, user]) => ({
|
||||
messages,
|
||||
navigation: {
|
||||
compact : navigation.compact,
|
||||
default : navigation.default,
|
||||
futuristic: navigation.futuristic,
|
||||
horizontal: navigation.horizontal
|
||||
},
|
||||
notifications,
|
||||
shortcuts,
|
||||
user
|
||||
})
|
||||
)
|
||||
);
|
||||
this._navigationService.get(),
|
||||
this._messagesService.getAll(),
|
||||
this._notificationsService.getAll(),
|
||||
this._shortcutsService.getAll(),
|
||||
this._userService.get()
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -92,6 +92,7 @@ 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)},
|
||||
]},
|
||||
|
||||
@@ -148,6 +149,9 @@ export const appRoutes: Route[] = [
|
||||
// TailwindCSS
|
||||
{path: 'tailwindcss', loadChildren: () => import('app/modules/admin/ui/tailwindcss/tailwindcss.module').then(m => m.TailwindCSSModule)},
|
||||
|
||||
// Advanced search
|
||||
{path: 'advanced-search', loadChildren: () => import('app/modules/admin/ui/advanced-search/advanced-search.module').then(m => m.AdvancedSearchModule)},
|
||||
|
||||
// Animations
|
||||
{path: 'animations', loadChildren: () => import('app/modules/admin/ui/animations/animations.module').then(m => m.AnimationsModule)},
|
||||
|
||||
|
||||
@@ -1,19 +0,0 @@
|
||||
import { FuseNavigationItem } from '@fuse/components/navigation';
|
||||
import { Message } from 'app/layout/common/messages/messages.types';
|
||||
import { Notification } from 'app/layout/common/notifications/notifications.types';
|
||||
import { Shortcut } from 'app/layout/common/shortcuts/shortcuts.types';
|
||||
import { User } from 'app/core/user/user.model';
|
||||
|
||||
export interface InitialData
|
||||
{
|
||||
messages: Message[];
|
||||
navigation: {
|
||||
compact: FuseNavigationItem[];
|
||||
default: FuseNavigationItem[];
|
||||
futuristic: FuseNavigationItem[];
|
||||
horizontal: FuseNavigationItem[];
|
||||
};
|
||||
notifications: Notification[];
|
||||
shortcuts: Shortcut[];
|
||||
user: User;
|
||||
}
|
||||
48
src/app/core/navigation/navigation.service.ts
Normal file
48
src/app/core/navigation/navigation.service.ts
Normal file
@@ -0,0 +1,48 @@
|
||||
import { Injectable } from '@angular/core';
|
||||
import { HttpClient } from '@angular/common/http';
|
||||
import { Observable, ReplaySubject } from 'rxjs';
|
||||
import { tap } from 'rxjs/operators';
|
||||
import { Navigation } from 'app/core/navigation/navigation.types';
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root'
|
||||
})
|
||||
export class NavigationService
|
||||
{
|
||||
private _navigation: ReplaySubject<Navigation> = new ReplaySubject<Navigation>(1);
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*/
|
||||
constructor(private _httpClient: HttpClient)
|
||||
{
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------------------------------
|
||||
// @ Accessors
|
||||
// -----------------------------------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Getter for navigation
|
||||
*/
|
||||
get navigation$(): Observable<Navigation>
|
||||
{
|
||||
return this._navigation.asObservable();
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------------------------------
|
||||
// @ Public methods
|
||||
// -----------------------------------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Get all navigation data
|
||||
*/
|
||||
get(): Observable<Navigation>
|
||||
{
|
||||
return this._httpClient.get<Navigation>('api/common/navigation').pipe(
|
||||
tap((navigation) => {
|
||||
this._navigation.next(navigation);
|
||||
})
|
||||
);
|
||||
}
|
||||
}
|
||||
9
src/app/core/navigation/navigation.types.ts
Normal file
9
src/app/core/navigation/navigation.types.ts
Normal file
@@ -0,0 +1,9 @@
|
||||
import { FuseNavigationItem } from '@fuse/components/navigation';
|
||||
|
||||
export interface Navigation
|
||||
{
|
||||
compact: FuseNavigationItem[];
|
||||
default: FuseNavigationItem[];
|
||||
futuristic: FuseNavigationItem[];
|
||||
horizontal: FuseNavigationItem[];
|
||||
}
|
||||
@@ -1,8 +1,8 @@
|
||||
import { Injectable } from '@angular/core';
|
||||
import { HttpClient } from '@angular/common/http';
|
||||
import { Observable, ReplaySubject } from 'rxjs';
|
||||
import { map } from 'rxjs/operators';
|
||||
import { User } from 'app/core/user/user.model';
|
||||
import { map, tap } from 'rxjs/operators';
|
||||
import { User } from 'app/core/user/user.types';
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root'
|
||||
@@ -42,6 +42,18 @@ export class UserService
|
||||
// @ Public methods
|
||||
// -----------------------------------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Get the current logged in user data
|
||||
*/
|
||||
get(): Observable<User>
|
||||
{
|
||||
return this._httpClient.get<User>('api/common/user').pipe(
|
||||
tap((user) => {
|
||||
this._user.next(user);
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the user
|
||||
*
|
||||
@@ -51,7 +63,6 @@ export class UserService
|
||||
{
|
||||
return this._httpClient.patch<User>('api/common/user', {user}).pipe(
|
||||
map((response) => {
|
||||
// Execute the observable
|
||||
this._user.next(response);
|
||||
})
|
||||
);
|
||||
|
||||
@@ -4,13 +4,13 @@ import { AvailableLangs, TranslocoService } from '@ngneat/transloco';
|
||||
import { FuseNavigationService, FuseVerticalNavigationComponent } from '@fuse/components/navigation';
|
||||
|
||||
@Component({
|
||||
selector : 'language',
|
||||
templateUrl : './language.component.html',
|
||||
selector : 'languages',
|
||||
templateUrl : './languages.component.html',
|
||||
encapsulation : ViewEncapsulation.None,
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
exportAs : 'language'
|
||||
exportAs : 'languages'
|
||||
})
|
||||
export class LanguageComponent implements OnInit, OnDestroy
|
||||
export class LanguagesComponent implements OnInit, OnDestroy
|
||||
{
|
||||
availableLangs: AvailableLangs;
|
||||
activeLang: string;
|
||||
@@ -2,12 +2,12 @@ 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 { LanguagesComponent } from 'app/layout/common/languages/languages.component';
|
||||
import { SharedModule } from 'app/shared/shared.module';
|
||||
|
||||
@NgModule({
|
||||
declarations: [
|
||||
LanguageComponent
|
||||
LanguagesComponent
|
||||
],
|
||||
imports : [
|
||||
MatButtonModule,
|
||||
@@ -16,9 +16,9 @@ import { SharedModule } from 'app/shared/shared.module';
|
||||
SharedModule
|
||||
],
|
||||
exports : [
|
||||
LanguageComponent
|
||||
LanguagesComponent
|
||||
]
|
||||
})
|
||||
export class LanguageModule
|
||||
export class LanguagesModule
|
||||
{
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
import { ChangeDetectionStrategy, ChangeDetectorRef, Component, Input, OnChanges, OnDestroy, OnInit, SimpleChanges, TemplateRef, ViewChild, ViewContainerRef, ViewEncapsulation } from '@angular/core';
|
||||
import { ChangeDetectionStrategy, ChangeDetectorRef, Component, OnDestroy, OnInit, TemplateRef, ViewChild, ViewContainerRef, ViewEncapsulation } from '@angular/core';
|
||||
import { Overlay, OverlayRef } from '@angular/cdk/overlay';
|
||||
import { TemplatePortal } from '@angular/cdk/portal';
|
||||
import { MatButton } from '@angular/material/button';
|
||||
@@ -14,12 +14,12 @@ import { MessagesService } from 'app/layout/common/messages/messages.service';
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
exportAs : 'messages'
|
||||
})
|
||||
export class MessagesComponent implements OnInit, OnChanges, OnDestroy
|
||||
export class MessagesComponent implements OnInit, OnDestroy
|
||||
{
|
||||
@Input() messages: Message[];
|
||||
@ViewChild('messagesOrigin') private _messagesOrigin: MatButton;
|
||||
@ViewChild('messagesPanel') private _messagesPanel: TemplateRef<any>;
|
||||
|
||||
messages: Message[];
|
||||
unreadCount: number = 0;
|
||||
private _overlayRef: OverlayRef;
|
||||
private _unsubscribeAll: Subject<any> = new Subject<any>();
|
||||
@@ -40,21 +40,6 @@ export class MessagesComponent implements OnInit, OnChanges, OnDestroy
|
||||
// @ Lifecycle hooks
|
||||
// -----------------------------------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* On changes
|
||||
*
|
||||
* @param changes
|
||||
*/
|
||||
ngOnChanges(changes: SimpleChanges): void
|
||||
{
|
||||
// Messages
|
||||
if ( 'messages' in changes )
|
||||
{
|
||||
// Store the messages on the service
|
||||
this._messagesService.store(changes.messages.currentValue);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* On init
|
||||
*/
|
||||
|
||||
@@ -2,7 +2,7 @@ import { Injectable } from '@angular/core';
|
||||
import { HttpClient } from '@angular/common/http';
|
||||
import { Observable, ReplaySubject } from 'rxjs';
|
||||
import { Message } from 'app/layout/common/messages/messages.types';
|
||||
import { map, switchMap, take } from 'rxjs/operators';
|
||||
import { map, switchMap, take, tap } from 'rxjs/operators';
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root'
|
||||
@@ -35,17 +35,15 @@ export class MessagesService
|
||||
// -----------------------------------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Store messages on the service
|
||||
*
|
||||
* @param messages
|
||||
* Get all messages
|
||||
*/
|
||||
store(messages: Message[]): Observable<Message[]>
|
||||
getAll(): Observable<Message[]>
|
||||
{
|
||||
// Load the messages
|
||||
this._messages.next(messages);
|
||||
|
||||
// Return the messages
|
||||
return this.messages$;
|
||||
return this._httpClient.get<Message[]>('api/common/messages').pipe(
|
||||
tap((messages) => {
|
||||
this._messages.next(messages);
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { ChangeDetectionStrategy, ChangeDetectorRef, Component, Input, OnChanges, OnDestroy, OnInit, SimpleChanges, TemplateRef, ViewChild, ViewContainerRef, ViewEncapsulation } from '@angular/core';
|
||||
import { ChangeDetectionStrategy, ChangeDetectorRef, Component, OnDestroy, OnInit, TemplateRef, ViewChild, ViewContainerRef, ViewEncapsulation } from '@angular/core';
|
||||
import { Overlay, OverlayRef } from '@angular/cdk/overlay';
|
||||
import { TemplatePortal } from '@angular/cdk/portal';
|
||||
import { MatButton } from '@angular/material/button';
|
||||
@@ -14,12 +14,12 @@ import { NotificationsService } from 'app/layout/common/notifications/notificati
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
exportAs : 'notifications'
|
||||
})
|
||||
export class NotificationsComponent implements OnChanges, OnInit, OnDestroy
|
||||
export class NotificationsComponent implements OnInit, OnDestroy
|
||||
{
|
||||
@Input() notifications: Notification[];
|
||||
@ViewChild('notificationsOrigin') private _notificationsOrigin: MatButton;
|
||||
@ViewChild('notificationsPanel') private _notificationsPanel: TemplateRef<any>;
|
||||
|
||||
notifications: Notification[];
|
||||
unreadCount: number = 0;
|
||||
private _overlayRef: OverlayRef;
|
||||
private _unsubscribeAll: Subject<any> = new Subject<any>();
|
||||
@@ -40,21 +40,6 @@ export class NotificationsComponent implements OnChanges, OnInit, OnDestroy
|
||||
// @ Lifecycle hooks
|
||||
// -----------------------------------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* On changes
|
||||
*
|
||||
* @param changes
|
||||
*/
|
||||
ngOnChanges(changes: SimpleChanges): void
|
||||
{
|
||||
// Notifications
|
||||
if ( 'notifications' in changes )
|
||||
{
|
||||
// Store the notifications on the service
|
||||
this._notificationsService.store(changes.notifications.currentValue);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* On init
|
||||
*/
|
||||
|
||||
@@ -2,7 +2,7 @@ import { Injectable } from '@angular/core';
|
||||
import { HttpClient } from '@angular/common/http';
|
||||
import { Observable, ReplaySubject } from 'rxjs';
|
||||
import { Notification } from 'app/layout/common/notifications/notifications.types';
|
||||
import { map, switchMap, take } from 'rxjs/operators';
|
||||
import { map, switchMap, take, tap } from 'rxjs/operators';
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root'
|
||||
@@ -35,17 +35,15 @@ export class NotificationsService
|
||||
// -----------------------------------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Store notifications on the service
|
||||
*
|
||||
* @param notifications
|
||||
* Get all notifications
|
||||
*/
|
||||
store(notifications: Notification[]): Observable<Notification[]>
|
||||
getAll(): Observable<Notification[]>
|
||||
{
|
||||
// Load the notifications
|
||||
this._notifications.next(notifications);
|
||||
|
||||
// Return the notifications
|
||||
return this.notifications$;
|
||||
return this._httpClient.get<Notification[]>('api/common/notifications').pipe(
|
||||
tap((notifications) => {
|
||||
this._notifications.next(notifications);
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -6,7 +6,6 @@
|
||||
(click)="open()">
|
||||
<mat-icon [svgIcon]="'heroicons_outline:search'"></mat-icon>
|
||||
</button>
|
||||
|
||||
<div
|
||||
class="absolute inset-0 flex items-center flex-shrink-0 z-99 bg-card"
|
||||
*ngIf="opened"
|
||||
@@ -23,22 +22,36 @@
|
||||
(keydown)="onKeydown($event)"
|
||||
#barSearchInput>
|
||||
<mat-autocomplete
|
||||
class="max-h-128 border-t rounded-b shadow-md"
|
||||
class="max-h-128 sm:px-2 border-t rounded-b shadow-md"
|
||||
[disableRipple]="true"
|
||||
#matAutocomplete="matAutocomplete">
|
||||
<mat-option
|
||||
class="h-14 px-6 py-0 sm:px-8 text-md pointer-events-none text-secondary bg-transparent"
|
||||
*ngIf="results && !results.length">
|
||||
class="py-0 px-6 text-md pointer-events-none text-secondary bg-transparent"
|
||||
*ngIf="resultSets && !resultSets.length">
|
||||
No results found!
|
||||
</mat-option>
|
||||
<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">
|
||||
<ng-container
|
||||
[ngTemplateOutlet]="searchResult"
|
||||
[ngTemplateOutletContext]="{$implicit: result}"></ng-container>
|
||||
</mat-option>
|
||||
<ng-container *ngFor="let resultSet of resultSets; trackBy: trackByFn">
|
||||
<mat-optgroup class="flex items-center mt-2 px-2">
|
||||
<span class="text-sm font-semibold tracking-wider text-secondary">{{resultSet.label.toUpperCase()}}</span>
|
||||
</mat-optgroup>
|
||||
<ng-container *ngFor="let result of resultSet.results; trackBy: trackByFn">
|
||||
<mat-option
|
||||
class="group relative mb-1 py-0 px-6 text-md rounded-md hover:bg-gray-100 dark:hover:bg-hover"
|
||||
[routerLink]="result.link">
|
||||
<!-- Contacts -->
|
||||
<ng-container *ngIf="resultSet.id === 'contacts'">
|
||||
<ng-container *ngTemplateOutlet="contactResult; context: {$implicit: result}"></ng-container>
|
||||
</ng-container>
|
||||
<!-- Pages -->
|
||||
<ng-container *ngIf="resultSet.id === 'pages'">
|
||||
<ng-container *ngTemplateOutlet="pageResult; context: {$implicit: result}"></ng-container>
|
||||
</ng-container>
|
||||
<!-- Tasks -->
|
||||
<ng-container *ngIf="resultSet.id === 'tasks'">
|
||||
<ng-container *ngTemplateOutlet="taskResult; context: {$implicit: result}"></ng-container>
|
||||
</ng-container>
|
||||
</mat-option>
|
||||
</ng-container>
|
||||
</ng-container>
|
||||
</mat-autocomplete>
|
||||
<button
|
||||
@@ -69,62 +82,89 @@
|
||||
[disableRipple]="true"
|
||||
#matAutocomplete="matAutocomplete">
|
||||
<mat-option
|
||||
class="h-14 px-5 py-0 text-md pointer-events-none text-secondary bg-transparent"
|
||||
*ngIf="results && !results.length">
|
||||
class="py-0 px-6 text-md pointer-events-none text-secondary bg-transparent"
|
||||
*ngIf="resultSets && !resultSets.length">
|
||||
No results found!
|
||||
</mat-option>
|
||||
<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">
|
||||
<ng-container
|
||||
[ngTemplateOutlet]="searchResult"
|
||||
[ngTemplateOutletContext]="{$implicit: result}"></ng-container>
|
||||
</mat-option>
|
||||
<ng-container *ngFor="let resultSet of resultSets; trackBy: trackByFn">
|
||||
<mat-optgroup class="flex items-center mt-2 px-2">
|
||||
<span class="text-sm font-semibold tracking-wider text-secondary">{{resultSet.label.toUpperCase()}}</span>
|
||||
</mat-optgroup>
|
||||
<ng-container *ngFor="let result of resultSet.results; trackBy: trackByFn">
|
||||
<mat-option
|
||||
class="group relative mb-1 py-0 px-6 text-md rounded-md hover:bg-gray-100 dark:hover:bg-hover"
|
||||
[routerLink]="result.link">
|
||||
<!-- Contacts -->
|
||||
<ng-container *ngIf="resultSet.id === 'contacts'">
|
||||
<ng-container *ngTemplateOutlet="contactResult; context: {$implicit: result}"></ng-container>
|
||||
</ng-container>
|
||||
<!-- Pages -->
|
||||
<ng-container *ngIf="resultSet.id === 'pages'">
|
||||
<ng-container *ngTemplateOutlet="pageResult; context: {$implicit: result}"></ng-container>
|
||||
</ng-container>
|
||||
<!-- Tasks -->
|
||||
<ng-container *ngIf="resultSet.id === 'tasks'">
|
||||
<ng-container *ngTemplateOutlet="taskResult; context: {$implicit: result}"></ng-container>
|
||||
</ng-container>
|
||||
</mat-option>
|
||||
</ng-container>
|
||||
</ng-container>
|
||||
</mat-autocomplete>
|
||||
</div>
|
||||
</ng-container>
|
||||
|
||||
<!-- Contact result template -->
|
||||
<ng-template
|
||||
#searchResult
|
||||
#contactResult
|
||||
let-result>
|
||||
|
||||
<!-- Hover indicator -->
|
||||
<div class="absolute inset-y-0 left-0 hidden w-1 bg-primary group-hover:flex"></div>
|
||||
|
||||
<!-- Contact result -->
|
||||
<ng-container *ngIf="result.resultType === 'contact'">
|
||||
<div class="flex items-center">
|
||||
<div class="px-1.5 py-1 mr-4 text-xs font-semibold leading-normal rounded text-indigo-50 bg-indigo-600">Contact</div>
|
||||
<div class="overflow-hidden overflow-ellipsis">
|
||||
<span [innerHTML]="result.title"></span>
|
||||
</div>
|
||||
<div class="flex flex-shrink-0 items-center justify-center w-8 h-8 ml-auto rounded-full overflow-hidden bg-primary-100 dark:bg-black dark:bg-opacity-5">
|
||||
<img
|
||||
*ngIf="result.avatar"
|
||||
[src]="result.avatar">
|
||||
<mat-icon
|
||||
class="m-0 icon-size-5 text-primary"
|
||||
*ngIf="!result.avatar"
|
||||
[svgIcon]="'heroicons_outline:user-circle'"></mat-icon>
|
||||
</div>
|
||||
<div class="flex items-center">
|
||||
<div class="flex flex-shrink-0 items-center justify-center w-8 h-8 rounded-full overflow-hidden bg-primary-100 dark:bg-primary-800">
|
||||
<img
|
||||
*ngIf="result.avatar"
|
||||
[src]="result.avatar">
|
||||
<mat-icon
|
||||
class="m-0 icon-size-5 text-primary dark:text-primary-400"
|
||||
*ngIf="!result.avatar"
|
||||
[svgIcon]="'heroicons_outline:user-circle'"></mat-icon>
|
||||
</div>
|
||||
</ng-container>
|
||||
|
||||
<!-- Page result -->
|
||||
<ng-container *ngIf="result.resultType === 'page'">
|
||||
<div class="flex items-center">
|
||||
<div class="px-1.5 py-1 mr-4 text-xs font-semibold leading-normal rounded text-teal-50 bg-teal-600">Page</div>
|
||||
<div class="flex flex-col overflow-hidden overflow-ellipsis">
|
||||
<span
|
||||
class="overflow-hidden overflow-ellipsis whitespace-nowrap leading-normal"
|
||||
[innerHTML]="result.title"></span>
|
||||
<span
|
||||
class="mt-1 text-secondary overflow-hidden overflow-ellipsis whitespace-nowrap leading-normal text-sm no-underline"
|
||||
[routerLink]="result.link">{{result.link}}</span>
|
||||
</div>
|
||||
<div class="ml-3 truncate">
|
||||
<span [innerHTML]="result.name"></span>
|
||||
</div>
|
||||
</ng-container>
|
||||
|
||||
</div>
|
||||
</ng-template>
|
||||
|
||||
<!-- Page result template -->
|
||||
<ng-template
|
||||
#pageResult
|
||||
let-result>
|
||||
<div class="flex flex-col">
|
||||
<div
|
||||
class="truncate leading-normal"
|
||||
[innerHTML]="result.title"></div>
|
||||
<div class="truncate leading-normal text-sm text-secondary">
|
||||
{{result.link}}
|
||||
</div>
|
||||
</div>
|
||||
</ng-template>
|
||||
|
||||
<!-- Task result template -->
|
||||
<ng-template
|
||||
#taskResult
|
||||
let-result>
|
||||
<div class="flex items-center">
|
||||
<ng-container *ngIf="result.completed">
|
||||
<mat-icon
|
||||
class="mr-0 text-primary dark:text-primary-400"
|
||||
[svgIcon]="'heroicons_outline:check-circle'"></mat-icon>
|
||||
</ng-container>
|
||||
<ng-container *ngIf="!result.completed">
|
||||
<mat-icon
|
||||
class="mr-0 text-hint"
|
||||
[svgIcon]="'heroicons_outline:check-circle'"></mat-icon>
|
||||
</ng-container>
|
||||
<div
|
||||
class="ml-3 truncate leading-normal"
|
||||
[ngClass]="{'line-through text-hint': result.completed}"
|
||||
[innerHTML]="result.title"></div>
|
||||
</div>
|
||||
</ng-template>
|
||||
|
||||
@@ -20,7 +20,7 @@ export class SearchComponent implements OnChanges, OnInit, OnDestroy
|
||||
@Output() search: EventEmitter<any> = new EventEmitter<any>();
|
||||
|
||||
opened: boolean = false;
|
||||
results: any[];
|
||||
resultSets: any[];
|
||||
searchControl: FormControl = new FormControl();
|
||||
private _unsubscribeAll: Subject<any> = new Subject<any>();
|
||||
|
||||
@@ -104,12 +104,12 @@ export class SearchComponent implements OnChanges, OnInit, OnDestroy
|
||||
takeUntil(this._unsubscribeAll),
|
||||
map((value) => {
|
||||
|
||||
// Set the search results to null if there is no value or
|
||||
// Set the resultSets to null if there is no value or
|
||||
// the length of the value is smaller than the minLength
|
||||
// so the autocomplete panel can be closed
|
||||
if ( !value || value.length < this.minLength )
|
||||
{
|
||||
this.results = null;
|
||||
this.resultSets = null;
|
||||
}
|
||||
|
||||
// Continue
|
||||
@@ -121,13 +121,13 @@ export class SearchComponent implements OnChanges, OnInit, OnDestroy
|
||||
)
|
||||
.subscribe((value) => {
|
||||
this._httpClient.post('api/common/search', {query: value})
|
||||
.subscribe((response: any) => {
|
||||
.subscribe((resultSets: any) => {
|
||||
|
||||
// Store the results
|
||||
this.results = response.results;
|
||||
// Store the result sets
|
||||
this.resultSets = resultSets;
|
||||
|
||||
// Execute the event
|
||||
this.search.next(this.results);
|
||||
this.search.next(resultSets);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
@@ -21,7 +21,15 @@
|
||||
[svgIcon]="'heroicons_solid:x'"></mat-icon>
|
||||
</button>
|
||||
</div>
|
||||
<div class="text-lg font-medium leading-10">Shortcuts</div>
|
||||
<div class="flex items-center text-lg font-medium leading-10">
|
||||
<span class="">Shortcuts</span>
|
||||
<ng-container *ngIf="mode !== 'view'">
|
||||
<span class="ml-1">
|
||||
<ng-container *ngIf="mode === 'add'">- Add new</ng-container>
|
||||
<ng-container *ngIf="mode === 'modify' || mode === 'edit'">- Editing</ng-container>
|
||||
</span>
|
||||
</ng-container>
|
||||
</div>
|
||||
<div class="ml-auto">
|
||||
|
||||
<!-- View mode -->
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { ChangeDetectionStrategy, ChangeDetectorRef, Component, Input, OnChanges, OnDestroy, OnInit, SimpleChanges, TemplateRef, ViewChild, ViewContainerRef, ViewEncapsulation } from '@angular/core';
|
||||
import { ChangeDetectionStrategy, ChangeDetectorRef, Component, OnDestroy, OnInit, TemplateRef, ViewChild, ViewContainerRef, ViewEncapsulation } from '@angular/core';
|
||||
import { FormBuilder, FormGroup, Validators } from '@angular/forms';
|
||||
import { Overlay, OverlayRef } from '@angular/cdk/overlay';
|
||||
import { TemplatePortal } from '@angular/cdk/portal';
|
||||
@@ -15,14 +15,14 @@ import { ShortcutsService } from 'app/layout/common/shortcuts/shortcuts.service'
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
exportAs : 'shortcuts'
|
||||
})
|
||||
export class ShortcutsComponent implements OnChanges, OnInit, OnDestroy
|
||||
export class ShortcutsComponent implements OnInit, OnDestroy
|
||||
{
|
||||
@Input() shortcuts: Shortcut[];
|
||||
@ViewChild('shortcutsOrigin') private _shortcutsOrigin: MatButton;
|
||||
@ViewChild('shortcutsPanel') private _shortcutsPanel: TemplateRef<any>;
|
||||
|
||||
mode: 'view' | 'modify' | 'add' | 'edit' = 'view';
|
||||
shortcutForm: FormGroup;
|
||||
shortcuts: Shortcut[];
|
||||
private _overlayRef: OverlayRef;
|
||||
private _unsubscribeAll: Subject<any> = new Subject<any>();
|
||||
|
||||
@@ -43,21 +43,6 @@ export class ShortcutsComponent implements OnChanges, OnInit, OnDestroy
|
||||
// @ Lifecycle hooks
|
||||
// -----------------------------------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* On changes
|
||||
*
|
||||
* @param changes
|
||||
*/
|
||||
ngOnChanges(changes: SimpleChanges): void
|
||||
{
|
||||
// Shortcuts
|
||||
if ( 'shortcuts' in changes )
|
||||
{
|
||||
// Store the shortcuts on the service
|
||||
this._shortcutsService.store(changes.shortcuts.currentValue);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* On init
|
||||
*/
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { Injectable } from '@angular/core';
|
||||
import { HttpClient } from '@angular/common/http';
|
||||
import { Observable, ReplaySubject } from 'rxjs';
|
||||
import { map, switchMap, take } from 'rxjs/operators';
|
||||
import { map, switchMap, take, tap } from 'rxjs/operators';
|
||||
import { Shortcut } from 'app/layout/common/shortcuts/shortcuts.types';
|
||||
|
||||
@Injectable({
|
||||
@@ -35,17 +35,15 @@ export class ShortcutsService
|
||||
// -----------------------------------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Store shortcuts on the service
|
||||
*
|
||||
* @param shortcuts
|
||||
* Get all messages
|
||||
*/
|
||||
store(shortcuts: Shortcut[]): Observable<Shortcut[]>
|
||||
getAll(): Observable<Shortcut[]>
|
||||
{
|
||||
// Load the shortcuts
|
||||
this._shortcuts.next(shortcuts);
|
||||
|
||||
// Return the shortcuts
|
||||
return this.shortcuts$;
|
||||
return this._httpClient.get<Shortcut[]>('api/common/shortcuts').pipe(
|
||||
tap((shortcuts) => {
|
||||
this._shortcuts.next(shortcuts);
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -3,17 +3,17 @@ import { Router } from '@angular/router';
|
||||
import { BooleanInput } from '@angular/cdk/coercion';
|
||||
import { Subject } from 'rxjs';
|
||||
import { takeUntil } from 'rxjs/operators';
|
||||
import { User } from 'app/core/user/user.model';
|
||||
import { User } from 'app/core/user/user.types';
|
||||
import { UserService } from 'app/core/user/user.service';
|
||||
|
||||
@Component({
|
||||
selector : 'user-menu',
|
||||
templateUrl : './user-menu.component.html',
|
||||
selector : 'user',
|
||||
templateUrl : './user.component.html',
|
||||
encapsulation : ViewEncapsulation.None,
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
exportAs : 'userMenu'
|
||||
exportAs : 'user'
|
||||
})
|
||||
export class UserMenuComponent implements OnInit, OnDestroy
|
||||
export class UserComponent implements OnInit, OnDestroy
|
||||
{
|
||||
/* eslint-disable @typescript-eslint/naming-convention */
|
||||
static ngAcceptInputType_showAvatar: BooleanInput;
|
||||
@@ -3,12 +3,12 @@ import { MatButtonModule } from '@angular/material/button';
|
||||
import { MatDividerModule } from '@angular/material/divider';
|
||||
import { MatIconModule } from '@angular/material/icon';
|
||||
import { MatMenuModule } from '@angular/material/menu';
|
||||
import { UserMenuComponent } from 'app/layout/common/user-menu/user-menu.component';
|
||||
import { UserComponent } from 'app/layout/common/user/user.component';
|
||||
import { SharedModule } from 'app/shared/shared.module';
|
||||
|
||||
@NgModule({
|
||||
declarations: [
|
||||
UserMenuComponent
|
||||
UserComponent
|
||||
],
|
||||
imports : [
|
||||
MatButtonModule,
|
||||
@@ -18,9 +18,9 @@ import { SharedModule } from 'app/shared/shared.module';
|
||||
SharedModule
|
||||
],
|
||||
exports : [
|
||||
UserMenuComponent
|
||||
UserComponent
|
||||
]
|
||||
})
|
||||
export class UserMenuModule
|
||||
export class UserModule
|
||||
{
|
||||
}
|
||||
@@ -6,7 +6,7 @@
|
||||
class="dark bg-gray-900 print:hidden"
|
||||
[mode]="'over'"
|
||||
[name]="'mainNavigation'"
|
||||
[navigation]="data.navigation.default"
|
||||
[navigation]="navigation.default"
|
||||
[opened]="false">
|
||||
<!-- Navigation header hook -->
|
||||
<ng-container fuseVerticalNavigationContentHeader>
|
||||
@@ -50,7 +50,7 @@
|
||||
<fuse-horizontal-navigation
|
||||
class="mr-2"
|
||||
[name]="'mainNavigation'"
|
||||
[navigation]="data.navigation.horizontal"></fuse-horizontal-navigation>
|
||||
[navigation]="navigation.horizontal"></fuse-horizontal-navigation>
|
||||
</ng-container>
|
||||
<!-- Navigation toggle button -->
|
||||
<ng-container *ngIf="isScreenSmall">
|
||||
@@ -63,13 +63,13 @@
|
||||
</ng-container>
|
||||
<!-- Components -->
|
||||
<div class="flex items-center pl-2 ml-auto space-x-2">
|
||||
<language></language>
|
||||
<languages></languages>
|
||||
<fuse-fullscreen></fuse-fullscreen>
|
||||
<search [appearance]="'bar'"></search>
|
||||
<shortcuts [shortcuts]="data.shortcuts"></shortcuts>
|
||||
<messages [messages]="data.messages"></messages>
|
||||
<notifications [notifications]="data.notifications"></notifications>
|
||||
<user-menu></user-menu>
|
||||
<shortcuts></shortcuts>
|
||||
<messages></messages>
|
||||
<notifications></notifications>
|
||||
<user></user>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -4,7 +4,8 @@ import { Subject } from 'rxjs';
|
||||
import { takeUntil } from 'rxjs/operators';
|
||||
import { FuseMediaWatcherService } from '@fuse/services/media-watcher';
|
||||
import { FuseNavigationService, FuseVerticalNavigationComponent } from '@fuse/components/navigation';
|
||||
import { InitialData } from 'app/app.types';
|
||||
import { Navigation } from 'app/core/navigation/navigation.types';
|
||||
import { NavigationService } from 'app/core/navigation/navigation.service';
|
||||
|
||||
@Component({
|
||||
selector : 'centered-layout',
|
||||
@@ -13,7 +14,7 @@ import { InitialData } from 'app/app.types';
|
||||
})
|
||||
export class CenteredLayoutComponent implements OnInit, OnDestroy
|
||||
{
|
||||
data: InitialData;
|
||||
navigation: Navigation;
|
||||
isScreenSmall: boolean;
|
||||
private _unsubscribeAll: Subject<any> = new Subject<any>();
|
||||
|
||||
@@ -23,6 +24,7 @@ export class CenteredLayoutComponent implements OnInit, OnDestroy
|
||||
constructor(
|
||||
private _activatedRoute: ActivatedRoute,
|
||||
private _router: Router,
|
||||
private _navigationService: NavigationService,
|
||||
private _fuseMediaWatcherService: FuseMediaWatcherService,
|
||||
private _fuseNavigationService: FuseNavigationService
|
||||
)
|
||||
@@ -50,10 +52,12 @@ export class CenteredLayoutComponent implements OnInit, OnDestroy
|
||||
*/
|
||||
ngOnInit(): void
|
||||
{
|
||||
// Subscribe to the resolved route data
|
||||
this._activatedRoute.data.subscribe((data: Data) => {
|
||||
this.data = data.initialData;
|
||||
});
|
||||
// Subscribe to navigation data
|
||||
this._navigationService.navigation$
|
||||
.pipe(takeUntil(this._unsubscribeAll))
|
||||
.subscribe((navigation: Navigation) => {
|
||||
this.navigation = navigation;
|
||||
});
|
||||
|
||||
// Subscribe to media changes
|
||||
this._fuseMediaWatcherService.onMediaChange$
|
||||
|
||||
@@ -7,12 +7,12 @@ 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 { LanguagesModule } from 'app/layout/common/languages/languages.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';
|
||||
import { ShortcutsModule } from 'app/layout/common/shortcuts/shortcuts.module';
|
||||
import { UserMenuModule } from 'app/layout/common/user-menu/user-menu.module';
|
||||
import { UserModule } from 'app/layout/common/user/user.module';
|
||||
import { SharedModule } from 'app/shared/shared.module';
|
||||
import { CenteredLayoutComponent } from 'app/layout/layouts/horizontal/centered/centered.component';
|
||||
|
||||
@@ -29,12 +29,12 @@ import { CenteredLayoutComponent } from 'app/layout/layouts/horizontal/centered/
|
||||
MatMenuModule,
|
||||
FuseFullscreenModule,
|
||||
FuseNavigationModule,
|
||||
LanguageModule,
|
||||
LanguagesModule,
|
||||
MessagesModule,
|
||||
NotificationsModule,
|
||||
SearchModule,
|
||||
ShortcutsModule,
|
||||
UserMenuModule,
|
||||
UserModule,
|
||||
SharedModule
|
||||
],
|
||||
exports : [
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
class="dark bg-gray-900 print:hidden"
|
||||
[mode]="'over'"
|
||||
[name]="'mainNavigation'"
|
||||
[navigation]="data.navigation.default"
|
||||
[navigation]="navigation.default"
|
||||
[opened]="false">
|
||||
<!-- Navigation header hook -->
|
||||
<ng-container fuseVerticalNavigationContentHeader>
|
||||
@@ -46,13 +46,13 @@
|
||||
</ng-container>
|
||||
<!-- Components -->
|
||||
<div class="flex items-center pl-2 ml-auto space-x-2">
|
||||
<language></language>
|
||||
<languages></languages>
|
||||
<fuse-fullscreen></fuse-fullscreen>
|
||||
<search [appearance]="'bar'"></search>
|
||||
<shortcuts [shortcuts]="data.shortcuts"></shortcuts>
|
||||
<messages [messages]="data.messages"></messages>
|
||||
<notifications [notifications]="data.notifications"></notifications>
|
||||
<user-menu></user-menu>
|
||||
<shortcuts></shortcuts>
|
||||
<messages></messages>
|
||||
<notifications></notifications>
|
||||
<user></user>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -63,7 +63,7 @@
|
||||
<fuse-horizontal-navigation
|
||||
class="-mx-4"
|
||||
[name]="'mainNavigation'"
|
||||
[navigation]="data.navigation.horizontal"></fuse-horizontal-navigation>
|
||||
[navigation]="navigation.horizontal"></fuse-horizontal-navigation>
|
||||
</div>
|
||||
</div>
|
||||
</ng-container>
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
import { Component, OnDestroy, OnInit, ViewEncapsulation } from '@angular/core';
|
||||
import { ActivatedRoute, Data, Router } from '@angular/router';
|
||||
import { ActivatedRoute, Router } from '@angular/router';
|
||||
import { Subject } from 'rxjs';
|
||||
import { takeUntil } from 'rxjs/operators';
|
||||
import { FuseMediaWatcherService } from '@fuse/services/media-watcher';
|
||||
import { FuseNavigationService, FuseVerticalNavigationComponent } from '@fuse/components/navigation';
|
||||
import { InitialData } from 'app/app.types';
|
||||
import { Navigation } from 'app/core/navigation/navigation.types';
|
||||
import { NavigationService } from 'app/core/navigation/navigation.service';
|
||||
|
||||
@Component({
|
||||
selector : 'enterprise-layout',
|
||||
@@ -13,8 +14,8 @@ import { InitialData } from 'app/app.types';
|
||||
})
|
||||
export class EnterpriseLayoutComponent implements OnInit, OnDestroy
|
||||
{
|
||||
data: InitialData;
|
||||
isScreenSmall: boolean;
|
||||
navigation: Navigation;
|
||||
private _unsubscribeAll: Subject<any> = new Subject<any>();
|
||||
|
||||
/**
|
||||
@@ -23,6 +24,7 @@ export class EnterpriseLayoutComponent implements OnInit, OnDestroy
|
||||
constructor(
|
||||
private _activatedRoute: ActivatedRoute,
|
||||
private _router: Router,
|
||||
private _navigationService: NavigationService,
|
||||
private _fuseMediaWatcherService: FuseMediaWatcherService,
|
||||
private _fuseNavigationService: FuseNavigationService
|
||||
)
|
||||
@@ -50,10 +52,12 @@ export class EnterpriseLayoutComponent implements OnInit, OnDestroy
|
||||
*/
|
||||
ngOnInit(): void
|
||||
{
|
||||
// Subscribe to the resolved route data
|
||||
this._activatedRoute.data.subscribe((data: Data) => {
|
||||
this.data = data.initialData;
|
||||
});
|
||||
// Subscribe to navigation data
|
||||
this._navigationService.navigation$
|
||||
.pipe(takeUntil(this._unsubscribeAll))
|
||||
.subscribe((navigation: Navigation) => {
|
||||
this.navigation = navigation;
|
||||
});
|
||||
|
||||
// Subscribe to media changes
|
||||
this._fuseMediaWatcherService.onMediaChange$
|
||||
|
||||
@@ -7,12 +7,12 @@ 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 { LanguagesModule } from 'app/layout/common/languages/languages.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';
|
||||
import { ShortcutsModule } from 'app/layout/common/shortcuts/shortcuts.module';
|
||||
import { UserMenuModule } from 'app/layout/common/user-menu/user-menu.module';
|
||||
import { UserModule } from 'app/layout/common/user/user.module';
|
||||
import { SharedModule } from 'app/shared/shared.module';
|
||||
import { EnterpriseLayoutComponent } from 'app/layout/layouts/horizontal/enterprise/enterprise.component';
|
||||
|
||||
@@ -29,12 +29,12 @@ import { EnterpriseLayoutComponent } from 'app/layout/layouts/horizontal/enterpr
|
||||
MatMenuModule,
|
||||
FuseFullscreenModule,
|
||||
FuseNavigationModule,
|
||||
LanguageModule,
|
||||
LanguagesModule,
|
||||
MessagesModule,
|
||||
NotificationsModule,
|
||||
SearchModule,
|
||||
ShortcutsModule,
|
||||
UserMenuModule,
|
||||
UserModule,
|
||||
SharedModule
|
||||
],
|
||||
exports : [
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
class="dark bg-gray-900 print:hidden"
|
||||
[mode]="'over'"
|
||||
[name]="'mainNavigation'"
|
||||
[navigation]="data.navigation.default"
|
||||
[navigation]="navigation.default"
|
||||
[opened]="false">
|
||||
<!-- Navigation header hook -->
|
||||
<ng-container fuseVerticalNavigationContentHeader>
|
||||
@@ -52,13 +52,13 @@
|
||||
</ng-container>
|
||||
<!-- Components -->
|
||||
<div class="flex items-center pl-2 ml-auto space-x-2">
|
||||
<language></language>
|
||||
<languages></languages>
|
||||
<fuse-fullscreen></fuse-fullscreen>
|
||||
<search [appearance]="'bar'"></search>
|
||||
<shortcuts [shortcuts]="data.shortcuts"></shortcuts>
|
||||
<messages [messages]="data.messages"></messages>
|
||||
<notifications [notifications]="data.notifications"></notifications>
|
||||
<user-menu></user-menu>
|
||||
<shortcuts></shortcuts>
|
||||
<messages></messages>
|
||||
<notifications></notifications>
|
||||
<user></user>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Bottom bar -->
|
||||
@@ -66,7 +66,7 @@
|
||||
<div class="relative flex flex-auto flex-0 items-center h-16 px-4">
|
||||
<fuse-horizontal-navigation
|
||||
[name]="'mainNavigation'"
|
||||
[navigation]="data.navigation.horizontal"></fuse-horizontal-navigation>
|
||||
[navigation]="navigation.horizontal"></fuse-horizontal-navigation>
|
||||
</div>
|
||||
</ng-container>
|
||||
</div>
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
import { Component, OnDestroy, OnInit, ViewEncapsulation } from '@angular/core';
|
||||
import { ActivatedRoute, Data, Router } from '@angular/router';
|
||||
import { ActivatedRoute, Router } from '@angular/router';
|
||||
import { Subject } from 'rxjs';
|
||||
import { takeUntil } from 'rxjs/operators';
|
||||
import { FuseMediaWatcherService } from '@fuse/services/media-watcher';
|
||||
import { FuseNavigationService, FuseVerticalNavigationComponent } from '@fuse/components/navigation';
|
||||
import { InitialData } from 'app/app.types';
|
||||
import { Navigation } from 'app/core/navigation/navigation.types';
|
||||
import { NavigationService } from 'app/core/navigation/navigation.service';
|
||||
|
||||
@Component({
|
||||
selector : 'material-layout',
|
||||
@@ -13,8 +14,8 @@ import { InitialData } from 'app/app.types';
|
||||
})
|
||||
export class MaterialLayoutComponent implements OnInit, OnDestroy
|
||||
{
|
||||
data: InitialData;
|
||||
isScreenSmall: boolean;
|
||||
navigation: Navigation;
|
||||
private _unsubscribeAll: Subject<any> = new Subject<any>();
|
||||
|
||||
/**
|
||||
@@ -23,6 +24,7 @@ export class MaterialLayoutComponent implements OnInit, OnDestroy
|
||||
constructor(
|
||||
private _activatedRoute: ActivatedRoute,
|
||||
private _router: Router,
|
||||
private _navigationService: NavigationService,
|
||||
private _fuseMediaWatcherService: FuseMediaWatcherService,
|
||||
private _fuseNavigationService: FuseNavigationService
|
||||
)
|
||||
@@ -50,10 +52,12 @@ export class MaterialLayoutComponent implements OnInit, OnDestroy
|
||||
*/
|
||||
ngOnInit(): void
|
||||
{
|
||||
// Subscribe to the resolved route data
|
||||
this._activatedRoute.data.subscribe((data: Data) => {
|
||||
this.data = data.initialData;
|
||||
});
|
||||
// Subscribe to navigation data
|
||||
this._navigationService.navigation$
|
||||
.pipe(takeUntil(this._unsubscribeAll))
|
||||
.subscribe((navigation: Navigation) => {
|
||||
this.navigation = navigation;
|
||||
});
|
||||
|
||||
// Subscribe to media changes
|
||||
this._fuseMediaWatcherService.onMediaChange$
|
||||
|
||||
@@ -7,12 +7,12 @@ 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 { LanguagesModule } from 'app/layout/common/languages/languages.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';
|
||||
import { ShortcutsModule } from 'app/layout/common/shortcuts/shortcuts.module';
|
||||
import { UserMenuModule } from 'app/layout/common/user-menu/user-menu.module';
|
||||
import { UserModule } from 'app/layout/common/user/user.module';
|
||||
import { SharedModule } from 'app/shared/shared.module';
|
||||
import { MaterialLayoutComponent } from 'app/layout/layouts/horizontal/material/material.component';
|
||||
|
||||
@@ -29,12 +29,12 @@ import { MaterialLayoutComponent } from 'app/layout/layouts/horizontal/material/
|
||||
MatMenuModule,
|
||||
FuseFullscreenModule,
|
||||
FuseNavigationModule,
|
||||
LanguageModule,
|
||||
LanguagesModule,
|
||||
MessagesModule,
|
||||
NotificationsModule,
|
||||
SearchModule,
|
||||
ShortcutsModule,
|
||||
UserMenuModule,
|
||||
UserModule,
|
||||
SharedModule
|
||||
],
|
||||
exports : [
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
class="dark bg-gray-900 print:hidden"
|
||||
[mode]="'over'"
|
||||
[name]="'mainNavigation'"
|
||||
[navigation]="data.navigation.default"
|
||||
[navigation]="navigation.default"
|
||||
[opened]="false">
|
||||
<!-- Navigation header hook -->
|
||||
<ng-container fuseVerticalNavigationContentHeader>
|
||||
@@ -43,7 +43,7 @@
|
||||
<fuse-horizontal-navigation
|
||||
class="mr-2"
|
||||
[name]="'mainNavigation'"
|
||||
[navigation]="data.navigation.horizontal"></fuse-horizontal-navigation>
|
||||
[navigation]="navigation.horizontal"></fuse-horizontal-navigation>
|
||||
</ng-container>
|
||||
<!-- Navigation toggle button -->
|
||||
<ng-container *ngIf="isScreenSmall">
|
||||
@@ -55,13 +55,13 @@
|
||||
</ng-container>
|
||||
<!-- Components -->
|
||||
<div class="flex items-center pl-2 ml-auto space-x-2">
|
||||
<language></language>
|
||||
<languages></languages>
|
||||
<fuse-fullscreen></fuse-fullscreen>
|
||||
<search [appearance]="'bar'"></search>
|
||||
<shortcuts [shortcuts]="data.shortcuts"></shortcuts>
|
||||
<messages [messages]="data.messages"></messages>
|
||||
<notifications [notifications]="data.notifications"></notifications>
|
||||
<user-menu></user-menu>
|
||||
<shortcuts></shortcuts>
|
||||
<messages></messages>
|
||||
<notifications></notifications>
|
||||
<user></user>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
import { Component, OnDestroy, OnInit, ViewEncapsulation } from '@angular/core';
|
||||
import { ActivatedRoute, Data, Router } from '@angular/router';
|
||||
import { ActivatedRoute, Router } from '@angular/router';
|
||||
import { Subject } from 'rxjs';
|
||||
import { takeUntil } from 'rxjs/operators';
|
||||
import { FuseMediaWatcherService } from '@fuse/services/media-watcher';
|
||||
import { FuseNavigationService, FuseVerticalNavigationComponent } from '@fuse/components/navigation';
|
||||
import { InitialData } from 'app/app.types';
|
||||
import { Navigation } from 'app/core/navigation/navigation.types';
|
||||
import { NavigationService } from 'app/core/navigation/navigation.service';
|
||||
|
||||
@Component({
|
||||
selector : 'modern-layout',
|
||||
@@ -13,8 +14,8 @@ import { InitialData } from 'app/app.types';
|
||||
})
|
||||
export class ModernLayoutComponent implements OnInit, OnDestroy
|
||||
{
|
||||
data: InitialData;
|
||||
isScreenSmall: boolean;
|
||||
navigation: Navigation;
|
||||
private _unsubscribeAll: Subject<any> = new Subject<any>();
|
||||
|
||||
/**
|
||||
@@ -23,6 +24,7 @@ export class ModernLayoutComponent implements OnInit, OnDestroy
|
||||
constructor(
|
||||
private _activatedRoute: ActivatedRoute,
|
||||
private _router: Router,
|
||||
private _navigationService: NavigationService,
|
||||
private _fuseMediaWatcherService: FuseMediaWatcherService,
|
||||
private _fuseNavigationService: FuseNavigationService
|
||||
)
|
||||
@@ -50,10 +52,12 @@ export class ModernLayoutComponent implements OnInit, OnDestroy
|
||||
*/
|
||||
ngOnInit(): void
|
||||
{
|
||||
// Subscribe to the resolved route data
|
||||
this._activatedRoute.data.subscribe((data: Data) => {
|
||||
this.data = data.initialData;
|
||||
});
|
||||
// Subscribe to navigation data
|
||||
this._navigationService.navigation$
|
||||
.pipe(takeUntil(this._unsubscribeAll))
|
||||
.subscribe((navigation: Navigation) => {
|
||||
this.navigation = navigation;
|
||||
});
|
||||
|
||||
// Subscribe to media changes
|
||||
this._fuseMediaWatcherService.onMediaChange$
|
||||
|
||||
@@ -7,12 +7,12 @@ 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 { LanguagesModule } from 'app/layout/common/languages/languages.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';
|
||||
import { ShortcutsModule } from 'app/layout/common/shortcuts/shortcuts.module';
|
||||
import { UserMenuModule } from 'app/layout/common/user-menu/user-menu.module';
|
||||
import { UserModule } from 'app/layout/common/user/user.module';
|
||||
import { SharedModule } from 'app/shared/shared.module';
|
||||
import { ModernLayoutComponent } from 'app/layout/layouts/horizontal/modern/modern.component';
|
||||
|
||||
@@ -29,12 +29,12 @@ import { ModernLayoutComponent } from 'app/layout/layouts/horizontal/modern/mode
|
||||
MatMenuModule,
|
||||
FuseFullscreenModule,
|
||||
FuseNavigationModule,
|
||||
LanguageModule,
|
||||
LanguagesModule,
|
||||
MessagesModule,
|
||||
NotificationsModule,
|
||||
SearchModule,
|
||||
ShortcutsModule,
|
||||
UserMenuModule,
|
||||
UserModule,
|
||||
SharedModule
|
||||
],
|
||||
exports : [
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
class="dark bg-gray-900 print:hidden"
|
||||
[mode]="isScreenSmall ? 'over' : 'side'"
|
||||
[name]="'mainNavigation'"
|
||||
[navigation]="data.navigation.default"
|
||||
[navigation]="navigation.default"
|
||||
[opened]="!isScreenSmall">
|
||||
<!-- Navigation header hook -->
|
||||
<ng-container fuseVerticalNavigationContentHeader>
|
||||
@@ -36,13 +36,13 @@
|
||||
</button>
|
||||
<!-- Components -->
|
||||
<div class="flex items-center pl-2 ml-auto space-x-2">
|
||||
<language></language>
|
||||
<languages></languages>
|
||||
<fuse-fullscreen></fuse-fullscreen>
|
||||
<search [appearance]="'bar'"></search>
|
||||
<shortcuts [shortcuts]="data.shortcuts"></shortcuts>
|
||||
<messages [messages]="data.messages"></messages>
|
||||
<notifications [notifications]="data.notifications"></notifications>
|
||||
<user-menu></user-menu>
|
||||
<shortcuts></shortcuts>
|
||||
<messages></messages>
|
||||
<notifications></notifications>
|
||||
<user></user>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
import { Component, OnDestroy, OnInit, ViewEncapsulation } from '@angular/core';
|
||||
import { ActivatedRoute, Data, Router } from '@angular/router';
|
||||
import { ActivatedRoute, Router } from '@angular/router';
|
||||
import { Subject } from 'rxjs';
|
||||
import { takeUntil } from 'rxjs/operators';
|
||||
import { FuseMediaWatcherService } from '@fuse/services/media-watcher';
|
||||
import { FuseNavigationService, FuseVerticalNavigationComponent } from '@fuse/components/navigation';
|
||||
import { InitialData } from 'app/app.types';
|
||||
import { Navigation } from 'app/core/navigation/navigation.types';
|
||||
import { NavigationService } from 'app/core/navigation/navigation.service';
|
||||
|
||||
@Component({
|
||||
selector : 'classic-layout',
|
||||
@@ -13,8 +14,8 @@ import { InitialData } from 'app/app.types';
|
||||
})
|
||||
export class ClassicLayoutComponent implements OnInit, OnDestroy
|
||||
{
|
||||
data: InitialData;
|
||||
isScreenSmall: boolean;
|
||||
navigation: Navigation;
|
||||
private _unsubscribeAll: Subject<any> = new Subject<any>();
|
||||
|
||||
/**
|
||||
@@ -23,6 +24,7 @@ export class ClassicLayoutComponent implements OnInit, OnDestroy
|
||||
constructor(
|
||||
private _activatedRoute: ActivatedRoute,
|
||||
private _router: Router,
|
||||
private _navigationService: NavigationService,
|
||||
private _fuseMediaWatcherService: FuseMediaWatcherService,
|
||||
private _fuseNavigationService: FuseNavigationService
|
||||
)
|
||||
@@ -50,10 +52,12 @@ export class ClassicLayoutComponent implements OnInit, OnDestroy
|
||||
*/
|
||||
ngOnInit(): void
|
||||
{
|
||||
// Subscribe to the resolved route data
|
||||
this._activatedRoute.data.subscribe((data: Data) => {
|
||||
this.data = data.initialData;
|
||||
});
|
||||
// Subscribe to navigation data
|
||||
this._navigationService.navigation$
|
||||
.pipe(takeUntil(this._unsubscribeAll))
|
||||
.subscribe((navigation: Navigation) => {
|
||||
this.navigation = navigation;
|
||||
});
|
||||
|
||||
// Subscribe to media changes
|
||||
this._fuseMediaWatcherService.onMediaChange$
|
||||
|
||||
@@ -7,12 +7,12 @@ 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 { LanguagesModule } from 'app/layout/common/languages/languages.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';
|
||||
import { ShortcutsModule } from 'app/layout/common/shortcuts/shortcuts.module';
|
||||
import { UserMenuModule } from 'app/layout/common/user-menu/user-menu.module';
|
||||
import { UserModule } from 'app/layout/common/user/user.module';
|
||||
import { SharedModule } from 'app/shared/shared.module';
|
||||
import { ClassicLayoutComponent } from 'app/layout/layouts/vertical/classic/classic.component';
|
||||
|
||||
@@ -29,12 +29,12 @@ import { ClassicLayoutComponent } from 'app/layout/layouts/vertical/classic/clas
|
||||
MatMenuModule,
|
||||
FuseFullscreenModule,
|
||||
FuseNavigationModule,
|
||||
LanguageModule,
|
||||
LanguagesModule,
|
||||
MessagesModule,
|
||||
NotificationsModule,
|
||||
SearchModule,
|
||||
ShortcutsModule,
|
||||
UserMenuModule,
|
||||
UserModule,
|
||||
SharedModule
|
||||
],
|
||||
exports : [
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
class="dark bg-gray-900 print:hidden"
|
||||
[mode]="isScreenSmall ? 'over' : 'side'"
|
||||
[name]="'mainNavigation'"
|
||||
[navigation]="data.navigation.default"
|
||||
[navigation]="navigation.default"
|
||||
[opened]="!isScreenSmall">
|
||||
<!-- Navigation header hook -->
|
||||
<ng-container fuseVerticalNavigationContentHeader>
|
||||
@@ -16,8 +16,8 @@
|
||||
</div>
|
||||
<!-- Components -->
|
||||
<div class="flex items-center ml-auto">
|
||||
<notifications [notifications]="data.notifications"></notifications>
|
||||
<user-menu [showAvatar]="false"></user-menu>
|
||||
<notifications></notifications>
|
||||
<user [showAvatar]="false"></user>
|
||||
</div>
|
||||
</div>
|
||||
<!-- User -->
|
||||
@@ -25,20 +25,20 @@
|
||||
<div class="relative w-24 h-24">
|
||||
<img
|
||||
class="w-full h-full rounded-full"
|
||||
*ngIf="data.user.avatar"
|
||||
[src]="data.user.avatar"
|
||||
*ngIf="user.avatar"
|
||||
[src]="user.avatar"
|
||||
alt="User avatar">
|
||||
<mat-icon
|
||||
class="icon-size-24"
|
||||
*ngIf="!data.user.avatar"
|
||||
*ngIf="!user.avatar"
|
||||
[svgIcon]="'heroicons_solid:user-circle'"></mat-icon>
|
||||
</div>
|
||||
<div class="flex flex-col items-center justify-center w-full mt-6">
|
||||
<div class="w-full whitespace-nowrap overflow-ellipsis overflow-hidden text-center leading-normal font-medium">
|
||||
{{data.user.name}}
|
||||
{{user.name}}
|
||||
</div>
|
||||
<div class="w-full mt-0.5 whitespace-nowrap overflow-ellipsis overflow-hidden text-center text-md leading-normal font-medium text-secondary">
|
||||
{{data.user.email}}
|
||||
{{user.email}}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -66,11 +66,11 @@
|
||||
</button>
|
||||
<!-- Components -->
|
||||
<div class="flex items-center pl-2 ml-auto space-x-2">
|
||||
<language></language>
|
||||
<languages></languages>
|
||||
<fuse-fullscreen></fuse-fullscreen>
|
||||
<search [appearance]="'bar'"></search>
|
||||
<shortcuts [shortcuts]="data.shortcuts"></shortcuts>
|
||||
<messages [messages]="data.messages"></messages>
|
||||
<shortcuts></shortcuts>
|
||||
<messages></messages>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -1,10 +1,13 @@
|
||||
import { Component, OnDestroy, OnInit, ViewEncapsulation } from '@angular/core';
|
||||
import { ActivatedRoute, Data, Router } from '@angular/router';
|
||||
import { ActivatedRoute, Router } from '@angular/router';
|
||||
import { Subject } from 'rxjs';
|
||||
import { takeUntil } from 'rxjs/operators';
|
||||
import { FuseMediaWatcherService } from '@fuse/services/media-watcher';
|
||||
import { FuseNavigationService, FuseVerticalNavigationComponent } from '@fuse/components/navigation';
|
||||
import { InitialData } from 'app/app.types';
|
||||
import { Navigation } from 'app/core/navigation/navigation.types';
|
||||
import { NavigationService } from 'app/core/navigation/navigation.service';
|
||||
import { User } from 'app/core/user/user.types';
|
||||
import { UserService } from 'app/core/user/user.service';
|
||||
|
||||
@Component({
|
||||
selector : 'classy-layout',
|
||||
@@ -13,8 +16,9 @@ import { InitialData } from 'app/app.types';
|
||||
})
|
||||
export class ClassyLayoutComponent implements OnInit, OnDestroy
|
||||
{
|
||||
data: InitialData;
|
||||
isScreenSmall: boolean;
|
||||
navigation: Navigation;
|
||||
user: User;
|
||||
private _unsubscribeAll: Subject<any> = new Subject<any>();
|
||||
|
||||
/**
|
||||
@@ -23,6 +27,8 @@ export class ClassyLayoutComponent implements OnInit, OnDestroy
|
||||
constructor(
|
||||
private _activatedRoute: ActivatedRoute,
|
||||
private _router: Router,
|
||||
private _navigationService: NavigationService,
|
||||
private _userService: UserService,
|
||||
private _fuseMediaWatcherService: FuseMediaWatcherService,
|
||||
private _fuseNavigationService: FuseNavigationService
|
||||
)
|
||||
@@ -50,10 +56,19 @@ export class ClassyLayoutComponent implements OnInit, OnDestroy
|
||||
*/
|
||||
ngOnInit(): void
|
||||
{
|
||||
// Subscribe to the resolved route data
|
||||
this._activatedRoute.data.subscribe((data: Data) => {
|
||||
this.data = data.initialData;
|
||||
});
|
||||
// Subscribe to navigation data
|
||||
this._navigationService.navigation$
|
||||
.pipe(takeUntil(this._unsubscribeAll))
|
||||
.subscribe((navigation: Navigation) => {
|
||||
this.navigation = navigation;
|
||||
});
|
||||
|
||||
// Subscribe to the user service
|
||||
this._userService.user$
|
||||
.pipe((takeUntil(this._unsubscribeAll)))
|
||||
.subscribe((user: User) => {
|
||||
this.user = user;
|
||||
});
|
||||
|
||||
// Subscribe to media changes
|
||||
this._fuseMediaWatcherService.onMediaChange$
|
||||
|
||||
@@ -7,12 +7,12 @@ 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 { LanguagesModule } from 'app/layout/common/languages/languages.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';
|
||||
import { ShortcutsModule } from 'app/layout/common/shortcuts/shortcuts.module';
|
||||
import { UserMenuModule } from 'app/layout/common/user-menu/user-menu.module';
|
||||
import { UserModule } from 'app/layout/common/user/user.module';
|
||||
import { SharedModule } from 'app/shared/shared.module';
|
||||
import { ClassyLayoutComponent } from 'app/layout/layouts/vertical/classy/classy.component';
|
||||
|
||||
@@ -29,12 +29,12 @@ import { ClassyLayoutComponent } from 'app/layout/layouts/vertical/classy/classy
|
||||
MatMenuModule,
|
||||
FuseFullscreenModule,
|
||||
FuseNavigationModule,
|
||||
LanguageModule,
|
||||
LanguagesModule,
|
||||
MessagesModule,
|
||||
NotificationsModule,
|
||||
SearchModule,
|
||||
ShortcutsModule,
|
||||
UserMenuModule,
|
||||
UserModule,
|
||||
SharedModule
|
||||
],
|
||||
exports : [
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
[appearance]="'compact'"
|
||||
[mode]="isScreenSmall ? 'over' : 'side'"
|
||||
[name]="'mainNavigation'"
|
||||
[navigation]="data.navigation.compact"
|
||||
[navigation]="navigation.compact"
|
||||
[opened]="!isScreenSmall">
|
||||
<!-- Navigation header hook -->
|
||||
<ng-container fuseVerticalNavigationContentHeader>
|
||||
@@ -31,13 +31,13 @@
|
||||
</button>
|
||||
<!-- Components -->
|
||||
<div class="flex items-center pl-2 ml-auto space-x-2">
|
||||
<language></language>
|
||||
<languages></languages>
|
||||
<fuse-fullscreen></fuse-fullscreen>
|
||||
<search [appearance]="'bar'"></search>
|
||||
<shortcuts [shortcuts]="data.shortcuts"></shortcuts>
|
||||
<messages [messages]="data.messages"></messages>
|
||||
<notifications [notifications]="data.notifications"></notifications>
|
||||
<user-menu></user-menu>
|
||||
<shortcuts></shortcuts>
|
||||
<messages></messages>
|
||||
<notifications></notifications>
|
||||
<user></user>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
import { Component, OnDestroy, OnInit, ViewEncapsulation } from '@angular/core';
|
||||
import { ActivatedRoute, Data, Router } from '@angular/router';
|
||||
import { ActivatedRoute, Router } from '@angular/router';
|
||||
import { Subject } from 'rxjs';
|
||||
import { takeUntil } from 'rxjs/operators';
|
||||
import { FuseMediaWatcherService } from '@fuse/services/media-watcher';
|
||||
import { FuseNavigationService, FuseVerticalNavigationComponent } from '@fuse/components/navigation';
|
||||
import { InitialData } from 'app/app.types';
|
||||
import { Navigation } from 'app/core/navigation/navigation.types';
|
||||
import { NavigationService } from 'app/core/navigation/navigation.service';
|
||||
|
||||
@Component({
|
||||
selector : 'compact-layout',
|
||||
@@ -13,8 +14,8 @@ import { InitialData } from 'app/app.types';
|
||||
})
|
||||
export class CompactLayoutComponent implements OnInit, OnDestroy
|
||||
{
|
||||
data: InitialData;
|
||||
isScreenSmall: boolean;
|
||||
navigation: Navigation;
|
||||
private _unsubscribeAll: Subject<any> = new Subject<any>();
|
||||
|
||||
/**
|
||||
@@ -23,6 +24,7 @@ export class CompactLayoutComponent implements OnInit, OnDestroy
|
||||
constructor(
|
||||
private _activatedRoute: ActivatedRoute,
|
||||
private _router: Router,
|
||||
private _navigationService: NavigationService,
|
||||
private _fuseMediaWatcherService: FuseMediaWatcherService,
|
||||
private _fuseNavigationService: FuseNavigationService
|
||||
)
|
||||
@@ -50,10 +52,12 @@ export class CompactLayoutComponent implements OnInit, OnDestroy
|
||||
*/
|
||||
ngOnInit(): void
|
||||
{
|
||||
// Subscribe to the resolved route data
|
||||
this._activatedRoute.data.subscribe((data: Data) => {
|
||||
this.data = data.initialData;
|
||||
});
|
||||
// Subscribe to navigation data
|
||||
this._navigationService.navigation$
|
||||
.pipe(takeUntil(this._unsubscribeAll))
|
||||
.subscribe((navigation: Navigation) => {
|
||||
this.navigation = navigation;
|
||||
});
|
||||
|
||||
// Subscribe to media changes
|
||||
this._fuseMediaWatcherService.onMediaChange$
|
||||
|
||||
@@ -7,12 +7,12 @@ 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 { LanguagesModule } from 'app/layout/common/languages/languages.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';
|
||||
import { ShortcutsModule } from 'app/layout/common/shortcuts/shortcuts.module';
|
||||
import { UserMenuModule } from 'app/layout/common/user-menu/user-menu.module';
|
||||
import { UserModule } from 'app/layout/common/user/user.module';
|
||||
import { SharedModule } from 'app/shared/shared.module';
|
||||
import { CompactLayoutComponent } from 'app/layout/layouts/vertical/compact/compact.component';
|
||||
|
||||
@@ -29,12 +29,12 @@ import { CompactLayoutComponent } from 'app/layout/layouts/vertical/compact/comp
|
||||
MatMenuModule,
|
||||
FuseFullscreenModule,
|
||||
FuseNavigationModule,
|
||||
LanguageModule,
|
||||
LanguagesModule,
|
||||
MessagesModule,
|
||||
NotificationsModule,
|
||||
SearchModule,
|
||||
ShortcutsModule,
|
||||
UserMenuModule,
|
||||
UserModule,
|
||||
SharedModule
|
||||
],
|
||||
exports : [
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
[appearance]="navigationAppearance"
|
||||
[mode]="isScreenSmall ? 'over' : 'side'"
|
||||
[name]="'mainNavigation'"
|
||||
[navigation]="data.navigation.default"
|
||||
[navigation]="navigation.default"
|
||||
[opened]="!isScreenSmall">
|
||||
<!-- Navigation header hook -->
|
||||
<ng-container fuseVerticalNavigationContentHeader>
|
||||
@@ -40,13 +40,13 @@
|
||||
</div>
|
||||
<!-- Components -->
|
||||
<div class="flex items-center pl-2 ml-auto space-x-2">
|
||||
<language></language>
|
||||
<languages></languages>
|
||||
<fuse-fullscreen></fuse-fullscreen>
|
||||
<search [appearance]="'bar'"></search>
|
||||
<shortcuts [shortcuts]="data.shortcuts"></shortcuts>
|
||||
<messages [messages]="data.messages"></messages>
|
||||
<notifications [notifications]="data.notifications"></notifications>
|
||||
<user-menu></user-menu>
|
||||
<shortcuts></shortcuts>
|
||||
<messages></messages>
|
||||
<notifications></notifications>
|
||||
<user></user>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
import { Component, OnDestroy, OnInit, ViewEncapsulation } from '@angular/core';
|
||||
import { ActivatedRoute, Data, Router } from '@angular/router';
|
||||
import { ActivatedRoute, Router } from '@angular/router';
|
||||
import { Subject } from 'rxjs';
|
||||
import { takeUntil } from 'rxjs/operators';
|
||||
import { FuseMediaWatcherService } from '@fuse/services/media-watcher';
|
||||
import { FuseNavigationService, FuseVerticalNavigationComponent } from '@fuse/components/navigation';
|
||||
import { InitialData } from 'app/app.types';
|
||||
import { Navigation } from 'app/core/navigation/navigation.types';
|
||||
import { NavigationService } from 'app/core/navigation/navigation.service';
|
||||
|
||||
@Component({
|
||||
selector : 'dense-layout',
|
||||
@@ -13,8 +14,8 @@ import { InitialData } from 'app/app.types';
|
||||
})
|
||||
export class DenseLayoutComponent implements OnInit, OnDestroy
|
||||
{
|
||||
data: InitialData;
|
||||
isScreenSmall: boolean;
|
||||
navigation: Navigation;
|
||||
navigationAppearance: 'default' | 'dense' = 'dense';
|
||||
private _unsubscribeAll: Subject<any> = new Subject<any>();
|
||||
|
||||
@@ -24,6 +25,7 @@ export class DenseLayoutComponent implements OnInit, OnDestroy
|
||||
constructor(
|
||||
private _activatedRoute: ActivatedRoute,
|
||||
private _router: Router,
|
||||
private _navigationService: NavigationService,
|
||||
private _fuseMediaWatcherService: FuseMediaWatcherService,
|
||||
private _fuseNavigationService: FuseNavigationService
|
||||
)
|
||||
@@ -51,10 +53,12 @@ export class DenseLayoutComponent implements OnInit, OnDestroy
|
||||
*/
|
||||
ngOnInit(): void
|
||||
{
|
||||
// Subscribe to the resolved route data
|
||||
this._activatedRoute.data.subscribe((data: Data) => {
|
||||
this.data = data.initialData;
|
||||
});
|
||||
// Subscribe to navigation data
|
||||
this._navigationService.navigation$
|
||||
.pipe(takeUntil(this._unsubscribeAll))
|
||||
.subscribe((navigation: Navigation) => {
|
||||
this.navigation = navigation;
|
||||
});
|
||||
|
||||
// Subscribe to media changes
|
||||
this._fuseMediaWatcherService.onMediaChange$
|
||||
|
||||
@@ -7,12 +7,12 @@ 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 { LanguagesModule } from 'app/layout/common/languages/languages.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';
|
||||
import { ShortcutsModule } from 'app/layout/common/shortcuts/shortcuts.module';
|
||||
import { UserMenuModule } from 'app/layout/common/user-menu/user-menu.module';
|
||||
import { UserModule } from 'app/layout/common/user/user.module';
|
||||
import { SharedModule } from 'app/shared/shared.module';
|
||||
import { DenseLayoutComponent } from 'app/layout/layouts/vertical/dense/dense.component';
|
||||
|
||||
@@ -29,12 +29,12 @@ import { DenseLayoutComponent } from 'app/layout/layouts/vertical/dense/dense.co
|
||||
MatMenuModule,
|
||||
FuseFullscreenModule,
|
||||
FuseNavigationModule,
|
||||
LanguageModule,
|
||||
LanguagesModule,
|
||||
MessagesModule,
|
||||
NotificationsModule,
|
||||
SearchModule,
|
||||
ShortcutsModule,
|
||||
UserMenuModule,
|
||||
UserModule,
|
||||
SharedModule
|
||||
],
|
||||
exports : [
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
class="dark bg-indigo-800 text-white print:hidden"
|
||||
[mode]="isScreenSmall ? 'over' : 'side'"
|
||||
[name]="'mainNavigation'"
|
||||
[navigation]="data.navigation.futuristic"
|
||||
[navigation]="navigation.futuristic"
|
||||
[opened]="!isScreenSmall">
|
||||
<!-- Navigation header hook -->
|
||||
<ng-container fuseVerticalNavigationHeader>
|
||||
@@ -18,10 +18,10 @@
|
||||
<ng-container fuseVerticalNavigationFooter>
|
||||
<!-- User -->
|
||||
<div class="flex items-center w-full px-6 py-8 border-t">
|
||||
<user-menu></user-menu>
|
||||
<user></user>
|
||||
<div class="flex flex-col w-full ml-4 overflow-hidden">
|
||||
<div class="w-full whitespace-nowrap overflow-ellipsis overflow-hidden leading-normal text-current opacity-80">
|
||||
{{data.user.name}}
|
||||
{{user.name}}
|
||||
</div>
|
||||
<div class="w-full mt-0.5 whitespace-nowrap text-sm overflow-ellipsis overflow-hidden leading-normal text-current opacity-50">
|
||||
brian.hughes@company.com
|
||||
@@ -45,12 +45,12 @@
|
||||
</button>
|
||||
<!-- Components -->
|
||||
<div class="flex items-center pl-2 ml-auto space-x-2">
|
||||
<language></language>
|
||||
<languages></languages>
|
||||
<fuse-fullscreen></fuse-fullscreen>
|
||||
<search [appearance]="'bar'"></search>
|
||||
<shortcuts [shortcuts]="data.shortcuts"></shortcuts>
|
||||
<messages [messages]="data.messages"></messages>
|
||||
<notifications [notifications]="data.notifications"></notifications>
|
||||
<shortcuts></shortcuts>
|
||||
<messages></messages>
|
||||
<notifications></notifications>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -1,10 +1,13 @@
|
||||
import { Component, OnDestroy, OnInit, ViewEncapsulation } from '@angular/core';
|
||||
import { ActivatedRoute, Data, Router } from '@angular/router';
|
||||
import { ActivatedRoute, Router } from '@angular/router';
|
||||
import { Subject } from 'rxjs';
|
||||
import { takeUntil } from 'rxjs/operators';
|
||||
import { FuseMediaWatcherService } from '@fuse/services/media-watcher';
|
||||
import { FuseNavigationService, FuseVerticalNavigationComponent } from '@fuse/components/navigation';
|
||||
import { InitialData } from 'app/app.types';
|
||||
import { Navigation } from 'app/core/navigation/navigation.types';
|
||||
import { NavigationService } from 'app/core/navigation/navigation.service';
|
||||
import { User } from 'app/core/user/user.types';
|
||||
import { UserService } from 'app/core/user/user.service';
|
||||
|
||||
@Component({
|
||||
selector : 'futuristic-layout',
|
||||
@@ -13,8 +16,9 @@ import { InitialData } from 'app/app.types';
|
||||
})
|
||||
export class FuturisticLayoutComponent implements OnInit, OnDestroy
|
||||
{
|
||||
data: InitialData;
|
||||
isScreenSmall: boolean;
|
||||
navigation: Navigation;
|
||||
user: User;
|
||||
private _unsubscribeAll: Subject<any> = new Subject<any>();
|
||||
|
||||
/**
|
||||
@@ -23,6 +27,8 @@ export class FuturisticLayoutComponent implements OnInit, OnDestroy
|
||||
constructor(
|
||||
private _activatedRoute: ActivatedRoute,
|
||||
private _router: Router,
|
||||
private _navigationService: NavigationService,
|
||||
private _userService: UserService,
|
||||
private _fuseMediaWatcherService: FuseMediaWatcherService,
|
||||
private _fuseNavigationService: FuseNavigationService
|
||||
)
|
||||
@@ -50,10 +56,19 @@ export class FuturisticLayoutComponent implements OnInit, OnDestroy
|
||||
*/
|
||||
ngOnInit(): void
|
||||
{
|
||||
// Subscribe to the resolved route data
|
||||
this._activatedRoute.data.subscribe((data: Data) => {
|
||||
this.data = data.initialData;
|
||||
});
|
||||
// Subscribe to navigation data
|
||||
this._navigationService.navigation$
|
||||
.pipe(takeUntil(this._unsubscribeAll))
|
||||
.subscribe((navigation: Navigation) => {
|
||||
this.navigation = navigation;
|
||||
});
|
||||
|
||||
// Subscribe to the user service
|
||||
this._userService.user$
|
||||
.pipe((takeUntil(this._unsubscribeAll)))
|
||||
.subscribe((user: User) => {
|
||||
this.user = user;
|
||||
});
|
||||
|
||||
// Subscribe to media changes
|
||||
this._fuseMediaWatcherService.onMediaChange$
|
||||
|
||||
@@ -7,12 +7,12 @@ 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 { LanguagesModule } from 'app/layout/common/languages/languages.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';
|
||||
import { ShortcutsModule } from 'app/layout/common/shortcuts/shortcuts.module';
|
||||
import { UserMenuModule } from 'app/layout/common/user-menu/user-menu.module';
|
||||
import { UserModule } from 'app/layout/common/user/user.module';
|
||||
import { SharedModule } from 'app/shared/shared.module';
|
||||
import { FuturisticLayoutComponent } from 'app/layout/layouts/vertical/futuristic/futuristic.component';
|
||||
|
||||
@@ -29,12 +29,12 @@ import { FuturisticLayoutComponent } from 'app/layout/layouts/vertical/futuristi
|
||||
MatMenuModule,
|
||||
FuseFullscreenModule,
|
||||
FuseNavigationModule,
|
||||
LanguageModule,
|
||||
LanguagesModule,
|
||||
MessagesModule,
|
||||
NotificationsModule,
|
||||
SearchModule,
|
||||
ShortcutsModule,
|
||||
UserMenuModule,
|
||||
UserModule,
|
||||
SharedModule
|
||||
],
|
||||
exports : [
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
[appearance]="'thin'"
|
||||
[mode]="isScreenSmall ? 'over' : 'side'"
|
||||
[name]="'mainNavigation'"
|
||||
[navigation]="data.navigation.compact"
|
||||
[navigation]="navigation.compact"
|
||||
[opened]="!isScreenSmall">
|
||||
<!-- Navigation header hook -->
|
||||
<ng-container fuseVerticalNavigationContentHeader>
|
||||
@@ -32,13 +32,13 @@
|
||||
</button>
|
||||
<!-- Components -->
|
||||
<div class="flex items-center pl-2 ml-auto space-x-2">
|
||||
<language></language>
|
||||
<languages></languages>
|
||||
<fuse-fullscreen></fuse-fullscreen>
|
||||
<search [appearance]="'bar'"></search>
|
||||
<shortcuts [shortcuts]="data.shortcuts"></shortcuts>
|
||||
<messages [messages]="data.messages"></messages>
|
||||
<notifications [notifications]="data.notifications"></notifications>
|
||||
<user-menu></user-menu>
|
||||
<shortcuts></shortcuts>
|
||||
<messages></messages>
|
||||
<notifications></notifications>
|
||||
<user></user>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
import { Component, OnDestroy, OnInit, ViewEncapsulation } from '@angular/core';
|
||||
import { ActivatedRoute, Data, Router } from '@angular/router';
|
||||
import { ActivatedRoute, Router } from '@angular/router';
|
||||
import { Subject } from 'rxjs';
|
||||
import { takeUntil } from 'rxjs/operators';
|
||||
import { FuseMediaWatcherService } from '@fuse/services/media-watcher';
|
||||
import { FuseNavigationService, FuseVerticalNavigationComponent } from '@fuse/components/navigation';
|
||||
import { InitialData } from 'app/app.types';
|
||||
import { Navigation } from 'app/core/navigation/navigation.types';
|
||||
import { NavigationService } from 'app/core/navigation/navigation.service';
|
||||
|
||||
@Component({
|
||||
selector : 'thin-layout',
|
||||
@@ -13,8 +14,8 @@ import { InitialData } from 'app/app.types';
|
||||
})
|
||||
export class ThinLayoutComponent implements OnInit, OnDestroy
|
||||
{
|
||||
data: InitialData;
|
||||
isScreenSmall: boolean;
|
||||
navigation: Navigation;
|
||||
private _unsubscribeAll: Subject<any> = new Subject<any>();
|
||||
|
||||
/**
|
||||
@@ -23,6 +24,7 @@ export class ThinLayoutComponent implements OnInit, OnDestroy
|
||||
constructor(
|
||||
private _activatedRoute: ActivatedRoute,
|
||||
private _router: Router,
|
||||
private _navigationService: NavigationService,
|
||||
private _fuseMediaWatcherService: FuseMediaWatcherService,
|
||||
private _fuseNavigationService: FuseNavigationService
|
||||
)
|
||||
@@ -50,10 +52,12 @@ export class ThinLayoutComponent implements OnInit, OnDestroy
|
||||
*/
|
||||
ngOnInit(): void
|
||||
{
|
||||
// Subscribe to the resolved route data
|
||||
this._activatedRoute.data.subscribe((data: Data) => {
|
||||
this.data = data.initialData;
|
||||
});
|
||||
// Subscribe to navigation data
|
||||
this._navigationService.navigation$
|
||||
.pipe(takeUntil(this._unsubscribeAll))
|
||||
.subscribe((navigation: Navigation) => {
|
||||
this.navigation = navigation;
|
||||
});
|
||||
|
||||
// Subscribe to media changes
|
||||
this._fuseMediaWatcherService.onMediaChange$
|
||||
|
||||
@@ -7,12 +7,12 @@ 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 { LanguagesModule } from 'app/layout/common/languages/languages.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';
|
||||
import { ShortcutsModule } from 'app/layout/common/shortcuts/shortcuts.module';
|
||||
import { UserMenuModule } from 'app/layout/common/user-menu/user-menu.module';
|
||||
import { UserModule } from 'app/layout/common/user/user.module';
|
||||
import { SharedModule } from 'app/shared/shared.module';
|
||||
import { ThinLayoutComponent } from 'app/layout/layouts/vertical/thin/thin.component';
|
||||
|
||||
@@ -29,12 +29,12 @@ import { ThinLayoutComponent } from 'app/layout/layouts/vertical/thin/thin.compo
|
||||
MatMenuModule,
|
||||
FuseFullscreenModule,
|
||||
FuseNavigationModule,
|
||||
LanguageModule,
|
||||
LanguagesModule,
|
||||
MessagesModule,
|
||||
NotificationsModule,
|
||||
SearchModule,
|
||||
ShortcutsModule,
|
||||
UserMenuModule,
|
||||
UserModule,
|
||||
SharedModule
|
||||
],
|
||||
exports : [
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -33,10 +33,18 @@ export class FileManagerMockApi
|
||||
// -----------------------------------------------------------------------------------------------------
|
||||
this._fuseMockApiService
|
||||
.onGet('api/apps/file-manager')
|
||||
.reply(() => {
|
||||
.reply(({request}) => {
|
||||
|
||||
// Clone the items
|
||||
const items = cloneDeep(this._items);
|
||||
let items = cloneDeep(this._items);
|
||||
|
||||
// See if a folder id exist
|
||||
const folderId = request.params.get('folderId') ?? null;
|
||||
|
||||
// Filter the items by folder id. If folder id is null,
|
||||
// that means we want to root items which have folder id
|
||||
// of null
|
||||
items = items.filter(item => item.folderId === folderId);
|
||||
|
||||
// Separate the items by folders and files
|
||||
const folders = items.filter(item => item.type === 'folder');
|
||||
@@ -46,11 +54,38 @@ export class FileManagerMockApi
|
||||
folders.sort((a, b) => a.name.localeCompare(b.name));
|
||||
files.sort((a, b) => a.name.localeCompare(b.name));
|
||||
|
||||
// Figure out the path and attach it to the response
|
||||
// Prepare the empty paths array
|
||||
const pathItems = cloneDeep(this._items);
|
||||
const path = [];
|
||||
|
||||
// Prepare the current folder
|
||||
let currentFolder = null;
|
||||
|
||||
// Get the current folder and add it as the first entry
|
||||
if ( folderId )
|
||||
{
|
||||
currentFolder = pathItems.find(item => item.id === folderId);
|
||||
path.push(currentFolder);
|
||||
}
|
||||
|
||||
// Start traversing and storing the folders as a path array
|
||||
// until we hit null on the folder id
|
||||
while ( currentFolder?.folderId )
|
||||
{
|
||||
currentFolder = pathItems.find(item => item.id === currentFolder.folderId);
|
||||
if ( currentFolder )
|
||||
{
|
||||
path.unshift(currentFolder);
|
||||
}
|
||||
}
|
||||
|
||||
return [
|
||||
200,
|
||||
{
|
||||
folders,
|
||||
files
|
||||
files,
|
||||
path
|
||||
}
|
||||
];
|
||||
});
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
export const items = [
|
||||
{
|
||||
id : 'cd6897cb-acfd-4016-8b53-3f66a5b5fc68',
|
||||
folderId : null,
|
||||
name : 'Personal',
|
||||
createdBy : 'Brian Hughes',
|
||||
createdAt : 'April 24, 2018',
|
||||
@@ -13,6 +14,7 @@ export const items = [
|
||||
},
|
||||
{
|
||||
id : '6da8747f-b474-4c9a-9eba-5ef212285500',
|
||||
folderId : null,
|
||||
name : 'Photos',
|
||||
createdBy : 'Brian Hughes',
|
||||
createdAt : 'November 01, 2021',
|
||||
@@ -24,6 +26,7 @@ export const items = [
|
||||
},
|
||||
{
|
||||
id : 'ed58add1-45a7-41db-887d-3ca7ee7f2719',
|
||||
folderId : null,
|
||||
name : 'Work',
|
||||
createdBy : 'Brian Hughes',
|
||||
createdAt : 'May 8, 2020',
|
||||
@@ -35,6 +38,7 @@ export const items = [
|
||||
},
|
||||
{
|
||||
id : '5cb66e32-d1ac-4b9a-8c34-5991ce25add2',
|
||||
folderId : null,
|
||||
name : 'Contract #123',
|
||||
createdBy : 'Brian Hughes',
|
||||
createdAt : 'January 14, 2021',
|
||||
@@ -46,6 +50,7 @@ export const items = [
|
||||
},
|
||||
{
|
||||
id : '3ffc3d84-8f2d-4929-903a-ef6fc21657a7',
|
||||
folderId : null,
|
||||
name : 'Estimated budget',
|
||||
createdBy : 'Brian Hughes',
|
||||
createdAt : 'December 14, 2020',
|
||||
@@ -57,6 +62,7 @@ export const items = [
|
||||
},
|
||||
{
|
||||
id : '157adb9a-14f8-4559-ac93-8be893c9f80a',
|
||||
folderId : null,
|
||||
name : 'DMCA notice #42',
|
||||
createdBy : 'Brian Hughes',
|
||||
createdAt : 'May 8, 2021',
|
||||
@@ -68,6 +74,7 @@ export const items = [
|
||||
},
|
||||
{
|
||||
id : '4f64597a-df7e-461c-ad60-f33e5f7e0747',
|
||||
folderId : null,
|
||||
name : 'Invoices',
|
||||
createdBy : 'Brian Hughes',
|
||||
createdAt : 'January 12, 2020',
|
||||
@@ -79,6 +86,7 @@ export const items = [
|
||||
},
|
||||
{
|
||||
id : 'e445c445-57b2-4476-8c62-b068e3774b8e',
|
||||
folderId : null,
|
||||
name : 'Crash logs',
|
||||
createdBy : 'Brian Hughes',
|
||||
createdAt : 'June 8, 2020',
|
||||
@@ -90,6 +98,7 @@ export const items = [
|
||||
},
|
||||
{
|
||||
id : 'b482f93e-7847-4614-ad48-b78b78309f81',
|
||||
folderId : null,
|
||||
name : 'System logs',
|
||||
createdBy : 'Brian Hughes',
|
||||
createdAt : 'June 8, 2020',
|
||||
@@ -101,6 +110,7 @@ export const items = [
|
||||
},
|
||||
{
|
||||
id : 'ec07a98d-2e5b-422c-a9b2-b5d1c0e263f5',
|
||||
folderId : null,
|
||||
name : 'Personal projects',
|
||||
createdBy : 'Brian Hughes',
|
||||
createdAt : 'March 18, 2020',
|
||||
@@ -112,6 +122,7 @@ export const items = [
|
||||
},
|
||||
{
|
||||
id : 'ae908d59-07da-4dd8-aba0-124e50289295',
|
||||
folderId : null,
|
||||
name : 'Biometric portrait',
|
||||
createdBy : 'Brian Hughes',
|
||||
createdAt : 'August 29, 2020',
|
||||
@@ -123,6 +134,7 @@ export const items = [
|
||||
},
|
||||
{
|
||||
id : '4038a5b6-5b1a-432d-907c-e037aeb817a8',
|
||||
folderId : null,
|
||||
name : 'Scanned image 20201012-1',
|
||||
createdBy : 'Brian Hughes',
|
||||
createdAt : 'September 13, 2020',
|
||||
@@ -134,6 +146,7 @@ export const items = [
|
||||
},
|
||||
{
|
||||
id : '630d2e9a-d110-47a0-ac03-256073a0f56d',
|
||||
folderId : null,
|
||||
name : 'Scanned image 20201012-2',
|
||||
createdBy : 'Brian Hughes',
|
||||
createdAt : 'September 14, 2020',
|
||||
@@ -145,6 +158,7 @@ export const items = [
|
||||
},
|
||||
{
|
||||
id : '1417d5ed-b616-4cff-bfab-286677b69d79',
|
||||
folderId : null,
|
||||
name : 'Prices',
|
||||
createdBy : 'Brian Hughes',
|
||||
createdAt : 'April 07, 2020',
|
||||
@@ -156,6 +170,7 @@ export const items = [
|
||||
},
|
||||
{
|
||||
id : 'bd2817c7-6751-40dc-b252-b6b5634c0689',
|
||||
folderId : null,
|
||||
name : 'Shopping list',
|
||||
createdBy : 'Brian Hughes',
|
||||
createdAt : 'March 26, 2021',
|
||||
@@ -167,6 +182,7 @@ export const items = [
|
||||
},
|
||||
{
|
||||
id : '14fb47c9-6eeb-4070-919c-07c8133285d1',
|
||||
folderId : null,
|
||||
name : 'Summer budget',
|
||||
createdBy : 'Brian Hughes',
|
||||
createdAt : 'June 02, 2020',
|
||||
@@ -175,5 +191,67 @@ export const items = [
|
||||
type : 'XLS',
|
||||
contents : null,
|
||||
description: null
|
||||
},
|
||||
|
||||
{
|
||||
id : '894e8514-03d3-4f5e-bb28-f6c092501fae',
|
||||
folderId : 'cd6897cb-acfd-4016-8b53-3f66a5b5fc68',
|
||||
name : 'A personal file',
|
||||
createdBy : 'Brian Hughes',
|
||||
createdAt : 'June 02, 2020',
|
||||
modifiedAt : 'June 02, 2020',
|
||||
size : '943 KB',
|
||||
type : 'XLS',
|
||||
contents : null,
|
||||
description: null
|
||||
},
|
||||
{
|
||||
id : '74010810-16cf-441d-a1aa-c9fb620fceea',
|
||||
folderId : 'cd6897cb-acfd-4016-8b53-3f66a5b5fc68',
|
||||
name : 'A personal folder',
|
||||
createdBy : 'Brian Hughes',
|
||||
createdAt : 'November 01, 2021',
|
||||
modifiedAt : 'November 01, 2021',
|
||||
size : '3015 MB',
|
||||
type : 'folder',
|
||||
contents : '907 files',
|
||||
description: 'Personal photos; selfies, family, vacation and etc.'
|
||||
},
|
||||
{
|
||||
id : 'a8c73e5a-8114-436d-ab54-d900b50b3762',
|
||||
folderId : '74010810-16cf-441d-a1aa-c9fb620fceea',
|
||||
name : 'A personal file within the personal folder',
|
||||
createdBy : 'Brian Hughes',
|
||||
createdAt : 'June 02, 2020',
|
||||
modifiedAt : 'June 02, 2020',
|
||||
size : '943 KB',
|
||||
type : 'XLS',
|
||||
contents : null,
|
||||
description: null
|
||||
},
|
||||
|
||||
{
|
||||
id : '12d851a8-4f60-473e-8a59-abe4b422ea99',
|
||||
folderId : '6da8747f-b474-4c9a-9eba-5ef212285500',
|
||||
name : 'Photos file',
|
||||
createdBy : 'Brian Hughes',
|
||||
createdAt : 'June 02, 2020',
|
||||
modifiedAt : 'June 02, 2020',
|
||||
size : '943 KB',
|
||||
type : 'XLS',
|
||||
contents : null,
|
||||
description: null
|
||||
},
|
||||
{
|
||||
id : '2836766d-27e1-4f40-a31a-5a8419105e7e',
|
||||
folderId : 'ed58add1-45a7-41db-887d-3ca7ee7f2719',
|
||||
name : 'Work file',
|
||||
createdBy : 'Brian Hughes',
|
||||
createdAt : 'June 02, 2020',
|
||||
modifiedAt : 'June 02, 2020',
|
||||
size : '943 KB',
|
||||
type : 'XLS',
|
||||
contents : null,
|
||||
description: null
|
||||
}
|
||||
];
|
||||
|
||||
454
src/app/mock-api/apps/scrumboard/api.ts
Normal file
454
src/app/mock-api/apps/scrumboard/api.ts
Normal 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
|
||||
];
|
||||
});
|
||||
}
|
||||
}
|
||||
334
src/app/mock-api/apps/scrumboard/data.ts
Normal file
334
src/app/mock-api/apps/scrumboard/data.ts
Normal 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'
|
||||
}
|
||||
];
|
||||
@@ -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',
|
||||
|
||||
@@ -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'
|
||||
}
|
||||
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -590,7 +596,7 @@ export const defaultNavigation: FuseNavigationItem[] = [
|
||||
id : 'pages.invoice',
|
||||
title : 'Invoice',
|
||||
type : 'collapsable',
|
||||
icon : 'heroicons_outline:exclamation-circle',
|
||||
icon : 'heroicons_outline:calculator',
|
||||
children: [
|
||||
{
|
||||
id : 'pages.invoice.printable',
|
||||
@@ -677,9 +683,9 @@ export const defaultNavigation: FuseNavigationItem[] = [
|
||||
children: [
|
||||
{
|
||||
id : 'user-interface.angular-material',
|
||||
title: 'Angular Material',
|
||||
title: 'Angular Material components',
|
||||
type : 'basic',
|
||||
icon : 'heroicons_outline:shield-check',
|
||||
icon : 'heroicons_outline:chip',
|
||||
link : '/ui/angular-material'
|
||||
},
|
||||
{
|
||||
@@ -689,6 +695,13 @@ export const defaultNavigation: FuseNavigationItem[] = [
|
||||
icon : 'heroicons_outline:sparkles',
|
||||
link : '/ui/tailwindcss'
|
||||
},
|
||||
{
|
||||
id : 'user-interface.advanced-search',
|
||||
title: 'Advanced search',
|
||||
type : 'basic',
|
||||
icon : 'heroicons_outline:search-circle',
|
||||
link : '/ui/advanced-search'
|
||||
},
|
||||
{
|
||||
id : 'user-interface.animations',
|
||||
title: 'Animations',
|
||||
@@ -855,10 +868,16 @@ export const defaultNavigation: FuseNavigationItem[] = [
|
||||
type : 'collapsable',
|
||||
children: [
|
||||
{
|
||||
id : 'user-interface.page-layouts.simple.fullwidth',
|
||||
title: 'Fullwidth',
|
||||
id : 'user-interface.page-layouts.simple.fullwidth-1',
|
||||
title: 'Fullwidth #1',
|
||||
type : 'basic',
|
||||
link : '/ui/page-layouts/simple/fullwidth'
|
||||
link : '/ui/page-layouts/simple/fullwidth-1'
|
||||
},
|
||||
{
|
||||
id : 'user-interface.page-layouts.simple.fullwidth-2',
|
||||
title: 'Fullwidth #2',
|
||||
type : 'basic',
|
||||
link : '/ui/page-layouts/simple/fullwidth-2'
|
||||
},
|
||||
{
|
||||
id : 'user-interface.page-layouts.simple.left-sidebar-1',
|
||||
@@ -927,7 +946,7 @@ export const defaultNavigation: FuseNavigationItem[] = [
|
||||
icon : 'heroicons_outline:speakerphone',
|
||||
link : '/docs/changelog',
|
||||
badge: {
|
||||
title : '13.0.1',
|
||||
title : '13.1.0',
|
||||
classes: 'px-2 bg-yellow-300 text-black rounded-full'
|
||||
}
|
||||
},
|
||||
@@ -1150,134 +1169,17 @@ export const compactNavigation: FuseNavigationItem[] = [
|
||||
}
|
||||
];
|
||||
export const futuristicNavigation: FuseNavigationItem[] = [
|
||||
{
|
||||
id : 'dashboards',
|
||||
title : 'DASHBOARDS',
|
||||
type : 'group',
|
||||
children: [] // This will be filled from defaultNavigation so we don't have to manage multiple sets of the same navigation
|
||||
},
|
||||
{
|
||||
id : 'apps',
|
||||
title : 'APPS',
|
||||
type : 'group',
|
||||
children: [
|
||||
{
|
||||
id : 'apps.dashboards.analytics',
|
||||
title: 'Analytics',
|
||||
type : 'basic',
|
||||
icon : 'heroicons_outline:chart-pie',
|
||||
link : '/dashboards/analytics'
|
||||
},
|
||||
{
|
||||
id : 'apps.dashboards.project',
|
||||
title: 'Project',
|
||||
type : 'basic',
|
||||
icon : 'heroicons_outline:clipboard-check',
|
||||
link : '/dashboards/project'
|
||||
},
|
||||
{
|
||||
id : 'apps.academy',
|
||||
title: 'Academy',
|
||||
type : 'basic',
|
||||
icon : 'heroicons_outline:academic-cap',
|
||||
link : '/apps/academy'
|
||||
},
|
||||
{
|
||||
id : 'apps.calendar',
|
||||
title: 'Calendar',
|
||||
type : 'basic',
|
||||
icon : 'heroicons_outline:calendar',
|
||||
link : '/apps/calendar'
|
||||
},
|
||||
{
|
||||
id : 'apps.chat',
|
||||
title: 'Chat',
|
||||
type : 'basic',
|
||||
icon : 'heroicons_outline:chat-alt',
|
||||
link : '/apps/chat'
|
||||
},
|
||||
{
|
||||
id : 'apps.contacts',
|
||||
title: 'Contacts',
|
||||
type : 'basic',
|
||||
icon : 'heroicons_outline:user-group',
|
||||
link : '/apps/contacts'
|
||||
},
|
||||
{
|
||||
id : 'apps.ecommerce',
|
||||
title : 'ECommerce',
|
||||
type : 'collapsable',
|
||||
icon : 'heroicons_outline:shopping-cart',
|
||||
children: [
|
||||
{
|
||||
id : 'apps.ecommerce.inventory',
|
||||
title: 'Inventory',
|
||||
type : 'basic',
|
||||
link : '/apps/ecommerce/inventory'
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
id : 'apps.file-manager',
|
||||
title: 'File manager',
|
||||
type : 'basic',
|
||||
icon : 'heroicons_outline:shopping-cart',
|
||||
link : '/apps/file-manager'
|
||||
},
|
||||
{
|
||||
id : 'apps.help-center',
|
||||
title : 'Help center',
|
||||
type : 'collapsable',
|
||||
icon : 'heroicons_outline:support',
|
||||
link : '/apps/help-center',
|
||||
children: [
|
||||
{
|
||||
id : 'apps.help-center.home',
|
||||
title : 'Home',
|
||||
type : 'basic',
|
||||
link : '/apps/help-center',
|
||||
exactMatch: true
|
||||
},
|
||||
{
|
||||
id : 'apps.help-center.faqs',
|
||||
title: 'FAQs',
|
||||
type : 'basic',
|
||||
link : '/apps/help-center/faqs'
|
||||
},
|
||||
{
|
||||
id : 'apps.help-center.guides',
|
||||
title: 'Guides',
|
||||
type : 'basic',
|
||||
link : '/apps/help-center/guides'
|
||||
},
|
||||
{
|
||||
id : 'apps.help-center.support',
|
||||
title: 'Support',
|
||||
type : 'basic',
|
||||
link : '/apps/help-center/support'
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
id : 'apps.mailbox',
|
||||
title: 'Mailbox',
|
||||
type : 'basic',
|
||||
icon : 'heroicons_outline:mail',
|
||||
link : '/apps/mailbox',
|
||||
badge: {
|
||||
title : '27',
|
||||
classes: 'px-2 bg-black bg-opacity-25 text-white rounded-full'
|
||||
}
|
||||
},
|
||||
{
|
||||
id : 'apps.notes',
|
||||
title: 'Notes',
|
||||
type : 'basic',
|
||||
icon : 'heroicons_outline:pencil-alt',
|
||||
link : '/apps/notes'
|
||||
},
|
||||
{
|
||||
id : 'apps.tasks',
|
||||
title: 'Tasks',
|
||||
type : 'basic',
|
||||
icon : 'heroicons_outline:check-circle',
|
||||
link : '/apps/tasks'
|
||||
}
|
||||
]
|
||||
children: [] // This will be filled from defaultNavigation so we don't have to manage multiple sets of the same navigation
|
||||
},
|
||||
{
|
||||
id : 'others',
|
||||
|
||||
@@ -1,11 +1,10 @@
|
||||
/* 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',
|
||||
icon : 'heroicons_solid:star',
|
||||
title : 'Daily challenges',
|
||||
description: 'Your submission has been accepted',
|
||||
time : moment().subtract(25, 'minutes').toISOString(), // 25 minutes ago
|
||||
@@ -22,7 +21,7 @@ export const notifications: Notification[] = [
|
||||
},
|
||||
{
|
||||
id : 'b91ccb58-b06c-413b-b389-87010e03a120',
|
||||
icon : 'heroicons_outline:mail',
|
||||
icon : 'heroicons_solid:mail',
|
||||
title : 'Mailbox',
|
||||
description: 'You have 15 unread mails across 3 mailboxes',
|
||||
time : moment().subtract(3, 'hours').toISOString(), // 3 hours ago
|
||||
@@ -32,7 +31,7 @@ export const notifications: Notification[] = [
|
||||
},
|
||||
{
|
||||
id : '541416c9-84a7-408a-8d74-27a43c38d797',
|
||||
icon : 'heroicons_outline:refresh',
|
||||
icon : 'heroicons_solid:refresh',
|
||||
title : 'Cron jobs',
|
||||
description: 'Your <em>Docker container</em> is ready to publish',
|
||||
time : moment().subtract(5, 'hours').toISOString(), // 5 hours ago
|
||||
@@ -60,7 +59,7 @@ export const notifications: Notification[] = [
|
||||
},
|
||||
{
|
||||
id : 'b85c2338-cc98-4140-bbf8-c226ce4e395e',
|
||||
icon : 'heroicons_outline:mail',
|
||||
icon : 'heroicons_solid:mail',
|
||||
title : 'Mailbox',
|
||||
description: 'You have 3 new mails',
|
||||
time : moment().subtract(1, 'day').toISOString(), // 1 day ago
|
||||
@@ -70,7 +69,7 @@ export const notifications: Notification[] = [
|
||||
},
|
||||
{
|
||||
id : '8f8e1bf9-4661-4939-9e43-390957b60f42',
|
||||
icon : 'heroicons_outline:star',
|
||||
icon : 'heroicons_solid:star',
|
||||
title : 'Daily challenges',
|
||||
description: 'Your submission has been accepted and you are ready to sign-up for the final assigment which will be ready in 2 days',
|
||||
time : moment().subtract(3, 'days').toISOString(), // 3 days ago
|
||||
@@ -80,7 +79,7 @@ export const notifications: Notification[] = [
|
||||
},
|
||||
{
|
||||
id : '30af917b-7a6a-45d1-822f-9e7ad7f8bf69',
|
||||
icon : 'heroicons_outline:refresh',
|
||||
icon : 'heroicons_solid:refresh',
|
||||
title : 'Cron jobs',
|
||||
description: 'Your Vagrant container is ready to download',
|
||||
time : moment().subtract(4, 'day').toISOString(), // 4 days ago
|
||||
|
||||
@@ -4,6 +4,7 @@ import { FuseNavigationItem, FuseNavigationService } from '@fuse/components/navi
|
||||
import { FuseMockApiService } from '@fuse/lib/mock-api';
|
||||
import { defaultNavigation } from 'app/mock-api/common/navigation/data';
|
||||
import { contacts } from 'app/mock-api/apps/contacts/data';
|
||||
import { tasks } from 'app/mock-api/apps/tasks/data';
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root'
|
||||
@@ -12,6 +13,7 @@ export class SearchMockApi
|
||||
{
|
||||
private readonly _defaultNavigation: FuseNavigationItem[] = defaultNavigation;
|
||||
private readonly _contacts: any[] = contacts;
|
||||
private readonly _tasks: any[] = tasks;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
@@ -54,58 +56,75 @@ export class SearchMockApi
|
||||
return [200, {results: []}];
|
||||
}
|
||||
|
||||
// Filter the navigation
|
||||
const navigationResults = cloneDeep(flatNavigation).filter(item => (item.title?.toLowerCase().includes(query) || (item.subtitle && item.subtitle.includes(query))));
|
||||
|
||||
// Filter the contacts
|
||||
const contactsResults = cloneDeep(this._contacts).filter(user => user.name.toLowerCase().includes(query));
|
||||
const contactsResults = cloneDeep(this._contacts)
|
||||
.filter(contact => contact.name.toLowerCase().includes(query));
|
||||
|
||||
// Create the results array
|
||||
// Filter the navigation
|
||||
const pagesResults = cloneDeep(flatNavigation)
|
||||
.filter(page => (page.title?.toLowerCase().includes(query) || (page.subtitle && page.subtitle.includes(query))));
|
||||
|
||||
// Filter the tasks
|
||||
const tasksResults = cloneDeep(this._tasks)
|
||||
.filter(task => task.title.toLowerCase().includes(query));
|
||||
|
||||
// Prepare the results array
|
||||
const results = [];
|
||||
|
||||
// If there are navigation results...
|
||||
if ( navigationResults.length > 0 )
|
||||
{
|
||||
// Normalize the results while marking the found chars
|
||||
navigationResults.forEach((result: any) => {
|
||||
|
||||
// Normalize
|
||||
result['hint'] = result.link;
|
||||
result['resultType'] = 'page';
|
||||
|
||||
// Mark the found chars
|
||||
const re = new RegExp('(' + query.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&') + ')', 'ig');
|
||||
result.title = result.title.replace(re, '<mark>$1</mark>');
|
||||
});
|
||||
|
||||
// Add the results
|
||||
results.push(...navigationResults);
|
||||
}
|
||||
|
||||
// If there are contacts results...
|
||||
if ( contactsResults.length > 0 )
|
||||
{
|
||||
// Normalize the results while marking the found chars
|
||||
// Normalize the results
|
||||
contactsResults.forEach((result) => {
|
||||
|
||||
// Normalize
|
||||
result.title = result.name;
|
||||
result.resultType = 'contact';
|
||||
|
||||
// Make the found chars bold
|
||||
const re = new RegExp('(' + query.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&') + ')', 'ig');
|
||||
result.title = result.title.replace(re, '<mark>$1</mark>');
|
||||
|
||||
// Add a link
|
||||
result.link = '/apps/contacts/' + result.id;
|
||||
});
|
||||
|
||||
// Add the results to the results object
|
||||
results.push(...contactsResults);
|
||||
// Add to the results
|
||||
results.push({
|
||||
id : 'contacts',
|
||||
label : 'Contacts',
|
||||
results: contactsResults
|
||||
});
|
||||
}
|
||||
|
||||
// If there are page results...
|
||||
if ( pagesResults.length > 0 )
|
||||
{
|
||||
// Normalize the results
|
||||
pagesResults.forEach((result: any) => {
|
||||
|
||||
});
|
||||
|
||||
// Add to the results
|
||||
results.push({
|
||||
id : 'pages',
|
||||
label : 'Pages',
|
||||
results: pagesResults
|
||||
});
|
||||
}
|
||||
|
||||
// If there are tasks results...
|
||||
if ( tasksResults.length > 0 )
|
||||
{
|
||||
// Normalize the results
|
||||
tasksResults.forEach((result) => {
|
||||
|
||||
// Add a link
|
||||
result.link = '/apps/tasks/' + result.id;
|
||||
});
|
||||
|
||||
// Add to the results
|
||||
results.push({
|
||||
id : 'tasks',
|
||||
label : 'Tasks',
|
||||
results: tasksResults
|
||||
});
|
||||
}
|
||||
|
||||
// Return the response
|
||||
return [200, {results}];
|
||||
return [200, results];
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,13 +1,11 @@
|
||||
/* 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',
|
||||
description: 'Latest version: v1.2',
|
||||
description: 'List of changes',
|
||||
icon : 'heroicons_outline:clipboard-list',
|
||||
link : '/dashboards/project',
|
||||
link : '/docs/changelog',
|
||||
useRouter : true
|
||||
},
|
||||
{
|
||||
@@ -15,7 +13,7 @@ export const shortcuts: Shortcut[] = [
|
||||
label : 'Documentation',
|
||||
description: 'Getting started',
|
||||
icon : 'heroicons_outline:book-open',
|
||||
link : '/dashboards/project',
|
||||
link : '/docs/guides/getting-started/introduction',
|
||||
useRouter : true
|
||||
},
|
||||
{
|
||||
@@ -23,7 +21,7 @@ export const shortcuts: Shortcut[] = [
|
||||
label : 'Help center',
|
||||
description: 'FAQs and guides',
|
||||
icon : 'heroicons_outline:support',
|
||||
link : '/pages/help-center',
|
||||
link : '/apps/help-center',
|
||||
useRouter : true
|
||||
},
|
||||
{
|
||||
@@ -31,7 +29,7 @@ export const shortcuts: Shortcut[] = [
|
||||
label : 'Dashboard',
|
||||
description: 'User analytics',
|
||||
icon : 'heroicons_outline:chart-pie',
|
||||
link : '/dashboards/project',
|
||||
link : '/dashboards/analytics',
|
||||
useRouter : true
|
||||
},
|
||||
{
|
||||
@@ -69,7 +67,7 @@ export const shortcuts: Shortcut[] = [
|
||||
{
|
||||
id : '0a240ab8-e19d-4503-bf68-20013030d526',
|
||||
label : 'Reload',
|
||||
description: 'Restart the app',
|
||||
description: 'Reload the app',
|
||||
icon : 'heroicons_outline:refresh',
|
||||
link : '/dashboards/project',
|
||||
useRouter : false
|
||||
|
||||
@@ -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',
|
||||
|
||||
@@ -16,6 +16,7 @@ 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';
|
||||
@@ -39,6 +40,7 @@ export const mockApiServices = [
|
||||
NotificationsMockApi,
|
||||
ProjectMockApi,
|
||||
SearchMockApi,
|
||||
ScrumboardMockApi,
|
||||
ShortcutsMockApi,
|
||||
TasksMockApi,
|
||||
UserMockApi
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
/* eslint-disable */
|
||||
import * as moment from 'moment';
|
||||
import { Activity } from 'app/modules/admin/pages/activities/activities.types';
|
||||
|
||||
export const activities: Activity[] = [
|
||||
export const activities = [
|
||||
{
|
||||
id : '493190c9-5b61-4912-afe5-78c21f1044d7',
|
||||
icon : 'heroicons_solid:star',
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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
|
||||
]
|
||||
})
|
||||
|
||||
@@ -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
|
||||
],
|
||||
|
||||
@@ -598,11 +598,11 @@
|
||||
[svgIcon]="'heroicons_solid:menu-alt-2'"></mat-icon>
|
||||
<textarea
|
||||
matInput
|
||||
fuseAutogrow
|
||||
[rows]="5"
|
||||
[formControlName]="'notes'"
|
||||
[placeholder]="'Notes'"
|
||||
[spellcheck]="false"></textarea>
|
||||
[rows]="5"
|
||||
[spellcheck]="false"
|
||||
matTextareaAutosize></textarea>
|
||||
</mat-form-field>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -12,7 +12,6 @@ import { MatRippleModule } from '@angular/material/core';
|
||||
import { MatSortModule } from '@angular/material/sort';
|
||||
import { MatSelectModule } from '@angular/material/select';
|
||||
import { MatSlideToggleModule } from '@angular/material/slide-toggle';
|
||||
import { MatTableModule } from '@angular/material/table';
|
||||
import { MatTooltipModule } from '@angular/material/tooltip';
|
||||
import { SharedModule } from 'app/shared/shared.module';
|
||||
import { InventoryComponent } from 'app/modules/admin/apps/ecommerce/inventory/inventory.component';
|
||||
@@ -38,7 +37,6 @@ import { ecommerceRoutes } from 'app/modules/admin/apps/ecommerce/ecommerce.rout
|
||||
MatSortModule,
|
||||
MatSelectModule,
|
||||
MatSlideToggleModule,
|
||||
MatTableModule,
|
||||
MatTooltipModule,
|
||||
SharedModule
|
||||
]
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
<div class="absolute inset-0 flex flex-col min-w-0 overflow-hidden bg-card dark:bg-transparent">
|
||||
<div class="sm:absolute sm:inset-0 flex flex-col flex-auto min-w-0 sm:overflow-hidden bg-card dark:bg-transparent">
|
||||
|
||||
<!-- Header -->
|
||||
<div class="relative flex flex-col sm:flex-row flex-0 sm:items-center sm:justify-between py-8 px-6 md:px-8 border-b">
|
||||
@@ -39,523 +39,451 @@
|
||||
<div class="flex flex-auto overflow-hidden">
|
||||
|
||||
<!-- Products list -->
|
||||
<div class="flex flex-col flex-auto sm:mb-18 overflow-hidden">
|
||||
|
||||
<ng-container *ngIf="productsCount > 0; else noProducts">
|
||||
|
||||
<!-- Table wrapper -->
|
||||
<div
|
||||
class="overflow-x-auto sm:overflow-y-auto"
|
||||
cdkScrollable>
|
||||
|
||||
<!-- Table -->
|
||||
<table
|
||||
class="w-full min-w-320 table-fixed bg-transparent"
|
||||
[ngClass]="{'pointer-events-none': isLoading}"
|
||||
mat-table
|
||||
matSort
|
||||
[matSortActive]="'name'"
|
||||
[matSortDisableClear]="true"
|
||||
[matSortDirection]="'asc'"
|
||||
[multiTemplateDataRows]="true"
|
||||
[dataSource]="products$"
|
||||
[trackBy]="trackByFn">
|
||||
|
||||
<!-- SKU -->
|
||||
<ng-container matColumnDef="sku">
|
||||
<th
|
||||
class="w-56 pl-26 bg-gray-50 dark:bg-black dark:bg-opacity-5"
|
||||
mat-header-cell
|
||||
*matHeaderCellDef
|
||||
mat-sort-header
|
||||
disableClear>
|
||||
<div class="flex flex-col flex-auto sm:mb-18 overflow-hidden sm:overflow-y-auto">
|
||||
<ng-container *ngIf="(products$ | async) as products">
|
||||
<ng-container *ngIf="products.length > 0; else noProducts">
|
||||
<div class="grid">
|
||||
<!-- Header -->
|
||||
<div
|
||||
class="inventory-grid z-10 sticky top-0 grid gap-4 py-4 px-6 md:px-8 shadow text-md font-semibold text-secondary bg-gray-50 dark:bg-black dark:bg-opacity-5"
|
||||
matSort
|
||||
matSortDisableClear>
|
||||
<div></div>
|
||||
<div
|
||||
class="hidden md:block"
|
||||
[mat-sort-header]="'sku'">
|
||||
SKU
|
||||
</th>
|
||||
<td
|
||||
class="px-8"
|
||||
mat-cell
|
||||
*matCellDef="let product">
|
||||
<div class="flex items-center">
|
||||
<span class="relative flex flex-0 items-center justify-center w-12 h-12 mr-6 rounded overflow-hidden border">
|
||||
<img
|
||||
class="w-8"
|
||||
*ngIf="product.thumbnail"
|
||||
[src]="product.thumbnail">
|
||||
<span
|
||||
class="flex items-center justify-center w-full h-full text-xs font-semibold leading-none text-center uppercase"
|
||||
*ngIf="!product.thumbnail">
|
||||
No Image
|
||||
</span>
|
||||
</span>
|
||||
<span class="truncate">{{product.sku}}</span>
|
||||
</div>
|
||||
</td>
|
||||
</ng-container>
|
||||
|
||||
<!-- Name -->
|
||||
<ng-container matColumnDef="name">
|
||||
<th
|
||||
class="bg-gray-50 dark:bg-black dark:bg-opacity-5"
|
||||
mat-header-cell
|
||||
*matHeaderCellDef
|
||||
mat-sort-header
|
||||
disableClear>
|
||||
Name
|
||||
</th>
|
||||
<td
|
||||
class="pr-8 truncate"
|
||||
mat-cell
|
||||
*matCellDef="let product">
|
||||
{{product.name}}
|
||||
</td>
|
||||
</ng-container>
|
||||
|
||||
<!-- Price -->
|
||||
<ng-container matColumnDef="price">
|
||||
<th
|
||||
class="w-40 bg-gray-50 dark:bg-black dark:bg-opacity-5"
|
||||
mat-header-cell
|
||||
*matHeaderCellDef
|
||||
mat-sort-header
|
||||
disableClear>
|
||||
</div>
|
||||
<div [mat-sort-header]="'name'">Name</div>
|
||||
<div
|
||||
class="hidden sm:block"
|
||||
[mat-sort-header]="'price'">
|
||||
Price
|
||||
</th>
|
||||
<td
|
||||
class="pr-4"
|
||||
mat-cell
|
||||
*matCellDef="let product">
|
||||
{{product.price | currency:'USD':'symbol':'1.2-2'}}
|
||||
</td>
|
||||
</ng-container>
|
||||
|
||||
<!-- Stock -->
|
||||
<ng-container matColumnDef="stock">
|
||||
<th
|
||||
class="w-24 bg-gray-50 dark:bg-black dark:bg-opacity-5"
|
||||
mat-header-cell
|
||||
*matHeaderCellDef
|
||||
mat-sort-header
|
||||
disableClear>
|
||||
</div>
|
||||
<div
|
||||
class="hidden lg:block"
|
||||
[mat-sort-header]="'stock'">
|
||||
Stock
|
||||
</th>
|
||||
<td
|
||||
class="pr-4"
|
||||
mat-cell
|
||||
*matCellDef="let product">
|
||||
<span class="flex items-center">
|
||||
<span class="min-w-4">{{product.stock}}</span>
|
||||
<!-- Low stock -->
|
||||
<span
|
||||
class="flex items-end ml-2 w-1 h-4 bg-red-200 rounded overflow-hidden"
|
||||
*ngIf="product.stock < 20">
|
||||
<span class="flex w-full h-1/3 bg-red-600"></span>
|
||||
</span>
|
||||
<!-- Medium stock -->
|
||||
<span
|
||||
class="flex items-end ml-2 w-1 h-4 bg-orange-200 rounded overflow-hidden"
|
||||
*ngIf="product.stock >= 20 && product.stock < 30">
|
||||
<span class="flex w-full h-2/4 bg-orange-400"></span>
|
||||
</span>
|
||||
<!-- High stock -->
|
||||
<span
|
||||
class="flex items-end ml-2 w-1 h-4 bg-green-100 rounded overflow-hidden"
|
||||
*ngIf="product.stock >= 30">
|
||||
<span class="flex w-full h-full bg-green-400"></span>
|
||||
</span>
|
||||
</span>
|
||||
</td>
|
||||
</ng-container>
|
||||
|
||||
<!-- Active -->
|
||||
<ng-container matColumnDef="active">
|
||||
<th
|
||||
class="w-24 bg-gray-50 dark:bg-black dark:bg-opacity-5"
|
||||
mat-header-cell
|
||||
*matHeaderCellDef
|
||||
mat-sort-header
|
||||
disableClear>
|
||||
</div>
|
||||
<div
|
||||
class="hidden lg:block"
|
||||
[mat-sort-header]="'active'">
|
||||
Active
|
||||
</th>
|
||||
<td
|
||||
class="pr-4"
|
||||
mat-cell
|
||||
*matCellDef="let product">
|
||||
<mat-icon
|
||||
class="text-green-400 icon-size-5"
|
||||
*ngIf="product.active"
|
||||
[svgIcon]="'heroicons_solid:check'"></mat-icon>
|
||||
<mat-icon
|
||||
class="text-gray-400 icon-size-5"
|
||||
*ngIf="!product.active"
|
||||
[svgIcon]="'heroicons_solid:x'"></mat-icon>
|
||||
</td>
|
||||
</ng-container>
|
||||
|
||||
<!-- Details -->
|
||||
<ng-container matColumnDef="details">
|
||||
<th
|
||||
class="w-24 pr-8 bg-gray-50 dark:bg-black dark:bg-opacity-5"
|
||||
mat-header-cell
|
||||
*matHeaderCellDef>
|
||||
Details
|
||||
</th>
|
||||
<td
|
||||
class="pr-8"
|
||||
mat-cell
|
||||
*matCellDef="let product">
|
||||
<button
|
||||
class="min-w-10 min-h-7 h-7 px-2 leading-6"
|
||||
mat-stroked-button
|
||||
(click)="toggleDetails(product.id)">
|
||||
<mat-icon
|
||||
class="icon-size-5"
|
||||
[svgIcon]="selectedProduct?.id === product.id ? 'heroicons_solid:chevron-up' : 'heroicons_solid:chevron-down'"></mat-icon>
|
||||
</button>
|
||||
</td>
|
||||
</ng-container>
|
||||
|
||||
<!-- Product details row -->
|
||||
<ng-container matColumnDef="productDetails">
|
||||
<td
|
||||
class="p-0 border-b-0"
|
||||
mat-cell
|
||||
*matCellDef="let product"
|
||||
[attr.colspan]="productsTableColumns.length">
|
||||
<div
|
||||
class="shadow-lg overflow-hidden"
|
||||
[@expandCollapse]="selectedProduct?.id === product.id ? 'expanded' : 'collapsed'">
|
||||
<div class="flex border-b">
|
||||
<!-- Selected product form -->
|
||||
<form
|
||||
class="flex flex-col w-full"
|
||||
[formGroup]="selectedProductForm">
|
||||
|
||||
<div class="flex p-8">
|
||||
|
||||
<!-- Product images and status -->
|
||||
<div class="flex flex-col">
|
||||
<div class="flex flex-col items-center">
|
||||
<div class="p-3 border rounded">
|
||||
<ng-container *ngIf="selectedProductForm.get('images').value.length; else noImage">
|
||||
<img
|
||||
class="w-30 min-w-30"
|
||||
[src]="selectedProductForm.get('images').value[selectedProductForm.get('currentImageIndex').value]">
|
||||
</ng-container>
|
||||
<ng-template #noImage>
|
||||
<span class="flex items-center min-h-20 text-lg font-semibold">NO IMAGE</span>
|
||||
</ng-template>
|
||||
</div>
|
||||
<div
|
||||
class="flex items-center mt-2"
|
||||
*ngIf="selectedProductForm.get('images').value.length">
|
||||
<button
|
||||
mat-icon-button
|
||||
(click)="cycleImages(false)">
|
||||
<mat-icon
|
||||
class="icon-size-5"
|
||||
[svgIcon]="'heroicons_solid:arrow-narrow-left'"></mat-icon>
|
||||
</button>
|
||||
<span class="font-sm mx-2">
|
||||
{{selectedProductForm.get('currentImageIndex').value + 1}} of {{selectedProductForm.get('images').value.length}}
|
||||
</span>
|
||||
<button
|
||||
mat-icon-button
|
||||
(click)="cycleImages(true)">
|
||||
<mat-icon
|
||||
class="icon-size-5"
|
||||
[svgIcon]="'heroicons_solid:arrow-narrow-right'"></mat-icon>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex flex-col mt-8">
|
||||
<span class="font-semibold mb-2">Product status</span>
|
||||
<mat-slide-toggle
|
||||
[formControlName]="'active'"
|
||||
[color]="'primary'">
|
||||
{{selectedProductForm.get('active').value === true ? 'Active' : 'Disabled'}}
|
||||
</mat-slide-toggle>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="flex flex-auto">
|
||||
<div class="flex flex-col w-2/4 pl-8">
|
||||
|
||||
<!-- Name -->
|
||||
<mat-form-field class="w-full">
|
||||
<mat-label>Name</mat-label>
|
||||
<input
|
||||
matInput
|
||||
[formControlName]="'name'">
|
||||
</mat-form-field>
|
||||
|
||||
<!-- SKU and Barcode -->
|
||||
<div class="flex">
|
||||
<mat-form-field class="w-1/3 pr-2">
|
||||
<mat-label>SKU</mat-label>
|
||||
<input
|
||||
matInput
|
||||
[formControlName]="'sku'">
|
||||
</mat-form-field>
|
||||
<mat-form-field class="w-2/3 pl-2">
|
||||
<mat-label>Barcode</mat-label>
|
||||
<input
|
||||
matInput
|
||||
[formControlName]="'barcode'">
|
||||
</mat-form-field>
|
||||
</div>
|
||||
|
||||
<!-- Category, Brand & Vendor -->
|
||||
<div class="flex">
|
||||
<mat-form-field class="w-1/3 pr-2">
|
||||
<mat-label>Category</mat-label>
|
||||
<mat-select [formControlName]="'category'">
|
||||
<ng-container *ngFor="let category of categories">
|
||||
<mat-option [value]="category.id">
|
||||
{{category.name}}
|
||||
</mat-option>
|
||||
</ng-container>
|
||||
</mat-select>
|
||||
</mat-form-field>
|
||||
<mat-form-field class="w-1/3 px-2">
|
||||
<mat-label>Brand</mat-label>
|
||||
<mat-select [formControlName]="'brand'">
|
||||
<ng-container *ngFor="let brand of brands">
|
||||
<mat-option [value]="brand.id">
|
||||
{{brand.name}}
|
||||
</mat-option>
|
||||
</ng-container>
|
||||
</mat-select>
|
||||
</mat-form-field>
|
||||
<mat-form-field class="w-1/3 pl-2">
|
||||
<mat-label>Vendor</mat-label>
|
||||
<mat-select [formControlName]="'vendor'">
|
||||
<ng-container *ngFor="let vendor of vendors">
|
||||
<mat-option [value]="vendor.id">
|
||||
{{vendor.name}}
|
||||
</mat-option>
|
||||
</ng-container>
|
||||
</mat-select>
|
||||
</mat-form-field>
|
||||
</div>
|
||||
|
||||
<!-- Stock and Reserved -->
|
||||
<div class="flex">
|
||||
<mat-form-field class="w-1/3 pr-2">
|
||||
<mat-label>Stock</mat-label>
|
||||
<input
|
||||
type="number"
|
||||
matInput
|
||||
[formControlName]="'stock'">
|
||||
</mat-form-field>
|
||||
<mat-form-field class="w-1/3 pl-2">
|
||||
<mat-label>Reserved</mat-label>
|
||||
<input
|
||||
type="number"
|
||||
matInput
|
||||
[formControlName]="'reserved'">
|
||||
</mat-form-field>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Cost, Base price, Tax & Price -->
|
||||
<div class="flex flex-col w-1/4 pl-8">
|
||||
<mat-form-field class="w-full">
|
||||
<mat-label>Cost</mat-label>
|
||||
<span matPrefix>$</span>
|
||||
<input
|
||||
matInput
|
||||
[formControlName]="'cost'">
|
||||
</mat-form-field>
|
||||
<mat-form-field class="w-full">
|
||||
<mat-label>Base Price</mat-label>
|
||||
<span matPrefix>$</span>
|
||||
<input
|
||||
matInput
|
||||
[formControlName]="'basePrice'">
|
||||
</mat-form-field>
|
||||
<mat-form-field class="w-full">
|
||||
<mat-label>Tax</mat-label>
|
||||
<span matSuffix>%</span>
|
||||
<input
|
||||
type="number"
|
||||
matInput
|
||||
[formControlName]="'taxPercent'">
|
||||
</mat-form-field>
|
||||
<mat-form-field class="w-full">
|
||||
<mat-label>Price</mat-label>
|
||||
<span matSuffix>$</span>
|
||||
<input
|
||||
matInput
|
||||
[formControlName]="'price'">
|
||||
</mat-form-field>
|
||||
</div>
|
||||
|
||||
<!-- Weight & Tags -->
|
||||
<div class="flex flex-col w-1/4 pl-8">
|
||||
<mat-form-field class="w-full">
|
||||
<mat-label>Weight</mat-label>
|
||||
<span matSuffix>lbs.</span>
|
||||
<input
|
||||
matInput
|
||||
[formControlName]="'weight'">
|
||||
</mat-form-field>
|
||||
|
||||
<!-- Tags -->
|
||||
<ng-container *ngIf="selectedProduct && selectedProduct.tags.length">
|
||||
<span class="font-semibold">Tags</span>
|
||||
<div class="mt-1 rounded-md border shadow-sm overflow-hidden">
|
||||
<!-- Header -->
|
||||
<div class="flex items-center my-2 mx-3">
|
||||
<div class="flex items-center flex-auto min-w-0">
|
||||
<mat-icon
|
||||
class="icon-size-5"
|
||||
[svgIcon]="'heroicons_solid:search'"></mat-icon>
|
||||
<input
|
||||
class="min-w-0 ml-2 py-1 border-0"
|
||||
type="text"
|
||||
placeholder="Enter tag name"
|
||||
(input)="filterTags($event)"
|
||||
(keydown)="filterTagsInputKeyDown($event)"
|
||||
[maxLength]="50"
|
||||
#newTagInput>
|
||||
</div>
|
||||
<button
|
||||
class="ml-3 w-8 h-8 min-h-8"
|
||||
mat-icon-button
|
||||
(click)="toggleTagsEditMode()">
|
||||
<mat-icon
|
||||
*ngIf="!tagsEditMode"
|
||||
class="icon-size-5"
|
||||
[svgIcon]="'heroicons_solid:pencil-alt'"></mat-icon>
|
||||
<mat-icon
|
||||
*ngIf="tagsEditMode"
|
||||
class="icon-size-5"
|
||||
[svgIcon]="'heroicons_solid:check'"></mat-icon>
|
||||
</button>
|
||||
</div>
|
||||
<!-- Available tags -->
|
||||
<div class="max-h-40 leading-none overflow-y-auto border-t">
|
||||
<!-- Tags -->
|
||||
<ng-container *ngIf="!tagsEditMode">
|
||||
<ng-container *ngFor="let tag of filteredTags; trackBy: trackByFn">
|
||||
<mat-checkbox
|
||||
class="flex items-center h-10 min-h-10 px-4"
|
||||
[color]="'primary'"
|
||||
[checked]="selectedProduct.tags.includes(tag.id)"
|
||||
(change)="toggleProductTag(tag, $event)">
|
||||
{{tag.title}}
|
||||
</mat-checkbox>
|
||||
</ng-container>
|
||||
</ng-container>
|
||||
<!-- Tags editing -->
|
||||
<ng-container *ngIf="tagsEditMode">
|
||||
<div class="p-4 space-y-2">
|
||||
<ng-container *ngFor="let tag of filteredTags; trackBy: trackByFn">
|
||||
<mat-form-field class="fuse-mat-dense fuse-mat-no-subscript w-full">
|
||||
<input
|
||||
matInput
|
||||
[value]="tag.title"
|
||||
(input)="updateTagTitle(tag, $event)">
|
||||
<button
|
||||
mat-icon-button
|
||||
(click)="deleteTag(tag)"
|
||||
matSuffix>
|
||||
<mat-icon
|
||||
class="icon-size-5"
|
||||
[svgIcon]="'heroicons_solid:trash'"></mat-icon>
|
||||
</button>
|
||||
</mat-form-field>
|
||||
</ng-container>
|
||||
</div>
|
||||
</ng-container>
|
||||
</div>
|
||||
<div
|
||||
class="flex items-center h-10 min-h-10 -ml-0.5 pl-4 pr-3 leading-none cursor-pointer border-t hover:bg-gray-50 dark:hover:bg-hover"
|
||||
*ngIf="shouldShowCreateTagButton(newTagInput.value)"
|
||||
(click)="createTag(newTagInput.value); newTagInput.value = ''"
|
||||
matRipple>
|
||||
<mat-icon
|
||||
class="mr-2 icon-size-5"
|
||||
[svgIcon]="'heroicons_solid:plus-circle'"></mat-icon>
|
||||
<div class="break-all">Create "<b>{{newTagInput.value}}</b>"</div>
|
||||
</div>
|
||||
</div>
|
||||
</ng-container>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<div class="hidden sm:block">Details</div>
|
||||
</div>
|
||||
<!-- Rows -->
|
||||
<ng-container *ngIf="(products$ | async) as products">
|
||||
<ng-container *ngFor="let product of products; trackBy: trackByFn">
|
||||
<div class="inventory-grid grid items-center gap-4 py-3 px-6 md:px-8 border-b">
|
||||
|
||||
<!-- Image -->
|
||||
<div class="flex items-center">
|
||||
<div class="relative flex flex-0 items-center justify-center w-12 h-12 mr-6 rounded overflow-hidden border">
|
||||
<img
|
||||
class="w-8"
|
||||
*ngIf="product.thumbnail"
|
||||
[alt]="'Product thumbnail image'"
|
||||
[src]="product.thumbnail">
|
||||
<div
|
||||
class="flex items-center justify-center w-full h-full text-xs font-semibold leading-none text-center uppercase"
|
||||
*ngIf="!product.thumbnail">
|
||||
NO THUMB
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="flex items-center justify-between w-full border-t px-8 py-4">
|
||||
<button
|
||||
class="-ml-4"
|
||||
mat-button
|
||||
[color]="'warn'"
|
||||
(click)="deleteSelectedProduct()">
|
||||
Delete
|
||||
</button>
|
||||
<div class="flex items-center">
|
||||
<div
|
||||
class="flex items-center mr-4"
|
||||
*ngIf="flashMessage">
|
||||
<ng-container *ngIf="flashMessage === 'success'">
|
||||
<mat-icon
|
||||
class="text-green-500"
|
||||
[svgIcon]="'heroicons_outline:check'"></mat-icon>
|
||||
<span class="ml-2">Product updated</span>
|
||||
</ng-container>
|
||||
<ng-container *ngIf="flashMessage === 'error'">
|
||||
<mat-icon
|
||||
class="text-red-500"
|
||||
[svgIcon]="'heroicons_outline:x'"></mat-icon>
|
||||
<span class="ml-2">An error occurred, try again!</span>
|
||||
</ng-container>
|
||||
</div>
|
||||
<button
|
||||
mat-flat-button
|
||||
[color]="'primary'"
|
||||
(click)="updateSelectedProduct()">
|
||||
Update
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<!-- SKU -->
|
||||
<div class="hidden md:block truncate">
|
||||
{{product.sku}}
|
||||
</div>
|
||||
|
||||
</form>
|
||||
<!-- Name -->
|
||||
<div class="truncate">
|
||||
{{product.name}}
|
||||
</div>
|
||||
|
||||
<!-- Price -->
|
||||
<div class="hidden sm:block">
|
||||
{{product.price | currency:'USD':'symbol':'1.2-2'}}
|
||||
</div>
|
||||
|
||||
<!-- Stock -->
|
||||
<div class="hidden lg:flex items-center">
|
||||
<div class="min-w-4">{{product.stock}}</div>
|
||||
<!-- Low stock -->
|
||||
<div
|
||||
class="flex items-end ml-2 w-1 h-4 bg-red-200 rounded overflow-hidden"
|
||||
*ngIf="product.stock < 20">
|
||||
<div class="flex w-full h-1/3 bg-red-600"></div>
|
||||
</div>
|
||||
<!-- Medium stock -->
|
||||
<div
|
||||
class="flex items-end ml-2 w-1 h-4 bg-orange-200 rounded overflow-hidden"
|
||||
*ngIf="product.stock >= 20 && product.stock < 30">
|
||||
<div class="flex w-full h-2/4 bg-orange-400"></div>
|
||||
</div>
|
||||
<!-- High stock -->
|
||||
<div
|
||||
class="flex items-end ml-2 w-1 h-4 bg-green-100 rounded overflow-hidden"
|
||||
*ngIf="product.stock >= 30">
|
||||
<div class="flex w-full h-full bg-green-400"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Active -->
|
||||
<div class="hidden lg:block">
|
||||
<ng-container *ngIf="product.active">
|
||||
<mat-icon
|
||||
class="text-green-400 icon-size-5"
|
||||
[svgIcon]="'heroicons_solid:check'"></mat-icon>
|
||||
</ng-container>
|
||||
<ng-container *ngIf="!product.active">
|
||||
<mat-icon
|
||||
class="text-gray-400 icon-size-5"
|
||||
[svgIcon]="'heroicons_solid:x'"></mat-icon>
|
||||
</ng-container>
|
||||
</div>
|
||||
|
||||
<!-- Details button -->
|
||||
<div>
|
||||
<button
|
||||
class="min-w-10 min-h-7 h-7 px-2 leading-6"
|
||||
mat-stroked-button
|
||||
(click)="toggleDetails(product.id)">
|
||||
<mat-icon
|
||||
class="icon-size-5"
|
||||
[svgIcon]="selectedProduct?.id === product.id ? 'heroicons_solid:chevron-up' : 'heroicons_solid:chevron-down'"></mat-icon>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</td>
|
||||
<div class="grid">
|
||||
<ng-container *ngIf="selectedProduct?.id === product.id">
|
||||
<ng-container *ngTemplateOutlet="rowDetailsTemplate; context: {$implicit: product}"></ng-container>
|
||||
</ng-container>
|
||||
</div>
|
||||
</ng-container>
|
||||
</ng-container>
|
||||
</div>
|
||||
|
||||
<tr
|
||||
class="shadow"
|
||||
mat-header-row
|
||||
*matHeaderRowDef="productsTableColumns; sticky: true"></tr>
|
||||
<tr
|
||||
class="h-18 hover:bg-gray-100 dark:hover:bg-hover"
|
||||
mat-row
|
||||
*matRowDef="let product; columns: productsTableColumns;"></tr>
|
||||
<tr
|
||||
class="h-0"
|
||||
mat-row
|
||||
*matRowDef="let row; columns: ['productDetails']"></tr>
|
||||
|
||||
</table>
|
||||
|
||||
</div>
|
||||
|
||||
<mat-paginator
|
||||
class="sm:absolute sm:inset-x-0 sm:bottom-0 border-b sm:border-t sm:border-b-0 z-10 bg-gray-50 dark:bg-transparent"
|
||||
[ngClass]="{'pointer-events-none': isLoading}"
|
||||
[length]="pagination.length"
|
||||
[pageIndex]="pagination.page"
|
||||
[pageSize]="pagination.size"
|
||||
[pageSizeOptions]="[5, 10, 25, 100]"
|
||||
[showFirstLastButtons]="true"></mat-paginator>
|
||||
<mat-paginator
|
||||
class="sm:absolute sm:inset-x-0 sm:bottom-0 border-b sm:border-t sm:border-b-0 z-10 bg-gray-50 dark:bg-transparent"
|
||||
[ngClass]="{'pointer-events-none': isLoading}"
|
||||
[length]="pagination.length"
|
||||
[pageIndex]="pagination.page"
|
||||
[pageSize]="pagination.size"
|
||||
[pageSizeOptions]="[5, 10, 25, 100]"
|
||||
[showFirstLastButtons]="true"></mat-paginator>
|
||||
|
||||
</ng-container>
|
||||
</ng-container>
|
||||
|
||||
<ng-template
|
||||
#rowDetailsTemplate
|
||||
let-product>
|
||||
<div class="shadow-lg overflow-hidden">
|
||||
<div class="flex border-b">
|
||||
<!-- Selected product form -->
|
||||
<form
|
||||
class="flex flex-col w-full"
|
||||
[formGroup]="selectedProductForm">
|
||||
|
||||
<div class="flex flex-col sm:flex-row p-8">
|
||||
|
||||
<!-- Product images and status -->
|
||||
<div class="flex flex-col items-center sm:items-start mb-8 sm:mb-0">
|
||||
<div class="flex flex-col items-center">
|
||||
<div class="w-32 h-44 border rounded overflow-hidden">
|
||||
<ng-container *ngIf="selectedProductForm.get('images').value.length; else noImage">
|
||||
<img
|
||||
class="w-full h-full object-cover"
|
||||
[src]="selectedProductForm.get('images').value[selectedProductForm.get('currentImageIndex').value]">
|
||||
</ng-container>
|
||||
<ng-template #noImage>
|
||||
<span class="flex items-center min-h-20 text-lg font-semibold">NO IMAGE</span>
|
||||
</ng-template>
|
||||
</div>
|
||||
<div
|
||||
class="flex items-center mt-2 whitespace-nowrap"
|
||||
*ngIf="selectedProductForm.get('images').value.length">
|
||||
<button
|
||||
mat-icon-button
|
||||
(click)="cycleImages(false)">
|
||||
<mat-icon
|
||||
class="icon-size-5"
|
||||
[svgIcon]="'heroicons_solid:arrow-narrow-left'"></mat-icon>
|
||||
</button>
|
||||
<span class="font-sm mx-2">
|
||||
{{selectedProductForm.get('currentImageIndex').value + 1}} of {{selectedProductForm.get('images').value.length}}
|
||||
</span>
|
||||
<button
|
||||
mat-icon-button
|
||||
(click)="cycleImages(true)">
|
||||
<mat-icon
|
||||
class="icon-size-5"
|
||||
[svgIcon]="'heroicons_solid:arrow-narrow-right'"></mat-icon>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex flex-col mt-8">
|
||||
<span class="font-semibold mb-2">Product status</span>
|
||||
<mat-slide-toggle
|
||||
[formControlName]="'active'"
|
||||
[color]="'primary'">
|
||||
{{selectedProductForm.get('active').value === true ? 'Active' : 'Disabled'}}
|
||||
</mat-slide-toggle>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="flex flex-auto flex-wrap">
|
||||
<!-- Name, SKU & etc. -->
|
||||
<div class="flex flex-col w-full lg:w-2/4 sm:pl-8">
|
||||
|
||||
<!-- Name -->
|
||||
<mat-form-field class="w-full">
|
||||
<mat-label>Name</mat-label>
|
||||
<input
|
||||
matInput
|
||||
[formControlName]="'name'">
|
||||
</mat-form-field>
|
||||
|
||||
<!-- SKU and Barcode -->
|
||||
<div class="flex">
|
||||
<mat-form-field class="w-1/3 pr-2">
|
||||
<mat-label>SKU</mat-label>
|
||||
<input
|
||||
matInput
|
||||
[formControlName]="'sku'">
|
||||
</mat-form-field>
|
||||
<mat-form-field class="w-2/3 pl-2">
|
||||
<mat-label>Barcode</mat-label>
|
||||
<input
|
||||
matInput
|
||||
[formControlName]="'barcode'">
|
||||
</mat-form-field>
|
||||
</div>
|
||||
|
||||
<!-- Category, Brand & Vendor -->
|
||||
<div class="flex">
|
||||
<mat-form-field class="w-1/3 pr-2">
|
||||
<mat-label>Category</mat-label>
|
||||
<mat-select [formControlName]="'category'">
|
||||
<ng-container *ngFor="let category of categories">
|
||||
<mat-option [value]="category.id">
|
||||
{{category.name}}
|
||||
</mat-option>
|
||||
</ng-container>
|
||||
</mat-select>
|
||||
</mat-form-field>
|
||||
<mat-form-field class="w-1/3 px-2">
|
||||
<mat-label>Brand</mat-label>
|
||||
<mat-select [formControlName]="'brand'">
|
||||
<ng-container *ngFor="let brand of brands">
|
||||
<mat-option [value]="brand.id">
|
||||
{{brand.name}}
|
||||
</mat-option>
|
||||
</ng-container>
|
||||
</mat-select>
|
||||
</mat-form-field>
|
||||
<mat-form-field class="w-1/3 pl-2">
|
||||
<mat-label>Vendor</mat-label>
|
||||
<mat-select [formControlName]="'vendor'">
|
||||
<ng-container *ngFor="let vendor of vendors">
|
||||
<mat-option [value]="vendor.id">
|
||||
{{vendor.name}}
|
||||
</mat-option>
|
||||
</ng-container>
|
||||
</mat-select>
|
||||
</mat-form-field>
|
||||
</div>
|
||||
|
||||
<!-- Stock and Reserved -->
|
||||
<div class="flex">
|
||||
<mat-form-field class="w-1/3 pr-2">
|
||||
<mat-label>Stock</mat-label>
|
||||
<input
|
||||
type="number"
|
||||
matInput
|
||||
[formControlName]="'stock'">
|
||||
</mat-form-field>
|
||||
<mat-form-field class="w-1/3 pl-2">
|
||||
<mat-label>Reserved</mat-label>
|
||||
<input
|
||||
type="number"
|
||||
matInput
|
||||
[formControlName]="'reserved'">
|
||||
</mat-form-field>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Cost, Base price, Tax & Price -->
|
||||
<div class="flex flex-col w-full lg:w-1/4 sm:pl-8">
|
||||
<mat-form-field class="w-full">
|
||||
<mat-label>Cost</mat-label>
|
||||
<span matPrefix>$</span>
|
||||
<input
|
||||
matInput
|
||||
[formControlName]="'cost'">
|
||||
</mat-form-field>
|
||||
<mat-form-field class="w-full">
|
||||
<mat-label>Base Price</mat-label>
|
||||
<span matPrefix>$</span>
|
||||
<input
|
||||
matInput
|
||||
[formControlName]="'basePrice'">
|
||||
</mat-form-field>
|
||||
<mat-form-field class="w-full">
|
||||
<mat-label>Tax</mat-label>
|
||||
<span matSuffix>%</span>
|
||||
<input
|
||||
type="number"
|
||||
matInput
|
||||
[formControlName]="'taxPercent'">
|
||||
</mat-form-field>
|
||||
<mat-form-field class="w-full">
|
||||
<mat-label>Price</mat-label>
|
||||
<span matSuffix>$</span>
|
||||
<input
|
||||
matInput
|
||||
[formControlName]="'price'">
|
||||
</mat-form-field>
|
||||
</div>
|
||||
|
||||
<!-- Weight & Tags -->
|
||||
<div class="flex flex-col w-full lg:w-1/4 sm:pl-8">
|
||||
<mat-form-field class="w-full">
|
||||
<mat-label>Weight</mat-label>
|
||||
<span matSuffix>lbs.</span>
|
||||
<input
|
||||
matInput
|
||||
[formControlName]="'weight'">
|
||||
</mat-form-field>
|
||||
|
||||
<!-- Tags -->
|
||||
<span class="mb-px font-medium leading-tight">Tags</span>
|
||||
<div class="mt-1.5 rounded-md border border-gray-300 shadow-sm overflow-hidden">
|
||||
<!-- Header -->
|
||||
<div class="flex items-center -my-px py-2 px-3">
|
||||
<div class="flex items-center flex-auto min-w-0">
|
||||
<mat-icon
|
||||
class="icon-size-5"
|
||||
[svgIcon]="'heroicons_solid:search'"></mat-icon>
|
||||
<input
|
||||
class="min-w-0 ml-2 py-1 border-0"
|
||||
type="text"
|
||||
placeholder="Enter tag name"
|
||||
(input)="filterTags($event)"
|
||||
(keydown)="filterTagsInputKeyDown($event)"
|
||||
[maxLength]="50"
|
||||
#newTagInput>
|
||||
</div>
|
||||
<button
|
||||
class="ml-3 w-8 h-8 min-h-8"
|
||||
mat-icon-button
|
||||
(click)="toggleTagsEditMode()">
|
||||
<mat-icon
|
||||
*ngIf="!tagsEditMode"
|
||||
class="icon-size-5"
|
||||
[svgIcon]="'heroicons_solid:pencil-alt'"></mat-icon>
|
||||
<mat-icon
|
||||
*ngIf="tagsEditMode"
|
||||
class="icon-size-5"
|
||||
[svgIcon]="'heroicons_solid:check'"></mat-icon>
|
||||
</button>
|
||||
</div>
|
||||
<!-- Available tags -->
|
||||
<div class="h-44 leading-none overflow-y-auto border-t">
|
||||
<!-- Tags -->
|
||||
<ng-container *ngIf="!tagsEditMode">
|
||||
<ng-container *ngFor="let tag of filteredTags; trackBy: trackByFn">
|
||||
<mat-checkbox
|
||||
class="flex items-center h-10 min-h-10 px-4"
|
||||
[color]="'primary'"
|
||||
[checked]="selectedProduct.tags.includes(tag.id)"
|
||||
(change)="toggleProductTag(tag, $event)">
|
||||
{{tag.title}}
|
||||
</mat-checkbox>
|
||||
</ng-container>
|
||||
</ng-container>
|
||||
<!-- Tags editing -->
|
||||
<ng-container *ngIf="tagsEditMode">
|
||||
<div class="p-4 space-y-2">
|
||||
<ng-container *ngFor="let tag of filteredTags; trackBy: trackByFn">
|
||||
<mat-form-field class="fuse-mat-dense fuse-mat-no-subscript w-full">
|
||||
<input
|
||||
matInput
|
||||
[value]="tag.title"
|
||||
(input)="updateTagTitle(tag, $event)">
|
||||
<button
|
||||
mat-icon-button
|
||||
(click)="deleteTag(tag)"
|
||||
matSuffix>
|
||||
<mat-icon
|
||||
class="icon-size-5"
|
||||
[svgIcon]="'heroicons_solid:trash'"></mat-icon>
|
||||
</button>
|
||||
</mat-form-field>
|
||||
</ng-container>
|
||||
</div>
|
||||
</ng-container>
|
||||
<div
|
||||
class="flex items-center h-10 min-h-10 -ml-0.5 pl-4 pr-3 leading-none cursor-pointer border-t hover:bg-gray-50 dark:hover:bg-hover"
|
||||
*ngIf="shouldShowCreateTagButton(newTagInput.value)"
|
||||
(click)="createTag(newTagInput.value); newTagInput.value = ''"
|
||||
matRipple>
|
||||
<mat-icon
|
||||
class="mr-2 icon-size-5"
|
||||
[svgIcon]="'heroicons_solid:plus-circle'"></mat-icon>
|
||||
<div class="break-all">Create "<b>{{newTagInput.value}}</b>"</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="flex items-center justify-between w-full border-t px-8 py-4">
|
||||
<button
|
||||
class="-ml-4"
|
||||
mat-button
|
||||
[color]="'warn'"
|
||||
(click)="deleteSelectedProduct()">
|
||||
Delete
|
||||
</button>
|
||||
<div class="flex items-center">
|
||||
<div
|
||||
class="flex items-center mr-4"
|
||||
*ngIf="flashMessage">
|
||||
<ng-container *ngIf="flashMessage === 'success'">
|
||||
<mat-icon
|
||||
class="text-green-500"
|
||||
[svgIcon]="'heroicons_outline:check'"></mat-icon>
|
||||
<span class="ml-2">Product updated</span>
|
||||
</ng-container>
|
||||
<ng-container *ngIf="flashMessage === 'error'">
|
||||
<mat-icon
|
||||
class="text-red-500"
|
||||
[svgIcon]="'heroicons_outline:x'"></mat-icon>
|
||||
<span class="ml-2">An error occurred, try again!</span>
|
||||
</ng-container>
|
||||
</div>
|
||||
<button
|
||||
mat-flat-button
|
||||
[color]="'primary'"
|
||||
(click)="updateSelectedProduct()">
|
||||
Update
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</ng-template>
|
||||
|
||||
<ng-template #noProducts>
|
||||
<div class="p-8 sm:p-16 border-t text-4xl font-semibold tracking-tight text-center">There are no products!</div>
|
||||
</ng-template>
|
||||
|
||||
@@ -12,6 +12,26 @@ import { InventoryService } from 'app/modules/admin/apps/ecommerce/inventory/inv
|
||||
@Component({
|
||||
selector : 'inventory-list',
|
||||
templateUrl : './inventory.component.html',
|
||||
styles : [
|
||||
/* language=SCSS */
|
||||
`
|
||||
.inventory-grid {
|
||||
grid-template-columns: 48px auto 40px;
|
||||
|
||||
@screen sm {
|
||||
grid-template-columns: 48px auto 112px 72px;
|
||||
}
|
||||
|
||||
@screen md {
|
||||
grid-template-columns: 48px 112px auto 112px 72px;
|
||||
}
|
||||
|
||||
@screen lg {
|
||||
grid-template-columns: 48px 112px auto 112px 96px 96px 72px;
|
||||
}
|
||||
}
|
||||
`
|
||||
],
|
||||
encapsulation : ViewEncapsulation.None,
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
animations : fuseAnimations
|
||||
@@ -29,8 +49,6 @@ export class InventoryListComponent implements OnInit, AfterViewInit, OnDestroy
|
||||
flashMessage: 'success' | 'error' | null = null;
|
||||
isLoading: boolean = false;
|
||||
pagination: InventoryPagination;
|
||||
productsCount: number = 0;
|
||||
productsTableColumns: string[] = ['sku', 'name', 'price', 'stock', 'active', 'details'];
|
||||
searchInputControl: FormControl = new FormControl();
|
||||
selectedProduct: InventoryProduct | null = null;
|
||||
selectedProductForm: FormGroup;
|
||||
@@ -121,16 +139,6 @@ export class InventoryListComponent implements OnInit, AfterViewInit, OnDestroy
|
||||
|
||||
// Get the products
|
||||
this.products$ = this._inventoryService.products$;
|
||||
this._inventoryService.products$
|
||||
.pipe(takeUntil(this._unsubscribeAll))
|
||||
.subscribe((products: InventoryProduct[]) => {
|
||||
|
||||
// Update the counts
|
||||
this.productsCount = products.length;
|
||||
|
||||
// Mark for check
|
||||
this._changeDetectorRef.markForCheck();
|
||||
});
|
||||
|
||||
// Get the tags
|
||||
this._inventoryService.tags$
|
||||
@@ -179,28 +187,41 @@ export class InventoryListComponent implements OnInit, AfterViewInit, OnDestroy
|
||||
*/
|
||||
ngAfterViewInit(): void
|
||||
{
|
||||
// If the user changes the sort order...
|
||||
this._sort.sortChange
|
||||
.pipe(takeUntil(this._unsubscribeAll))
|
||||
.subscribe(() => {
|
||||
// Reset back to the first page
|
||||
this._paginator.pageIndex = 0;
|
||||
|
||||
// Close the details
|
||||
this.closeDetails();
|
||||
if ( this._sort && this._paginator )
|
||||
{
|
||||
// Set the initial sort
|
||||
this._sort.sort({
|
||||
id : 'name',
|
||||
start : 'asc',
|
||||
disableClear: true
|
||||
});
|
||||
|
||||
// Get products if sort or page changes
|
||||
merge(this._sort.sortChange, this._paginator.page).pipe(
|
||||
switchMap(() => {
|
||||
this.closeDetails();
|
||||
this.isLoading = true;
|
||||
return this._inventoryService.getProducts(this._paginator.pageIndex, this._paginator.pageSize, this._sort.active, this._sort.direction);
|
||||
}),
|
||||
map(() => {
|
||||
this.isLoading = false;
|
||||
})
|
||||
).subscribe();
|
||||
// Mark for check
|
||||
this._changeDetectorRef.markForCheck();
|
||||
|
||||
// If the user changes the sort order...
|
||||
this._sort.sortChange
|
||||
.pipe(takeUntil(this._unsubscribeAll))
|
||||
.subscribe(() => {
|
||||
// Reset back to the first page
|
||||
this._paginator.pageIndex = 0;
|
||||
|
||||
// Close the details
|
||||
this.closeDetails();
|
||||
});
|
||||
|
||||
// Get products if sort or page changes
|
||||
merge(this._sort.sortChange, this._paginator.page).pipe(
|
||||
switchMap(() => {
|
||||
this.closeDetails();
|
||||
this.isLoading = true;
|
||||
return this._inventoryService.getProducts(this._paginator.pageIndex, this._paginator.pageSize, this._sort.active, this._sort.direction);
|
||||
}),
|
||||
map(() => {
|
||||
this.isLoading = false;
|
||||
})
|
||||
).subscribe();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -239,9 +260,6 @@ export class InventoryListComponent implements OnInit, AfterViewInit, OnDestroy
|
||||
// Set the selected product
|
||||
this.selectedProduct = product;
|
||||
|
||||
// Mark for check
|
||||
this._changeDetectorRef.markForCheck();
|
||||
|
||||
// Fill the form
|
||||
this.selectedProductForm.patchValue(product);
|
||||
|
||||
@@ -335,15 +353,15 @@ export class InventoryListComponent implements OnInit, AfterViewInit, OnDestroy
|
||||
const tag = this.filteredTags[0];
|
||||
const isTagApplied = this.selectedProduct.tags.find(id => id === tag.id);
|
||||
|
||||
// If the found tag is already applied to the contact...
|
||||
// If the found tag is already applied to the product...
|
||||
if ( isTagApplied )
|
||||
{
|
||||
// Remove the tag from the contact
|
||||
// Remove the tag from the product
|
||||
this.removeTagFromProduct(tag);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Otherwise add the tag to the contact
|
||||
// Otherwise add the tag to the product
|
||||
this.addTagToProduct(tag);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
<div class="flex items-center justify-end">
|
||||
<button
|
||||
mat-icon-button
|
||||
[routerLink]="['../']">
|
||||
[routerLink]="['../../']">
|
||||
<mat-icon [svgIcon]="'heroicons_outline:x'"></mat-icon>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
@@ -22,17 +22,17 @@ export class CanDeactivateFileManagerDetails implements CanDeactivate<FileManage
|
||||
nextRoute = nextRoute.firstChild;
|
||||
}
|
||||
|
||||
// If the next state doesn't contain '/files'
|
||||
// If the next state doesn't contain '/file-manager'
|
||||
// it means we are navigating away from the
|
||||
// tasks app
|
||||
// file manager app
|
||||
if ( !nextState.url.includes('/file-manager') )
|
||||
{
|
||||
// Let it navigate
|
||||
return true;
|
||||
}
|
||||
|
||||
// If we are navigating to another task...
|
||||
if ( nextRoute.paramMap.get('id') )
|
||||
// If we are navigating to another item...
|
||||
if ( nextState.url.includes('/details') )
|
||||
{
|
||||
// Just navigate
|
||||
return true;
|
||||
|
||||
@@ -33,6 +33,54 @@ export class FileManagerItemsResolver implements Resolve<any>
|
||||
}
|
||||
}
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root'
|
||||
})
|
||||
export class FileManagerFolderResolver implements Resolve<any>
|
||||
{
|
||||
/**
|
||||
* Constructor
|
||||
*/
|
||||
constructor(
|
||||
private _router: Router,
|
||||
private _fileManagerService: FileManagerService
|
||||
)
|
||||
{
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------------------------------
|
||||
// @ Public methods
|
||||
// -----------------------------------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Resolver
|
||||
*
|
||||
* @param route
|
||||
* @param state
|
||||
*/
|
||||
resolve(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<Item[]>
|
||||
{
|
||||
return this._fileManagerService.getItems(route.paramMap.get('folderId'))
|
||||
.pipe(
|
||||
// Error here means the requested task is not available
|
||||
catchError((error) => {
|
||||
|
||||
// Log the error
|
||||
console.error(error);
|
||||
|
||||
// Get the parent url
|
||||
const parentUrl = state.url.split('/').slice(0, -1).join('/');
|
||||
|
||||
// Navigate to there
|
||||
this._router.navigateByUrl(parentUrl);
|
||||
|
||||
// Throw an error
|
||||
return throwError(error);
|
||||
})
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root'
|
||||
})
|
||||
|
||||
@@ -3,13 +3,30 @@ import { CanDeactivateFileManagerDetails } from 'app/modules/admin/apps/file-man
|
||||
import { FileManagerComponent } from 'app/modules/admin/apps/file-manager/file-manager.component';
|
||||
import { FileManagerListComponent } from 'app/modules/admin/apps/file-manager/list/list.component';
|
||||
import { FileManagerDetailsComponent } from 'app/modules/admin/apps/file-manager/details/details.component';
|
||||
import { FileManagerItemResolver, FileManagerItemsResolver } from 'app/modules/admin/apps/file-manager/file-manager.resolvers';
|
||||
import { FileManagerFolderResolver, FileManagerItemResolver, FileManagerItemsResolver } from 'app/modules/admin/apps/file-manager/file-manager.resolvers';
|
||||
|
||||
export const fileManagerRoutes: Route[] = [
|
||||
{
|
||||
path : '',
|
||||
component: FileManagerComponent,
|
||||
children : [
|
||||
{
|
||||
path : 'folders/:folderId',
|
||||
component: FileManagerListComponent,
|
||||
resolve : {
|
||||
item: FileManagerFolderResolver
|
||||
},
|
||||
children: [
|
||||
{
|
||||
path : 'details/:id',
|
||||
component : FileManagerDetailsComponent,
|
||||
resolve : {
|
||||
item: FileManagerItemResolver
|
||||
},
|
||||
canDeactivate: [CanDeactivateFileManagerDetails]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
path : '',
|
||||
component: FileManagerListComponent,
|
||||
@@ -18,7 +35,7 @@ export const fileManagerRoutes: Route[] = [
|
||||
},
|
||||
children : [
|
||||
{
|
||||
path : ':id',
|
||||
path : 'details/:id',
|
||||
component : FileManagerDetailsComponent,
|
||||
resolve : {
|
||||
item: FileManagerItemResolver
|
||||
|
||||
@@ -47,9 +47,9 @@ export class FileManagerService
|
||||
/**
|
||||
* Get items
|
||||
*/
|
||||
getItems(): Observable<Item[]>
|
||||
getItems(folderId: string | null = null): Observable<Item[]>
|
||||
{
|
||||
return this._httpClient.get<Items>('api/apps/file-manager').pipe(
|
||||
return this._httpClient.get<Items>('api/apps/file-manager', {params: {folderId}}).pipe(
|
||||
tap((response: any) => {
|
||||
this._items.next(response);
|
||||
})
|
||||
|
||||
@@ -2,11 +2,13 @@ export interface Items
|
||||
{
|
||||
folders: Item[];
|
||||
files: Item[];
|
||||
path: any[];
|
||||
}
|
||||
|
||||
export interface Item
|
||||
{
|
||||
id?: string;
|
||||
folderId?: string;
|
||||
name?: string;
|
||||
createdBy?: string;
|
||||
createdAt?: string;
|
||||
|
||||
@@ -26,7 +26,32 @@
|
||||
<div>
|
||||
<div class="text-4xl font-extrabold tracking-tight leading-none">File Manager</div>
|
||||
<div class="flex items-center mt-0.5 font-medium text-secondary">
|
||||
{{items.folders.length}} folders, {{items.files.length}} files
|
||||
<ng-container *ngIf="!items.path.length">
|
||||
{{items.folders.length}} folders, {{items.files.length}} files
|
||||
</ng-container>
|
||||
<!-- Breadcrumbs -->
|
||||
<ng-container *ngIf="items.path.length">
|
||||
<div class="flex items-center space-x-2">
|
||||
<a
|
||||
class="text-primary cursor-pointer"
|
||||
[routerLink]="['/apps/file-manager']">Home
|
||||
</a>
|
||||
<div class="">/</div>
|
||||
<ng-container *ngFor="let path of items.path; let last = last; trackBy: trackByFn">
|
||||
<ng-container *ngIf="!last">
|
||||
<a
|
||||
class="text-primary cursor-pointer"
|
||||
[routerLink]="['/apps/file-manager/folders/', path.id]">{{path.name}}</a>
|
||||
</ng-container>
|
||||
<ng-container *ngIf="last">
|
||||
<div>{{path.name}}</div>
|
||||
</ng-container>
|
||||
<ng-container *ngIf="!last">
|
||||
<div class="">/</div>
|
||||
</ng-container>
|
||||
</ng-container>
|
||||
</div>
|
||||
</ng-container>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Actions -->
|
||||
@@ -42,75 +67,95 @@
|
||||
</div>
|
||||
|
||||
<!-- Items list -->
|
||||
<ng-container *ngIf="items && items.folders.length && items.files.length > 0; else noItems">
|
||||
<div class="p-6 md:p-8">
|
||||
<ng-container *ngIf="items && (items.folders.length > 0 || items.files.length > 0); else noItems">
|
||||
<div class="p-6 md:p-8 space-y-8">
|
||||
<!-- Folders -->
|
||||
<div class="font-medium">Folders</div>
|
||||
<div
|
||||
class="flex flex-wrap -m-2 mt-2">
|
||||
<ng-container *ngFor="let folder of items.folders; trackBy:trackByFn">
|
||||
<ng-container *ngTemplateOutlet="item, context: {$implicit: folder}"></ng-container>
|
||||
</ng-container>
|
||||
</div>
|
||||
|
||||
<!-- Files -->
|
||||
<div class="font-medium mt-8">Files</div>
|
||||
<div
|
||||
class="flex flex-wrap -m-2 mt-2">
|
||||
<ng-container *ngFor="let file of items.files; trackBy:trackByFn">
|
||||
<ng-container *ngTemplateOutlet="item, context: {$implicit: file}"></ng-container>
|
||||
</ng-container>
|
||||
</div>
|
||||
</div>
|
||||
</ng-container>
|
||||
|
||||
<!-- Item template -->
|
||||
<ng-template
|
||||
#item
|
||||
let-item>
|
||||
<a
|
||||
class="flex flex-col w-40 h-40 m-2 p-4 shadow rounded-2xl cursor-pointer bg-card"
|
||||
[routerLink]="['./', item.id]">
|
||||
<div class="aspect-w-9 aspect-h-6">
|
||||
<div class="flex items-center justify-center">
|
||||
<!-- Icons -->
|
||||
<ng-container [ngSwitch]="item.type">
|
||||
<!-- Folder -->
|
||||
<ng-container *ngSwitchCase="'folder'">
|
||||
<mat-icon
|
||||
class="icon-size-14 text-hint"
|
||||
[svgIcon]="'iconsmind:folder'"></mat-icon>
|
||||
</ng-container>
|
||||
<!-- File -->
|
||||
<ng-container *ngSwitchDefault>
|
||||
<div class="relative">
|
||||
<mat-icon
|
||||
class="icon-size-14 text-hint"
|
||||
[svgIcon]="'iconsmind:file'"></mat-icon>
|
||||
<div
|
||||
class="absolute left-0 bottom-0 px-1.5 rounded text-sm font-semibold leading-5 text-white"
|
||||
[class.bg-red-600]="item.type === 'PDF'"
|
||||
[class.bg-blue-600]="item.type === 'DOC'"
|
||||
[class.bg-green-600]="item.type === 'XLS'"
|
||||
[class.bg-gray-600]="item.type === 'TXT'"
|
||||
[class.bg-amber-600]="item.type === 'JPG'">
|
||||
{{item.type.toUpperCase()}}
|
||||
</div>
|
||||
<ng-container *ngIf="items.folders.length > 0">
|
||||
<div>
|
||||
<div class="font-medium">Folders</div>
|
||||
<div
|
||||
class="flex flex-wrap -m-2 mt-2">
|
||||
<ng-container *ngFor="let folder of items.folders; trackBy:trackByFn">
|
||||
<div class="relative w-40 h-40 m-2 p-4 shadow rounded-2xl bg-card">
|
||||
<a
|
||||
class="absolute z-20 top-1.5 right-1.5 w-8 h-8 min-h-8"
|
||||
(click)="$event.preventDefault()"
|
||||
[routerLink]="['./details/', folder.id]"
|
||||
mat-icon-button>
|
||||
<mat-icon
|
||||
class="icon-size-5"
|
||||
[svgIcon]="'heroicons_solid:information-circle'"></mat-icon>
|
||||
</a>
|
||||
<a
|
||||
class="z-10 absolute inset-0 flex flex-col p-4 cursor-pointer"
|
||||
[routerLink]="['/apps/file-manager/folders/', folder.id]">
|
||||
<div class="aspect-w-9 aspect-h-6">
|
||||
<div class="flex items-center justify-center">
|
||||
<!-- Icon -->
|
||||
<mat-icon
|
||||
class="icon-size-14 text-hint"
|
||||
[svgIcon]="'iconsmind:folder'"></mat-icon>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex flex-col flex-auto justify-center text-center text-sm font-medium">
|
||||
<div
|
||||
class="truncate"
|
||||
[matTooltip]="folder.name">{{folder.name}}</div>
|
||||
<ng-container *ngIf="folder.contents">
|
||||
<div class="text-secondary truncate">{{folder.contents}}</div>
|
||||
</ng-container>
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
</ng-container>
|
||||
</ng-container>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex flex-col flex-auto justify-center text-center text-sm font-medium">
|
||||
<div
|
||||
class="truncate"
|
||||
[matTooltip]="item.name">{{item.name}}</div>
|
||||
<ng-container *ngIf="item.contents">
|
||||
<div class="text-secondary truncate">{{item.contents}}</div>
|
||||
</ng-container>
|
||||
</div>
|
||||
</a>
|
||||
</ng-template>
|
||||
</ng-container>
|
||||
|
||||
<!-- Files -->
|
||||
<ng-container *ngIf="items.files.length > 0">
|
||||
<div>
|
||||
<div class="font-medium">Files</div>
|
||||
<div
|
||||
class="flex flex-wrap -m-2 mt-2">
|
||||
<ng-container *ngFor="let file of items.files; trackBy:trackByFn">
|
||||
<a
|
||||
class="flex flex-col w-40 h-40 m-2 p-4 shadow rounded-2xl cursor-pointer bg-card"
|
||||
[routerLink]="['./details/', file.id]">
|
||||
<div class="aspect-w-9 aspect-h-6">
|
||||
<div class="flex items-center justify-center">
|
||||
<!-- Icons -->
|
||||
<div class="relative">
|
||||
<mat-icon
|
||||
class="icon-size-14 text-hint"
|
||||
[svgIcon]="'iconsmind:file'"></mat-icon>
|
||||
<div
|
||||
class="absolute left-0 bottom-0 px-1.5 rounded text-sm font-semibold leading-5 text-white"
|
||||
[class.bg-red-600]="file.type === 'PDF'"
|
||||
[class.bg-blue-600]="file.type === 'DOC'"
|
||||
[class.bg-green-600]="file.type === 'XLS'"
|
||||
[class.bg-gray-600]="file.type === 'TXT'"
|
||||
[class.bg-amber-600]="file.type === 'JPG'">
|
||||
{{file.type.toUpperCase()}}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex flex-col flex-auto justify-center text-center text-sm font-medium">
|
||||
<div
|
||||
class="truncate"
|
||||
[matTooltip]="file.name">{{file.name}}</div>
|
||||
<ng-container *ngIf="file.contents">
|
||||
<div class="text-secondary truncate">{{file.contents}}</div>
|
||||
</ng-container>
|
||||
</div>
|
||||
</a>
|
||||
</ng-container>
|
||||
</div>
|
||||
</div>
|
||||
</ng-container>
|
||||
</div>
|
||||
</ng-container>
|
||||
|
||||
<!-- No items template -->
|
||||
<ng-template #noItems>
|
||||
|
||||
@@ -74,11 +74,10 @@
|
||||
<mat-form-field class="fuse-mat-textarea w-full">
|
||||
<textarea
|
||||
matInput
|
||||
[cdkTextareaAutosize]
|
||||
[cdkAutosizeMinRows]="5"
|
||||
[cdkAutosizeMaxRows]="5"
|
||||
[formControlName]="'message'"
|
||||
[required]="true"></textarea>
|
||||
[required]="true"
|
||||
[rows]="5"
|
||||
matTextareaAutosize></textarea>
|
||||
<mat-label>Message</mat-label>
|
||||
<mat-error *ngIf="supportForm.get('message').hasError('required')">
|
||||
Required
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
<!-- Header -->
|
||||
<div class="flex flex-0 items-center justify-between h-16 pr-3 sm:pr-5 pl-6 sm:pl-8 bg-primary text-on-primary">
|
||||
<div class="text-lg">New Message</div>
|
||||
<div class="text-lg font-medium">New Message</div>
|
||||
<button
|
||||
mat-icon-button
|
||||
(click)="saveAndClose()"
|
||||
|
||||
@@ -27,13 +27,13 @@
|
||||
(input)="updateNoteDetails(note)">
|
||||
</div>
|
||||
<!-- Note -->
|
||||
<div>
|
||||
<div class="flex w-full py-5 px-2">
|
||||
<textarea
|
||||
class="w-full my-2.5 p-2"
|
||||
fuseAutogrow
|
||||
class="w-full"
|
||||
[placeholder]="'Note'"
|
||||
[(ngModel)]="note.content"
|
||||
(input)="updateNoteDetails(note)"></textarea>
|
||||
(input)="updateNoteDetails(note)"
|
||||
matTextareaAutosize></textarea>
|
||||
</div>
|
||||
<!-- Tasks -->
|
||||
<ng-container *ngIf="note.tasks">
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user