diff --git a/.editorconfig b/.editorconfig index 6e87a003..ec967c61 100644 --- a/.editorconfig +++ b/.editorconfig @@ -1,13 +1,6 @@ -# Editor configuration, see http://editorconfig.org -root = true - [*] -charset = utf-8 -indent_style = space -indent_size = 2 -insert_final_newline = true -trim_trailing_whitespace = true - -[*.md] -max_line_length = off -trim_trailing_whitespace = false +charset=utf-8 +end_of_line=lf +insert_final_newline=false +indent_style=space +indent_size=4 diff --git a/README.md b/README.md index 81eacd6e..88a5fc88 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ -# Fuse2 +# Fuse - Angular -Material Design Admin Template with Angular 6+ and Angular Material 2 +Material Design Admin Template with Angular 6+ and Angular Material ## The Community diff --git a/package-lock.json b/package-lock.json index ca4a06f4..5f7f5482 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,36 +1,36 @@ { "name": "fuse", - "version": "6.0.1", + "version": "6.1.0", "lockfileVersion": 1, "requires": true, "dependencies": { "@agm/core": { - "version": "1.0.0-beta.2", - "resolved": "https://registry.npmjs.org/@agm/core/-/core-1.0.0-beta.2.tgz", - "integrity": "sha512-3bdfvkWDmJszpj/F6Fzgv7sks0cs/cUEQPfs37tcJFz3jc62SsXy4TGb/WJT8FpH2nSGE6DonP8lXuFxB0lblQ==" + "version": "1.0.0-beta.3", + "resolved": "https://registry.npmjs.org/@agm/core/-/core-1.0.0-beta.3.tgz", + "integrity": "sha512-nsyergarmMB4JCw7KGujj86ulgRYhEk8zXKRiJZdnju/irLvazQ/9Anlfsf1Rc5yph8sZrmQDwqLGZ6AqHhnzA==" }, "@angular-devkit/architect": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/@angular-devkit/architect/-/architect-0.6.0.tgz", - "integrity": "sha512-d/H8DxNk4f+EA/1BCP6QREyRRgd9Ul+PzFaObf0x6eEVRGylyKlA3vx2EepPm+P3lij0vRVhF08hDwJJ9n0jbQ==", + "version": "0.6.8", + "resolved": "https://registry.npmjs.org/@angular-devkit/architect/-/architect-0.6.8.tgz", + "integrity": "sha512-ZKTm/zC61iY9IBHOEAKoMSzZpvhkmv+1O/HHzpHEuR551jCzu6vSyCmMY9Z7GBcccscCV+hjeSMwgFrFRcqlkw==", "dev": true, "requires": { - "@angular-devkit/core": "0.6.0", + "@angular-devkit/core": "0.6.8", "rxjs": "^6.0.0" } }, "@angular-devkit/build-angular": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/@angular-devkit/build-angular/-/build-angular-0.6.0.tgz", - "integrity": "sha512-HUrB9g8Dk1SQUlKrfDUkH97kiaOlriDBYULV5TBwonMj7cih3hUaPmcyHTqKrz/GzGTF2YXMT9DYo0hThWcdGA==", + "version": "0.6.8", + "resolved": "https://registry.npmjs.org/@angular-devkit/build-angular/-/build-angular-0.6.8.tgz", + "integrity": "sha512-VGqYAk8jpISraz2UHfsDre270NOUmV0CTSZw2p9sm5g/XIr5m+IHetFZz3gpoAr9+If2aFTs8Rt3sGdCRzwBqA==", "dev": true, "requires": { - "@angular-devkit/architect": "0.6.0", - "@angular-devkit/build-optimizer": "0.6.0", - "@angular-devkit/core": "0.6.0", - "@ngtools/webpack": "6.0.0", + "@angular-devkit/architect": "0.6.8", + "@angular-devkit/build-optimizer": "0.6.8", + "@angular-devkit/core": "0.6.8", + "@ngtools/webpack": "6.0.8", "ajv": "~6.4.0", - "autoprefixer": "^8.1.0", + "autoprefixer": "^8.4.1", "cache-loader": "^1.2.2", "chalk": "~2.2.2", "circular-dependency-plugin": "^5.0.2", @@ -42,21 +42,21 @@ "istanbul": "^0.4.5", "istanbul-instrumenter-loader": "^3.0.1", "karma-source-map-support": "^1.2.0", - "less": "^3.0.2", + "less": "^3.0.4", "less-loader": "^4.1.0", "license-webpack-plugin": "^1.3.1", "lodash": "^4.17.4", "memory-fs": "^0.4.1", "mini-css-extract-plugin": "~0.4.0", "minimatch": "^3.0.4", - "node-sass": "^4.8.3", + "node-sass": "^4.9.0", "opn": "^5.1.0", "parse5": "^4.0.0", "portfinder": "^1.0.13", - "postcss": "^6.0.19", + "postcss": "^6.0.22", "postcss-import": "^11.1.0", - "postcss-loader": "^2.1.4", - "postcss-url": "^7.3.1", + "postcss-loader": "^2.1.5", + "postcss-url": "^7.3.2", "raw-loader": "^0.5.1", "resolve": "^1.5.0", "rxjs": "^6.0.0", @@ -70,7 +70,7 @@ "tree-kill": "^1.2.0", "uglifyjs-webpack-plugin": "^1.2.5", "url-loader": "^1.0.1", - "webpack": "~4.6.0", + "webpack": "~4.8.1", "webpack-dev-middleware": "^3.1.3", "webpack-dev-server": "^3.1.4", "webpack-merge": "^4.1.2", @@ -79,21 +79,29 @@ } }, "@angular-devkit/build-optimizer": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/@angular-devkit/build-optimizer/-/build-optimizer-0.6.0.tgz", - "integrity": "sha512-XV6NEf5G3iuXnIUpvSuwGSyTkIP5muS4NKbOWFpqqQhbQ0jacJ9KC3uXSBITD7zZD8ywA3Yq84mPl8c9pLKyXw==", + "version": "0.6.8", + "resolved": "https://registry.npmjs.org/@angular-devkit/build-optimizer/-/build-optimizer-0.6.8.tgz", + "integrity": "sha512-of5syQbv3uNPp4AQkfRecfnp8AE8kvffbfYi+FFPZ6OGr7e59T1fGwk6+Zgb2qQFQg8HO2tzWI/uygtLIqmbmw==", "dev": true, "requires": { "loader-utils": "^1.1.0", "source-map": "^0.5.6", - "typescript": "~2.7.2", + "typescript": "~2.9.1", "webpack-sources": "^1.1.0" + }, + "dependencies": { + "typescript": { + "version": "2.9.1", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-2.9.1.tgz", + "integrity": "sha512-h6pM2f/GDchCFlldnriOhs1QHuwbnmj6/v7499eMHqPeW4V2G0elua2eIc2nu8v2NdHV0Gm+tzX83Hr6nUFjQA==", + "dev": true + } } }, "@angular-devkit/core": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/@angular-devkit/core/-/core-0.6.0.tgz", - "integrity": "sha512-hM1AOSF/+XZpv350pODPgoO/2QL61tfRlCXf3u4zHxkXdcboFKGCIi7VEu7TYMWSQzujcTFJciVBrgf/IfQ3cA==", + "version": "0.6.8", + "resolved": "https://registry.npmjs.org/@angular-devkit/core/-/core-0.6.8.tgz", + "integrity": "sha512-rkIa1OSVWTt4g9leLSK/PsqOj3HZbDKHbZjqlslyfVa3AyCeiumFoOgViOVXlYgPX3HHDbE5uH24nyUWSD8uww==", "dev": true, "requires": { "ajv": "~6.4.0", @@ -103,43 +111,43 @@ } }, "@angular-devkit/schematics": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/@angular-devkit/schematics/-/schematics-0.6.0.tgz", - "integrity": "sha512-TK1wdBMXt6N2T8SUyqx45+HntvFknHyNQpGWvnQZLE/f0y9otCOAarVGxbDaxznc1SNYSPNckSQi8rjEsUNVsw==", + "version": "0.6.8", + "resolved": "https://registry.npmjs.org/@angular-devkit/schematics/-/schematics-0.6.8.tgz", + "integrity": "sha512-R4YqAUdo62wtrhX/5HSRGSKXNTWqfQb66ZE6m8jj6GEJNFKdNXMdxOchxr07LCiKTxfh1w6G3nGzxIsu/+D4KA==", "dev": true, "requires": { - "@angular-devkit/core": "0.6.0", + "@angular-devkit/core": "0.6.8", "rxjs": "^6.0.0" } }, "@angular/animations": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/@angular/animations/-/animations-6.0.0.tgz", - "integrity": "sha512-jl3WZmM/csNeyzdb1cEEc5cUX7jLn3NvPYEiP/ZkKmib0XBGIGBBv7xiuoivTJFJsE4/N5sCFEHRFLnuBBE+OA==", + "version": "6.0.5", + "resolved": "https://registry.npmjs.org/@angular/animations/-/animations-6.0.5.tgz", + "integrity": "sha512-zW/qX3CvsuRDOcTNFFSf7uXktvq1jRrfKR8LdGQ/DER1GU3o8pR3z3H8gHy8lAFc3PESfETtzXinKUNzvTDfpA==", "requires": { "tslib": "^1.9.0" } }, "@angular/cdk": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/@angular/cdk/-/cdk-6.0.1.tgz", - "integrity": "sha512-f8WAY/PC4etTWhtPDuu5zRy+5+qUWSnW+6PidfYAHHdVGu+90H8qIKA27VOW/RWk+oZnl2SC2LVg4G7hggio+A==", + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/@angular/cdk/-/cdk-6.2.1.tgz", + "integrity": "sha512-uwW4eIGJKqOkR+ew6YcEAh1J4SP98jdyDpsZ4IEMkV9+jXcKfcwcxGFpZvs9wJsAvAr8EgNmZ8h+iuZLwJsvmA==", "requires": { "tslib": "^1.7.1" } }, "@angular/cli": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/@angular/cli/-/cli-6.0.0.tgz", - "integrity": "sha512-IGYewWdCpWRDJF/rA1y5R9MwDkO6gvxWSC27FTUNhkymZr+BUY7UgOnp1uwNtU/lLi7V9D28Pd4btOvrd2y5fA==", + "version": "6.0.8", + "resolved": "https://registry.npmjs.org/@angular/cli/-/cli-6.0.8.tgz", + "integrity": "sha512-DhH1Zq5Yonthw6zh6W07fhf+9XrAZbD1fcQ0MrmbxlieCfLlTAdBqyK2LavFCKwSZkUMLF6UHM3+jiNRVZSSIg==", "dev": true, "requires": { - "@angular-devkit/architect": "0.6.0", - "@angular-devkit/core": "0.6.0", - "@angular-devkit/schematics": "0.6.0", - "@schematics/angular": "0.6.0", - "@schematics/update": "0.6.0", - "opn": "~5.1.0", + "@angular-devkit/architect": "0.6.8", + "@angular-devkit/core": "0.6.8", + "@angular-devkit/schematics": "0.6.8", + "@schematics/angular": "0.6.8", + "@schematics/update": "0.6.8", + "opn": "~5.3.0", "resolve": "^1.1.7", "rxjs": "^6.0.0", "semver": "^5.1.0", @@ -154,15 +162,6 @@ "integrity": "sha1-1UVjW+HjPFQmScaRc+Xeas+uNN0=", "dev": true }, - "opn": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/opn/-/opn-5.1.0.tgz", - "integrity": "sha512-iPNl7SyM8L30Rm1sjGdLLheyHVw5YXVfi3SKWJzBI7efxRwHojfRFjwE/OLM6qp9xJYMgab8WicTU1cPoY+Hpg==", - "dev": true, - "requires": { - "is-wsl": "^1.1.0" - } - }, "yargs-parser": { "version": "10.0.0", "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-10.0.0.tgz", @@ -175,31 +174,31 @@ } }, "@angular/common": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/@angular/common/-/common-6.0.0.tgz", - "integrity": "sha512-oo/KESihAZo0FsZPHthO9PYhanN4Q+Lo7Lb2HNbWnD+xRIPa1yFC12JOWiD+SPPfFGWMI6aW3wAlcoej1+QKSw==", + "version": "6.0.5", + "resolved": "https://registry.npmjs.org/@angular/common/-/common-6.0.5.tgz", + "integrity": "sha512-xL4Aq+uGQcmHYs90WSKsS9vBC1XO042hM5lSVz+zyYtYzYHdt/Qg1CIuR3zkP+8DG+mf1QZqbg5YtQx5XykmgA==", "requires": { "tslib": "^1.9.0" } }, "@angular/compiler": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/@angular/compiler/-/compiler-6.0.0.tgz", - "integrity": "sha512-UsYfsvHf4VVtkhzM7tyabh8co7gqWZTm3p79hbLDeyCEojl0AkrwbSgh0DQnKRxp4Tu3DEeeDkg1ahA7n19I8A==", + "version": "6.0.5", + "resolved": "https://registry.npmjs.org/@angular/compiler/-/compiler-6.0.5.tgz", + "integrity": "sha512-Oe0VRCyKfHLatalRuXjCdgaY6hhiMXEL/ueknMJFC0+xA73mEchmLYXj64/1ed753cjnLOM2qbVVwqhc26tmEg==", "requires": { "tslib": "^1.9.0" } }, "@angular/compiler-cli": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/@angular/compiler-cli/-/compiler-cli-6.0.0.tgz", - "integrity": "sha512-RV0xTSTPT3yOnbS5Gx6lMAETQeTUr72Ifu0+JZh9AV07xGVislZ+SdQGSeNgXoqxise6e65lJp3Nrb5KE4Lv6g==", + "version": "6.0.5", + "resolved": "https://registry.npmjs.org/@angular/compiler-cli/-/compiler-cli-6.0.5.tgz", + "integrity": "sha512-onRlVLWo1mTdyxLMRtW4iPntTUglJl9T0hacRlscKKlAUT8jaSfqIyknCF3jEXJrTnfKdypen053U7g2ajifrA==", "dev": true, "requires": { "chokidar": "^1.4.2", "minimist": "^1.2.0", "reflect-metadata": "^0.1.2", - "tsickle": "^0.27.2" + "tsickle": "^0.29.0" }, "dependencies": { "anymatch": { @@ -336,79 +335,79 @@ } }, "@angular/core": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/@angular/core/-/core-6.0.0.tgz", - "integrity": "sha512-52X2ZKXOoaMRYaC/ycHePTkXuwku8qJFxoEXAFBItAkk9rebLU4CD8Fx1Z9vUd8aWu1uFfLTxqkgE0mUyBANZw==", + "version": "6.0.5", + "resolved": "https://registry.npmjs.org/@angular/core/-/core-6.0.5.tgz", + "integrity": "sha512-yG4Qz5wHWgFYOCtX62F8MmJ1wZwZA1ALbyQC+WAZfi7Y8Asx8TShJ+3QKUDYwO1jj530pqNbfauDTCmPzzPvaQ==", "requires": { "tslib": "^1.9.0" } }, "@angular/flex-layout": { - "version": "6.0.0-beta.15", - "resolved": "https://registry.npmjs.org/@angular/flex-layout/-/flex-layout-6.0.0-beta.15.tgz", - "integrity": "sha512-Tu3BMzxAJppLnHicII8gUS2dnkSfAEy5/rxI6eSo6CH9z5uz+h/Q2gj2j7V53y9IyqTgIugvKzPa9/3jB+R8/w==", + "version": "6.0.0-beta.16", + "resolved": "https://registry.npmjs.org/@angular/flex-layout/-/flex-layout-6.0.0-beta.16.tgz", + "integrity": "sha512-0AYtIBGrEJshdFMc6TXGloCkD19YTCRKVJl6xZHX4H5dLnUn+daqXcbh4UsWhayevnLp85HEf2ViHLmTa6jv3g==", "requires": { "tslib": "^1.7.1" } }, "@angular/forms": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/@angular/forms/-/forms-6.0.0.tgz", - "integrity": "sha512-4eVfCcSyPRhml7Xa6ia/DgDl3JhOnEdBdHo+jads1YL5AF6D08Tthngjf3KjuctGqZDACPyxNt6ciX4g8IbGCA==", + "version": "6.0.5", + "resolved": "https://registry.npmjs.org/@angular/forms/-/forms-6.0.5.tgz", + "integrity": "sha512-d1SdhAQ/W1n3vtm1lp5y16EaUylcZ2wftLUj6MSne3bH/2MJ6JsxJKwX+MfPcQCo+DCfG5bF0UMCa1KAwUQthQ==", "requires": { "tslib": "^1.9.0" } }, "@angular/http": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/@angular/http/-/http-6.0.0.tgz", - "integrity": "sha512-nBZ4KmXx0KR+cIPOMBsJpPhcec5wSCbVtTYRH0zTxmzTmqM3g6+i0PECpqbVgcQEGiOxBLcmXNWfXZl5czpiqw==", + "version": "6.0.5", + "resolved": "https://registry.npmjs.org/@angular/http/-/http-6.0.5.tgz", + "integrity": "sha512-N9lx1s1h4wki1ob4qne3FdyAWG3TcCAGnUAjDmZ1+c/hhxtcv0iEJ22nBrGkPIsUxIPXg0JgsD1hKhu5DGEbWg==", "requires": { "tslib": "^1.9.0" } }, "@angular/language-service": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/@angular/language-service/-/language-service-6.0.0.tgz", - "integrity": "sha512-ysNUM8uec9Kf5Te5HBT6b3G5CLlxOKAXtk+bY1sqbE9sMDZFWQhqR66QzfWdOPRyj9KKrwuKZd9ArMjAbOVNYw==", + "version": "6.0.5", + "resolved": "https://registry.npmjs.org/@angular/language-service/-/language-service-6.0.5.tgz", + "integrity": "sha512-PH06chMTcWTLfVxZqpXksIx9969N/azEghYx0U+MzlGomeaaBXr7RuZWHRVn/lD5XljrqdWAQSMc+abbn1oKgg==", "dev": true }, "@angular/material": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/@angular/material/-/material-6.0.1.tgz", - "integrity": "sha512-QbAFoE3wruv/XsAKJirGn0fSfmVIBMCrtGe55hZjOVhvRbrnXJ61VSr4zrO/LDPzT17yXhf3ZaB3Yp/4GmRk8w==", + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/@angular/material/-/material-6.2.1.tgz", + "integrity": "sha512-SBoUXxHknkgwzp5pNDHW0jyrTM0d0Tk4lVyDbtEX8VEPtXqG5nL3BSgyjpJbTvqlmy2kOooUu3qgAmt87VH9lw==", "requires": { "tslib": "^1.7.1" } }, "@angular/material-moment-adapter": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/@angular/material-moment-adapter/-/material-moment-adapter-6.0.1.tgz", - "integrity": "sha512-h7+EFGsh+x3gtrmOYfspFy8KRsDV1Pyw/O+09U2RQ/gnbwfXjjMPpTa9hHE5rcY4y37vJ6smLubleCbJw50r/w==", + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/@angular/material-moment-adapter/-/material-moment-adapter-6.2.1.tgz", + "integrity": "sha512-mZA/gUDI/B6lnKBx0Qov3920MdNhOvVk0oQq/wrxgt2I25AVbpKZO2d8PSCBATQzWjqUwN3GKtcQFx0bPtvNCQ==", "requires": { "tslib": "^1.7.1" } }, "@angular/platform-browser": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/@angular/platform-browser/-/platform-browser-6.0.0.tgz", - "integrity": "sha512-ExI1o40BJIbJKFz1p1ivGSgLA1+T0uUo8rjheOZhcGDwCNx54/RapCFLdcHCNiW8NzAIzx+kt4DdXnCSKitnDA==", + "version": "6.0.5", + "resolved": "https://registry.npmjs.org/@angular/platform-browser/-/platform-browser-6.0.5.tgz", + "integrity": "sha512-FSsA9C3cJa7S4SPUAhypKlTQf4uA4hiqx/h65v7frDiyRVHv22oWKX7aKmyyb9oP5FHN/TDeQiRn4m8XNqG6AQ==", "requires": { "tslib": "^1.9.0" } }, "@angular/platform-browser-dynamic": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/@angular/platform-browser-dynamic/-/platform-browser-dynamic-6.0.0.tgz", - "integrity": "sha512-yk4wZYn2bosuvDaYaEq6UuEeI966/28uCljm5iBfo3l8Vuv2IChk5664M68O6C+KwWzCCWDHvIqm0q178YUYug==", + "version": "6.0.5", + "resolved": "https://registry.npmjs.org/@angular/platform-browser-dynamic/-/platform-browser-dynamic-6.0.5.tgz", + "integrity": "sha512-TTSLOMVrgRXI29xmBWsnSp8187vbWnbj0YEehuyup2FmltUl+H5Vms7poWV9/6fI3RnW3Yg9Ziv3T5iKqsiADQ==", "requires": { "tslib": "^1.9.0" } }, "@angular/router": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/@angular/router/-/router-6.0.0.tgz", - "integrity": "sha512-ONrfgfYmFGz0Ht2MvymMvBMxPI9w5037ZfJWpTu1/Xo1XmVOawzj2SvYfEzTqexznWcTAALggq/A23k8r9ArKA==", + "version": "6.0.5", + "resolved": "https://registry.npmjs.org/@angular/router/-/router-6.0.5.tgz", + "integrity": "sha512-M3cb5CDX+WvkM2xmFeP64zPwLJ6by6cyzl5OCfEQjoTGKOFY7N2B4kHAOw5KJN3nIEd0PersSBgf11Y9g7GPwA==", "requires": { "tslib": "^1.9.0" } @@ -420,63 +419,63 @@ "dev": true }, "@ngrx/effects": { - "version": "6.0.0-beta.1", - "resolved": "https://registry.npmjs.org/@ngrx/effects/-/effects-6.0.0-beta.1.tgz", - "integrity": "sha512-X0QF1Yymc564eE8ryJi1OTf/ssCoM4hLOZRr7vPPILDwbQnnMTUDqrcVaYEXoOoMvzZqvUwDrpM2F6pmGCosyA==" + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/@ngrx/effects/-/effects-6.0.1.tgz", + "integrity": "sha512-YS68D7E1qKbbOIzV6Iyfv6BY3CrTNi8nBgGJ6whTi6f7Y0apXySvNj9aOQyzuJsePWziu6h0uJhy2ZFT/iELyg==" }, "@ngrx/router-store": { - "version": "6.0.0-beta.1", - "resolved": "https://registry.npmjs.org/@ngrx/router-store/-/router-store-6.0.0-beta.1.tgz", - "integrity": "sha512-6wPBexp+KfOPdLsExgI+S0T2DaQUvRVlmiMq8ZmvoEydBryjxQdBLgTunF6t45WIxfuXsSisqTWPwW8tuN5Zzw==" + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/@ngrx/router-store/-/router-store-6.0.1.tgz", + "integrity": "sha512-Nz6HI6cGcWZtRP8Z1eWH0jhkmukQYSpH5AptCcXMjOP2MorHv23Ddw1O+0W6hF8SYX1JvGdaQ2BUJS00MaKfKw==" }, "@ngrx/store": { - "version": "6.0.0-beta.1", - "resolved": "https://registry.npmjs.org/@ngrx/store/-/store-6.0.0-beta.1.tgz", - "integrity": "sha512-P/Tn3EccUigPvE2ED4hhF+yuCGj1qH44NWxbJmH5JISj8d+h5vpiv11YyINyoRVcU3o8TaFj4dRaZZOm9kIH1g==" + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/@ngrx/store/-/store-6.0.1.tgz", + "integrity": "sha512-cSgfT8CgpOr6BOQac9M3DH6QQC5gxCVjdEcZH//Zn/kwdse86X73iK7KWv6B6AiIEdyVbFfggXNZwd/HiyLGOA==" }, "@ngrx/store-devtools": { - "version": "6.0.0-beta.1", - "resolved": "https://registry.npmjs.org/@ngrx/store-devtools/-/store-devtools-6.0.0-beta.1.tgz", - "integrity": "sha512-VKtkyN2yjnLvnBUtMlq6j1BW0WnqCge+5t5xNbmZgppm9AD1BhelB3GuhOG+g/LzN1sZ2u+JM1A+NJvzyAyiJg==" + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/@ngrx/store-devtools/-/store-devtools-6.0.1.tgz", + "integrity": "sha512-eZyguQvIltJuhCVgPPR1IyMAztykRuvGalwCH1G2ODWKGZPNrWlJbxVMqzUeSJTBS268RIFIkMTwEDKi/xCQoQ==" }, "@ngtools/webpack": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/@ngtools/webpack/-/webpack-6.0.0.tgz", - "integrity": "sha512-ULZnn1sFmVZ4o8LRWRk8BVnJzSpfjvpjTC2lsC/5DavPwpYLbMEdecwE5OIZhkXUr6QLZebPHEjlazesWHwqrA==", + "version": "6.0.8", + "resolved": "https://registry.npmjs.org/@ngtools/webpack/-/webpack-6.0.8.tgz", + "integrity": "sha512-jorGpTd82ILbyUwg4JQekovHFaYwSMlZan4f7x+sd3+2WgyL3Z1+ZbVSGKvXZWKS/mAVx7eLkRikzJkuC4FgHw==", "dev": true, "requires": { - "@angular-devkit/core": "0.6.0", + "@angular-devkit/core": "0.6.8", "tree-kill": "^1.0.0", "webpack-sources": "^1.1.0" } }, "@ngx-translate/core": { - "version": "10.0.1", - "resolved": "https://registry.npmjs.org/@ngx-translate/core/-/core-10.0.1.tgz", - "integrity": "sha1-nzo+0HfoR90NKVGmZNpu40igbSI=", + "version": "10.0.2", + "resolved": "https://registry.npmjs.org/@ngx-translate/core/-/core-10.0.2.tgz", + "integrity": "sha512-7nM3DrJaqKswwtJlbu2kuKNl+hE8Isr18sKsKvGGpSxQk+G0gO0reDlx2PhUNus7TJTkA1C59vU/JoN8hIvZ4g==", "requires": { "tslib": "^1.9.0" } }, "@schematics/angular": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/@schematics/angular/-/angular-0.6.0.tgz", - "integrity": "sha512-mgDCNHF/41934HGMU4PCY3nk19kTBvUBZ5PLQEkZ6Q+wLDs2WigjuJqcYrUluC1T0Z3SvVDKrwSbC2RRMC/oFA==", + "version": "0.6.8", + "resolved": "https://registry.npmjs.org/@schematics/angular/-/angular-0.6.8.tgz", + "integrity": "sha512-9kRphqTYG5Df/I8fvnT1zMsw0YNDPO9tl18tQZXj4am4raT7l9UCr+WkwJdlBoA5pwG6baWE9sL0iGWV/bzF/g==", "dev": true, "requires": { - "@angular-devkit/core": "0.6.0", - "@angular-devkit/schematics": "0.6.0", + "@angular-devkit/core": "0.6.8", + "@angular-devkit/schematics": "0.6.8", "typescript": ">=2.6.2 <2.8" } }, "@schematics/update": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/@schematics/update/-/update-0.6.0.tgz", - "integrity": "sha512-/6p81bKbbH19EAFDhwHZCKMDEHwLkSdvCTVESAsrDQzjReGiLJ/NhStkpHp56kIYqsY/WXZlujn8MLQdSEMolA==", + "version": "0.6.8", + "resolved": "https://registry.npmjs.org/@schematics/update/-/update-0.6.8.tgz", + "integrity": "sha512-1Uq7LYnwL2wBwGVCgNz76QAR13ghAk+2vDDHOi+VX5+usHManxydrpoMGeX66OBPd+y5D3D2MFb+8mYHE7mygg==", "dev": true, "requires": { - "@angular-devkit/core": "0.6.0", - "@angular-devkit/schematics": "0.6.0", + "@angular-devkit/core": "0.6.8", + "@angular-devkit/schematics": "0.6.8", "npm-registry-client": "^8.5.1", "rxjs": "^6.0.0", "semver": "^5.3.0", @@ -484,9 +483,9 @@ } }, "@swimlane/ngx-charts": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/@swimlane/ngx-charts/-/ngx-charts-8.0.0.tgz", - "integrity": "sha512-6MfHXlnE2mHZsSGhSchY6vV4gshgZ2y3RImys2GWporao7ZRh8+kDFo9osdYMyOwleCGRA1LQOW8XNXzDTey7g==", + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/@swimlane/ngx-charts/-/ngx-charts-8.1.0.tgz", + "integrity": "sha512-jjcIwt5uQXoBaQwCgHPqpzSoNJj68PiKItMYg6RVyqLua67vZ90ZdxzuYPsYpRtDIXJiV5/gXuDtD3ZrjtdQCA==", "requires": { "d3-array": "^1.2.1", "d3-brush": "^1.0.4", @@ -502,9 +501,9 @@ } }, "@swimlane/ngx-datatable": { - "version": "12.0.0", - "resolved": "https://registry.npmjs.org/@swimlane/ngx-datatable/-/ngx-datatable-12.0.0.tgz", - "integrity": "sha512-JT7fxtzvUP5gVYlP1VHxgtGVrn/0UlW8TzzFjAc9w25Yc9RppJ1Xsdzg8eyBb8H/e+Qa+Y0p2y6LvMUNFNJjsw==" + "version": "13.0.1", + "resolved": "https://registry.npmjs.org/@swimlane/ngx-datatable/-/ngx-datatable-13.0.1.tgz", + "integrity": "sha512-jjMEzQhXcdD+jfKNp+7U61lWx9ZzSGDn9QbpY6pJOJwz+E2CKeek6OouT5Qcc4MY4oFL9g/SZoPjLf90cbNIRw==" }, "@swimlane/ngx-dnd": { "version": "4.0.0", @@ -523,9 +522,9 @@ "integrity": "sha512-cb5BNoOXPZ4Bohe+TC7/bbNxbFOL9T+32xjlU2h7gJfCg+9qV/5uX1mVm7dfyFutVdxAQDjZemGz2m9Dav8rMA==" }, "@types/jasmine": { - "version": "2.8.7", - "resolved": "https://registry.npmjs.org/@types/jasmine/-/jasmine-2.8.7.tgz", - "integrity": "sha512-RdbrPcW1aD78UmdLiDa9ZCKrbR5Go8PXh6GCpb4oIOkWVEusubSJJDrP4c5RYOu8m/CBz+ygZpicj6Pgms5a4Q==", + "version": "2.8.8", + "resolved": "https://registry.npmjs.org/@types/jasmine/-/jasmine-2.8.8.tgz", + "integrity": "sha512-OJSUxLaxXsjjhob2DBzqzgrkLmukM3+JMpRp0r0E4HTdT1nwDCWhaswjYxazPij6uOdzHCJfNbDjmQ1/rnNbCg==", "dev": true }, "@types/jasminewd2": { @@ -538,9 +537,9 @@ } }, "@types/lodash": { - "version": "4.14.108", - "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.108.tgz", - "integrity": "sha512-WD2vUOKfBBVHxWUV9iMR9RMfpuf8HquxWeAq2yqGVL7Nc4JW2+sQama0pREMqzNI3Tutj0PyxYUJwuoxxvX+xA==", + "version": "4.14.109", + "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.109.tgz", + "integrity": "sha512-hop8SdPUEzbcJm6aTsmuwjIYQo1tqLseKCM+s2bBqTU2gErwI4fE+aqUVOlscPSQbKHKgtMMPoC+h4AIGOJYvw==", "dev": true }, "@types/node": { @@ -566,6 +565,219 @@ "integrity": "sha512-UBYHWph6P3tutkbXpW6XYg9ZPbTKjw/YC2hGG1/GEvWwTbvezBUv3h+mmUFw79T3RFPnmedpiXdOBbXX+4l0jg==", "dev": true }, + "@webassemblyjs/ast": { + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.4.3.tgz", + "integrity": "sha512-S6npYhPcTHDYe9nlsKa9CyWByFi8Vj8HovcAgtmMAQZUOczOZbQ8CnwMYKYC5HEZzxEE+oY0jfQk4cVlI3J59Q==", + "dev": true, + "requires": { + "@webassemblyjs/helper-wasm-bytecode": "1.4.3", + "@webassemblyjs/wast-parser": "1.4.3", + "debug": "^3.1.0", + "webassemblyjs": "1.4.3" + }, + "dependencies": { + "debug": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", + "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + } + } + }, + "@webassemblyjs/floating-point-hex-parser": { + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.4.3.tgz", + "integrity": "sha512-3zTkSFswwZOPNHnzkP9ONq4bjJSeKVMcuahGXubrlLmZP8fmTIJ58dW7h/zOVWiFSuG2em3/HH3BlCN7wyu9Rw==", + "dev": true + }, + "@webassemblyjs/helper-buffer": { + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-buffer/-/helper-buffer-1.4.3.tgz", + "integrity": "sha512-e8+KZHh+RV8MUvoSRtuT1sFXskFnWG9vbDy47Oa166xX+l0dD5sERJ21g5/tcH8Yo95e9IN3u7Jc3NbhnUcSkw==", + "dev": true, + "requires": { + "debug": "^3.1.0" + }, + "dependencies": { + "debug": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", + "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + } + } + }, + "@webassemblyjs/helper-code-frame": { + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-code-frame/-/helper-code-frame-1.4.3.tgz", + "integrity": "sha512-9FgHEtNsZQYaKrGCtsjswBil48Qp1agrzRcPzCbQloCoaTbOXLJ9IRmqT+uEZbenpULLRNFugz3I4uw18hJM8w==", + "dev": true, + "requires": { + "@webassemblyjs/wast-printer": "1.4.3" + } + }, + "@webassemblyjs/helper-fsm": { + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-fsm/-/helper-fsm-1.4.3.tgz", + "integrity": "sha512-JINY76U+702IRf7ePukOt037RwmtH59JHvcdWbTTyHi18ixmQ+uOuNhcdCcQHTquDAH35/QgFlp3Y9KqtyJsCQ==", + "dev": true + }, + "@webassemblyjs/helper-wasm-bytecode": { + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.4.3.tgz", + "integrity": "sha512-I7bS+HaO0K07Io89qhJv+z1QipTpuramGwUSDkwEaficbSvCcL92CUZEtgykfNtk5wb0CoLQwWlmXTwGbNZUeQ==", + "dev": true + }, + "@webassemblyjs/helper-wasm-section": { + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.4.3.tgz", + "integrity": "sha512-p0yeeO/h2r30PyjnJX9xXSR6EDcvJd/jC6xa/Pxg4lpfcNi7JUswOpqDToZQ55HMMVhXDih/yqkaywHWGLxqyQ==", + "dev": true, + "requires": { + "@webassemblyjs/ast": "1.4.3", + "@webassemblyjs/helper-buffer": "1.4.3", + "@webassemblyjs/helper-wasm-bytecode": "1.4.3", + "@webassemblyjs/wasm-gen": "1.4.3", + "debug": "^3.1.0" + }, + "dependencies": { + "debug": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", + "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + } + } + }, + "@webassemblyjs/leb128": { + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/@webassemblyjs/leb128/-/leb128-1.4.3.tgz", + "integrity": "sha512-4u0LJLSPzuRDWHwdqsrThYn+WqMFVqbI2ltNrHvZZkzFPO8XOZ0HFQ5eVc4jY/TNHgXcnwrHjONhPGYuuf//KQ==", + "dev": true, + "requires": { + "leb": "^0.3.0" + } + }, + "@webassemblyjs/validation": { + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/@webassemblyjs/validation/-/validation-1.4.3.tgz", + "integrity": "sha512-R+rRMKfhd9mq0rj2mhU9A9NKI2l/Rw65vIYzz4lui7eTKPcCu1l7iZNi4b9Gen8D42Sqh/KGiaQNk/x5Tn/iBQ==", + "dev": true, + "requires": { + "@webassemblyjs/ast": "1.4.3" + } + }, + "@webassemblyjs/wasm-edit": { + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-edit/-/wasm-edit-1.4.3.tgz", + "integrity": "sha512-qzuwUn771PV6/LilqkXcS0ozJYAeY/OKbXIWU3a8gexuqb6De2p4ya/baBeH5JQ2WJdfhWhSvSbu86Vienttpw==", + "dev": true, + "requires": { + "@webassemblyjs/ast": "1.4.3", + "@webassemblyjs/helper-buffer": "1.4.3", + "@webassemblyjs/helper-wasm-bytecode": "1.4.3", + "@webassemblyjs/helper-wasm-section": "1.4.3", + "@webassemblyjs/wasm-gen": "1.4.3", + "@webassemblyjs/wasm-opt": "1.4.3", + "@webassemblyjs/wasm-parser": "1.4.3", + "@webassemblyjs/wast-printer": "1.4.3", + "debug": "^3.1.0" + }, + "dependencies": { + "debug": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", + "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + } + } + }, + "@webassemblyjs/wasm-gen": { + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-gen/-/wasm-gen-1.4.3.tgz", + "integrity": "sha512-eR394T8dHZfpLJ7U/Z5pFSvxl1L63JdREebpv9gYc55zLhzzdJPAuxjBYT4XqevUdW67qU2s0nNA3kBuNJHbaQ==", + "dev": true, + "requires": { + "@webassemblyjs/ast": "1.4.3", + "@webassemblyjs/helper-wasm-bytecode": "1.4.3", + "@webassemblyjs/leb128": "1.4.3" + } + }, + "@webassemblyjs/wasm-opt": { + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-opt/-/wasm-opt-1.4.3.tgz", + "integrity": "sha512-7Gp+nschuKiDuAL1xmp4Xz0rgEbxioFXw4nCFYEmy+ytynhBnTeGc9W9cB1XRu1w8pqRU2lbj2VBBA4cL5Z2Kw==", + "dev": true, + "requires": { + "@webassemblyjs/ast": "1.4.3", + "@webassemblyjs/helper-buffer": "1.4.3", + "@webassemblyjs/wasm-gen": "1.4.3", + "@webassemblyjs/wasm-parser": "1.4.3", + "debug": "^3.1.0" + }, + "dependencies": { + "debug": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", + "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + } + } + }, + "@webassemblyjs/wasm-parser": { + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-parser/-/wasm-parser-1.4.3.tgz", + "integrity": "sha512-KXBjtlwA3BVukR/yWHC9GF+SCzBcgj0a7lm92kTOaa4cbjaTaa47bCjXw6cX4SGQpkncB9PU2hHGYVyyI7wFRg==", + "dev": true, + "requires": { + "@webassemblyjs/ast": "1.4.3", + "@webassemblyjs/helper-wasm-bytecode": "1.4.3", + "@webassemblyjs/leb128": "1.4.3", + "@webassemblyjs/wasm-parser": "1.4.3", + "webassemblyjs": "1.4.3" + } + }, + "@webassemblyjs/wast-parser": { + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-parser/-/wast-parser-1.4.3.tgz", + "integrity": "sha512-QhCsQzqV0CpsEkRYyTzQDilCNUZ+5j92f+g35bHHNqS22FppNTywNFfHPq8ZWZfYCgbectc+PoghD+xfzVFh1Q==", + "dev": true, + "requires": { + "@webassemblyjs/ast": "1.4.3", + "@webassemblyjs/floating-point-hex-parser": "1.4.3", + "@webassemblyjs/helper-code-frame": "1.4.3", + "@webassemblyjs/helper-fsm": "1.4.3", + "long": "^3.2.0", + "webassemblyjs": "1.4.3" + } + }, + "@webassemblyjs/wast-printer": { + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-printer/-/wast-printer-1.4.3.tgz", + "integrity": "sha512-EgXk4anf8jKmuZJsqD8qy5bz2frEQhBvZruv+bqwNoLWUItjNSFygk8ywL3JTEz9KtxTlAmqTXNrdD1d9gNDtg==", + "dev": true, + "requires": { + "@webassemblyjs/ast": "1.4.3", + "@webassemblyjs/wast-parser": "1.4.3", + "long": "^3.2.0" + } + }, "abbrev": { "version": "1.0.9", "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.0.9.tgz", @@ -610,21 +822,12 @@ "dev": true }, "agent-base": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-2.1.1.tgz", - "integrity": "sha1-1t4Q1a9hMtW9aSQn1G/FOFOQlMc=", + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-4.2.0.tgz", + "integrity": "sha512-c+R/U5X+2zz2+UCrCFv6odQzJdoqI+YecuhnAJLa1zYaMc13zPfwMwZrr91Pd1DYNo/yPRbiM4WVf9whgwFsIg==", "dev": true, "requires": { - "extend": "~3.0.0", - "semver": "~5.0.1" - }, - "dependencies": { - "semver": { - "version": "5.0.3", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.0.3.tgz", - "integrity": "sha1-d0Zt5YnNXTyV8TiqeLxWmjy10no=", - "dev": true - } + "es6-promisify": "^5.0.0" } }, "ajv": { @@ -674,22 +877,25 @@ "dev": true }, "angular-calendar": { - "version": "0.24.0", - "resolved": "https://registry.npmjs.org/angular-calendar/-/angular-calendar-0.24.0.tgz", - "integrity": "sha512-gSOoUSnXBh8d1WMbVwR0klqZADXFLerNSzuAAqYyIeB2kxmw4Ghzmfk3yVreqduglBa0/qUOqmuG7gWUCeX2NQ==", + "version": "0.25.2", + "resolved": "https://registry.npmjs.org/angular-calendar/-/angular-calendar-0.25.2.tgz", + "integrity": "sha512-sFzqwioLIEbRIpFcZq6Ap0tW8n8NNApwbbbs0DTmjnQjr6N1VZArlkKCecfqkYYG6dE496t7V616Ak7gTBa4QA==", "requires": { - "angular-draggable-droppable": "^2.0.0", - "angular-resizable-element": "^2.0.0", + "angular-draggable-droppable": "^3.0.0", + "angular-resizable-element": "^3.0.0", "calendar-utils": "^0.1.2", "date-fns": "^1.28.5", "positioning": "^1.3.1", - "tslib": "^1.7.1" + "tslib": "^1.9.0" } }, "angular-draggable-droppable": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/angular-draggable-droppable/-/angular-draggable-droppable-2.0.0.tgz", - "integrity": "sha512-/b8LIGamjOKnDI2uG1jRUErTIHeQ3w2WqHn4cbeiUTy+6eNHjkQI32DNhvxl0nVxr2gF5QluECNB4uWjMMyzQg==" + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/angular-draggable-droppable/-/angular-draggable-droppable-3.0.0.tgz", + "integrity": "sha512-plPrP1voXfV0w13LSvKadMIl4UMsP+eVAqZM73VowB/c6YZyIRb50+MXML2UOX2Or1dFGBIJA4pWpcT623Xktw==", + "requires": { + "tslib": "^1.9.0" + } }, "angular-in-memory-web-api": { "version": "0.6.0", @@ -697,9 +903,12 @@ "integrity": "sha512-+i2bH9T/S4gTQdJLt264H4JMKXNpik33pMatSOvPSqFQ0vImnTBVbvijfmy75OgwKPJ8OZw0R76CrLjp2EYX2A==" }, "angular-resizable-element": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/angular-resizable-element/-/angular-resizable-element-2.0.0.tgz", - "integrity": "sha512-Jsa818fxtAtBA3Fp1u4mWV9tcpakM+bNYFFbB/AjKig2BtzZkeyLx3vjcBCfwPmXkK10kX2QKR8RDALk1w209A==" + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/angular-resizable-element/-/angular-resizable-element-3.0.0.tgz", + "integrity": "sha512-5fpklah0P48S0W89k839WwB7sj7Slik39+EcfKlAgrXgXuwEwPjeXX6mduDYtFDFNkVb081SjEfPbNW/nborJA==", + "requires": { + "tslib": "^1.9.0" + } }, "ansi-html": { "version": "0.0.7", @@ -750,12 +959,12 @@ "dev": true }, "append-transform": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/append-transform/-/append-transform-0.4.0.tgz", - "integrity": "sha1-126/jKlNJ24keja61EpLdKthGZE=", + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/append-transform/-/append-transform-1.0.0.tgz", + "integrity": "sha512-P009oYkeHyU742iSZJzZZywj4QRJdnTWffaKuJQLablCZ1uz6/cW4yaRgcDaoQ+uwOxxnt0gRUcwfsNP2ri0gw==", "dev": true, "requires": { - "default-require-extensions": "^1.0.0" + "default-require-extensions": "^2.0.0" } }, "aproba": { @@ -765,9 +974,9 @@ "dev": true }, "are-we-there-yet": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-1.1.4.tgz", - "integrity": "sha1-u13KOCu5TwXhUZQ3PRb9O6HKEQ0=", + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-1.1.5.tgz", + "integrity": "sha512-5hYdAkZlcG8tOLujVDTgCT+uPX0VnpAH28gWsLfzpXYm7wP6mp5Q/gYyR7YQ0cKVJcXJnl3j2kpBan13PtQf6w==", "dev": true, "requires": { "delegates": "^1.0.0", @@ -893,6 +1102,23 @@ "dev": true, "requires": { "util": "0.10.3" + }, + "dependencies": { + "inherits": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.1.tgz", + "integrity": "sha1-sX0I0ya0Qj5Wjv9xn5GwscvfafE=", + "dev": true + }, + "util": { + "version": "0.10.3", + "resolved": "https://registry.npmjs.org/util/-/util-0.10.3.tgz", + "integrity": "sha1-evsa/lCAUkZInj23/g7TeTNqwPk=", + "dev": true, + "requires": { + "inherits": "2.0.1" + } + } } }, "assert-plus": { @@ -923,7 +1149,8 @@ "version": "0.1.3", "resolved": "https://registry.npmjs.org/async-foreach/-/async-foreach-0.1.3.tgz", "integrity": "sha1-NhIfhFwFeBct5Bmpfb6x0W7DRUI=", - "dev": true + "dev": true, + "optional": true }, "async-limiter": { "version": "1.0.0", @@ -949,13 +1176,13 @@ "dev": true }, "autoprefixer": { - "version": "8.4.1", - "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-8.4.1.tgz", - "integrity": "sha512-YqUclCBDXUT9Y7aQ8Xv+ja8yhTZYJoMsOD7WS++gZIJLCpCu+gPcKGDlhk6S3WxhLkTcNVdaMZAWys2nzZCH7g==", + "version": "8.6.2", + "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-8.6.2.tgz", + "integrity": "sha512-cv9v1mYYBcAnZq4MHseJ9AIdjQmNahnpCpPO46oTkQJS2GggsBp2azHjNpAuQ95Epvsg+AIsyjYhfI9YwFxGSA==", "dev": true, "requires": { - "browserslist": "^3.2.6", - "caniuse-lite": "^1.0.30000832", + "browserslist": "^3.2.8", + "caniuse-lite": "^1.0.30000851", "normalize-range": "^0.1.2", "num2fraction": "^1.2.2", "postcss": "^6.0.22", @@ -1239,6 +1466,7 @@ "resolved": "https://registry.npmjs.org/block-stream/-/block-stream-0.0.9.tgz", "integrity": "sha1-E+v+d4oDIFz+A3UUgeu0szAMEmo=", "dev": true, + "optional": true, "requires": { "inherits": "~2.0.0" } @@ -1449,13 +1677,13 @@ } }, "browserslist": { - "version": "3.2.6", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-3.2.6.tgz", - "integrity": "sha512-XCsMSg9V4S1VRdcp265dJ+8kBRjfuFXcavbisY7G6T9QI0H1Z24PP53vvs0WDYWqm38Mco1ILDtafcS8ZR4xiw==", + "version": "3.2.8", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-3.2.8.tgz", + "integrity": "sha512-WHVocJYavUwVgVViC0ORikPHQquXwVh939TaelZ4WDqpWgTX/FsGhl/+P4qBUAGcRvtOgDgC+xftNWWp2RUTAQ==", "dev": true, "requires": { - "caniuse-lite": "^1.0.30000830", - "electron-to-chromium": "^1.3.42" + "caniuse-lite": "^1.0.30000844", + "electron-to-chromium": "^1.3.47" } }, "buffer": { @@ -1608,9 +1836,9 @@ } }, "caniuse-lite": { - "version": "1.0.30000836", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30000836.tgz", - "integrity": "sha512-DlVR8sVTKDgd7t95U0shX3g7MeJ/DOjKOhUcaiXqnVmnO5sG4Tn2rLVOkVfPUJgnQNxnGe8/4GK0dGSI+AagQw==", + "version": "1.0.30000851", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30000851.tgz", + "integrity": "sha512-Y1ecA1cL9wg0vni8t33nBw/poX8ypm+2c3fbwAESj8cm4ufK9CBFQ1+nUK8Dp5dtFo5Fc3JzkI5DKmQbuIo6hQ==", "dev": true }, "caseless": { @@ -1907,9 +2135,9 @@ "dev": true }, "compare-versions": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/compare-versions/-/compare-versions-3.1.0.tgz", - "integrity": "sha512-4hAxDSBypT/yp2ySFD346So6Ragw5xmBn/e/agIGl3bZr6DLUqnoRZPusxKrXdYRZpgexO9daejmIenlq/wrIQ==", + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/compare-versions/-/compare-versions-3.3.0.tgz", + "integrity": "sha512-MAAAIOdi2s4Gl6rZ76PNcUa9IOYB+5ICdT41o5uMRf09aEu/F9RK+qhe8RjXNPwcTjGV7KU7h2P/fljThFVqyQ==", "dev": true }, "component-bind": { @@ -1931,12 +2159,20 @@ "dev": true }, "compressible": { - "version": "2.0.13", - "resolved": "https://registry.npmjs.org/compressible/-/compressible-2.0.13.tgz", - "integrity": "sha1-DRAgq5JLL9tNYnmHXH1tq6a6p6k=", + "version": "2.0.14", + "resolved": "https://registry.npmjs.org/compressible/-/compressible-2.0.14.tgz", + "integrity": "sha1-MmxfUH+7BV9UEWeCuWmoG2einac=", "dev": true, "requires": { - "mime-db": ">= 1.33.0 < 2" + "mime-db": ">= 1.34.0 < 2" + }, + "dependencies": { + "mime-db": { + "version": "1.34.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.34.0.tgz", + "integrity": "sha1-RS0Oz/XDA0am3B5kseruDTcZ/5o=", + "dev": true + } } }, "compression": { @@ -2118,9 +2354,9 @@ } }, "core-js": { - "version": "2.5.6", - "resolved": "https://registry.npmjs.org/core-js/-/core-js-2.5.6.tgz", - "integrity": "sha512-lQUVfQi0aLix2xpyjrrJEvfuYCqPc/HwmTKsC/VNf8q0zsjX7SQZtp4+oRONN5Tsur9GDETPjj+Ub2iDiGZfSQ==" + "version": "2.5.7", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-2.5.7.tgz", + "integrity": "sha512-RszJCAxg/PP6uzXVXL6BsxSXx/B05oJAQ2vkJRjyjrEcNVycaqOmNb5OTxZPE3xa5gwZduqza6L9JOCenh/Ecw==" }, "core-util-is": { "version": "1.0.2", @@ -2193,6 +2429,7 @@ "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-3.0.1.tgz", "integrity": "sha1-ElYDfsufDF9549bvE14wdwGEuYI=", "dev": true, + "optional": true, "requires": { "lru-cache": "^4.0.1", "which": "^1.2.9" @@ -2331,9 +2568,9 @@ } }, "d3": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/d3/-/d3-5.2.0.tgz", - "integrity": "sha1-8cbHojlhX1QN1o2T30/LF6UM/9o=", + "version": "5.4.0", + "resolved": "https://registry.npmjs.org/d3/-/d3-5.4.0.tgz", + "integrity": "sha1-CQGZqFadHeI9BKP/B/4TYJX+p04=", "requires": { "d3-array": "1", "d3-axis": "1", @@ -2541,9 +2778,9 @@ } }, "d3-scale-chromatic": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/d3-scale-chromatic/-/d3-scale-chromatic-1.2.0.tgz", - "integrity": "sha512-qQUhLi8fPe/F0b0M46C6eFUbms5IIMHuhJ5DKjjzBUvm1b6aPtygJzGbrMdMUD/ckLBq+NdWwHeN2cpMDp4Q5Q==", + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/d3-scale-chromatic/-/d3-scale-chromatic-1.3.0.tgz", + "integrity": "sha512-YwMbiaW2bStWvQFByK8hA6hk7ToWflspIo2TRukCqERd8isiafEMBXmwfh8c7/0Z94mVvIzIveRLVC6RAjhgeA==", "requires": { "d3-color": "1", "d3-interpolate": "1" @@ -2669,12 +2906,20 @@ "dev": true }, "default-require-extensions": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/default-require-extensions/-/default-require-extensions-1.0.0.tgz", - "integrity": "sha1-836hXT4T/9m0N9M+GnW1+5eHTLg=", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/default-require-extensions/-/default-require-extensions-2.0.0.tgz", + "integrity": "sha1-9fj7sYp9bVCyH2QfZJ67Uiz+JPc=", "dev": true, "requires": { - "strip-bom": "^2.0.0" + "strip-bom": "^3.0.0" + }, + "dependencies": { + "strip-bom": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", + "integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=", + "dev": true + } } }, "define-properties": { @@ -3005,9 +3250,9 @@ "dev": true }, "electron-to-chromium": { - "version": "1.3.45", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.45.tgz", - "integrity": "sha1-RYrBscXHYM6IEaFtK/vZfsMLr7g=", + "version": "1.3.48", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.48.tgz", + "integrity": "sha1-07DYWTgUBE4JLs4hCPw6ya6kuQA=", "dev": true }, "elliptic": { @@ -3180,9 +3425,9 @@ } }, "es-abstract": { - "version": "1.11.0", - "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.11.0.tgz", - "integrity": "sha512-ZnQrE/lXTTQ39ulXZ+J1DTFazV9qBy61x2bY071B+qGco8Z8q1QddsLdt/EF8Ai9hcWH72dWS0kFqXLxOxqslA==", + "version": "1.12.0", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.12.0.tgz", + "integrity": "sha512-C8Fx/0jFmV5IPoMOFPA9P9G5NtqW+4cOPit3MIuvR2t7Ag2K15EJTpxnHAYTzL+aYQJIESYeXZmDBfOBE1HcpA==", "dev": true, "requires": { "es-to-primitive": "^1.1.1", @@ -3204,9 +3449,9 @@ } }, "es5-ext": { - "version": "0.10.42", - "resolved": "https://registry.npmjs.org/es5-ext/-/es5-ext-0.10.42.tgz", - "integrity": "sha512-AJxO1rmPe1bDEfSR6TJ/FgMFYuTBhR5R57KW58iCkYACMyFbrkqVyzXSurYoScDGvgyMpk7uRF/lPUPPTmsRSA==", + "version": "0.10.45", + "resolved": "https://registry.npmjs.org/es5-ext/-/es5-ext-0.10.45.tgz", + "integrity": "sha512-FkfM6Vxxfmztilbxxz5UKSD4ICMf5tSpRFtDNtkAhOxZ0EKtX6qwmXNyH/sFyIbX2P/nU5AMiA9jilWsUGJzCQ==", "dev": true, "requires": { "es6-iterator": "~2.0.3", @@ -3226,11 +3471,20 @@ } }, "es6-promise": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-3.0.2.tgz", - "integrity": "sha1-AQ1YWEI6XxGJeWZfRkhqlcbuK7Y=", + "version": "4.2.4", + "resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-4.2.4.tgz", + "integrity": "sha512-/NdNZVJg+uZgtm9eS3O6lrOLYmQag2DjdEXuPaHlZ6RuVqgqaVZfgYCepEIKsLqwdQArOPtC3XzRLqGGfT8KQQ==", "dev": true }, + "es6-promisify": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/es6-promisify/-/es6-promisify-5.0.0.tgz", + "integrity": "sha1-UQnWLz5W6pZ8S2NQWu8IKRyKUgM=", + "dev": true, + "requires": { + "es6-promise": "^4.0.3" + } + }, "es6-symbol": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/es6-symbol/-/es6-symbol-3.1.1.tgz", @@ -4507,10 +4761,11 @@ } }, "gaze": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/gaze/-/gaze-1.1.2.tgz", - "integrity": "sha1-hHIkZ3rbiHDWeSV+0ziP22HkAQU=", + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/gaze/-/gaze-1.1.3.tgz", + "integrity": "sha512-BRdNm8hbWzFzWHERTrejLqwHDfS4GibPoq5wjTPIoJHoBtKGPg3xAFfxmM+9ztbXelxcf2hwQcaz1PtmFeue8g==", "dev": true, + "optional": true, "requires": { "globule": "^1.0.0" } @@ -4519,13 +4774,15 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/generate-function/-/generate-function-2.0.0.tgz", "integrity": "sha1-aFj+fAlpt9TpCTM3ZHrHn2DfvnQ=", - "dev": true + "dev": true, + "optional": true }, "generate-object-property": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/generate-object-property/-/generate-object-property-1.2.0.tgz", "integrity": "sha1-nA4cQDCM6AT0eDYYuTf6iPmdUNA=", "dev": true, + "optional": true, "requires": { "is-property": "^1.0.0" } @@ -4655,13 +4912,14 @@ } }, "globule": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/globule/-/globule-1.2.0.tgz", - "integrity": "sha1-HcScaCLdnoovoAuiopUAboZkvQk=", + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/globule/-/globule-1.2.1.tgz", + "integrity": "sha512-g7QtgWF4uYSL5/dn71WxubOrS7JVGCnFPEnoeChJmBnyR9Mw8nGoEwOgJL/RC2Te0WhbsEUCejfH8SZNJ+adYQ==", "dev": true, + "optional": true, "requires": { "glob": "~7.1.1", - "lodash": "~4.17.4", + "lodash": "~4.17.10", "minimatch": "~3.0.2" } }, @@ -4776,12 +5034,12 @@ } }, "has": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/has/-/has-1.0.1.tgz", - "integrity": "sha1-hGFzP1OLCDfJNh45qauelwTcLyg=", + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", + "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", "dev": true, "requires": { - "function-bind": "^1.0.2" + "function-bind": "^1.1.1" } }, "has-ansi": { @@ -4946,9 +5204,9 @@ "dev": true }, "html-minifier": { - "version": "3.5.15", - "resolved": "https://registry.npmjs.org/html-minifier/-/html-minifier-3.5.15.tgz", - "integrity": "sha512-OZa4rfb6tZOZ3Z8Xf0jKxXkiDcFWldQePGYFDcgKqES2sXeWaEv9y6QQvWUtX3ySI3feApQi5uCsHLINQ6NoAw==", + "version": "3.5.16", + "resolved": "https://registry.npmjs.org/html-minifier/-/html-minifier-3.5.16.tgz", + "integrity": "sha512-zP5EfLSpiLRp0aAgud4CQXPQZm9kXwWjR/cF0PfdOj+jjWnOaCgeZcll4kYXSvIBPeUMmyaSc7mM4IDtA+kboA==", "dev": true, "requires": { "camel-case": "3.0.x", @@ -5055,9 +5313,9 @@ } }, "http-parser-js": { - "version": "0.4.12", - "resolved": "https://registry.npmjs.org/http-parser-js/-/http-parser-js-0.4.12.tgz", - "integrity": "sha1-uc+/Sizybw/DSxDKFImid3HjR08=", + "version": "0.4.13", + "resolved": "https://registry.npmjs.org/http-parser-js/-/http-parser-js-0.4.13.tgz", + "integrity": "sha1-O9bW/ebjFyyTNMOzO2wZPYD+ETc=", "dev": true }, "http-proxy": { @@ -5101,14 +5359,24 @@ "dev": true }, "https-proxy-agent": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-1.0.0.tgz", - "integrity": "sha1-NffabEjOTdv6JkiRrFk+5f+GceY=", + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-2.2.1.tgz", + "integrity": "sha512-HPCTS1LW51bcyMYbxUIOO4HEOlQ1/1qRaFWcyxvwaqUS9TY88aoEuHUY33kuAh1YhVVaDQhLZsnPd+XNARWZlQ==", "dev": true, "requires": { - "agent-base": "2", - "debug": "2", - "extend": "3" + "agent-base": "^4.1.0", + "debug": "^3.1.0" + }, + "dependencies": { + "debug": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", + "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + } } }, "iconv-lite": { @@ -5120,9 +5388,9 @@ } }, "ieee754": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.1.11.tgz", - "integrity": "sha512-VhDzCKN7K8ufStx/CLj5/PDTMgph+qwN5Pkd5i0sGnVwk56zJ0lkT8Qzi1xqWLS0Wp29DgDtNeS7v8/wMoZeHg==", + "version": "1.1.12", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.1.12.tgz", + "integrity": "sha512-GguP+DRY+pJ3soyIiGPTvdiVXjZ+DbXOxGpXn3eMvNW4x4irjqXm4wHKscC+TfxSJ0yw/S1F24tqdMNsMZTiLA==", "dev": true }, "iferr": { @@ -5170,7 +5438,8 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/in-publish/-/in-publish-2.0.0.tgz", "integrity": "sha1-4g/146KvwmkDILbcVSaCqcf631E=", - "dev": true + "dev": true, + "optional": true }, "indent-string": { "version": "2.1.0", @@ -5415,13 +5684,15 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-my-ip-valid/-/is-my-ip-valid-1.0.0.tgz", "integrity": "sha512-gmh/eWXROncUzRnIa1Ubrt5b8ep/MGSnfAUI3aRp+sqTCs1tv1Isl8d8F6JmkN3dXKc3ehZMrtiPN9eL03NuaQ==", - "dev": true + "dev": true, + "optional": true }, "is-my-json-valid": { "version": "2.17.2", "resolved": "https://registry.npmjs.org/is-my-json-valid/-/is-my-json-valid-2.17.2.tgz", "integrity": "sha512-IBhBslgngMQN8DDSppmgDv7RNrlFotuuDsKcrCP3+HbFaVivIBU7u9oiiErw8sH4ynx3+gOGQ3q2otkgiSi6kg==", "dev": true, + "optional": true, "requires": { "generate-function": "^2.0.0", "generate-object-property": "^1.1.0", @@ -5516,7 +5787,8 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/is-property/-/is-property-1.0.2.tgz", "integrity": "sha1-V/4cTkhHTt1lsJkR8msc1Ald2oQ=", - "dev": true + "dev": true, + "optional": true }, "is-regex": { "version": "1.0.4", @@ -5672,12 +5944,12 @@ }, "dependencies": { "async": { - "version": "2.6.0", - "resolved": "https://registry.npmjs.org/async/-/async-2.6.0.tgz", - "integrity": "sha512-xAfGg1/NTLBBKlHFmnd7PlmUW9KhVQIUuSrYem9xzFUZy13ScvtyGGejaae9iAVRiRq9+Cx7DPFaAAhCpyxyPw==", + "version": "2.6.1", + "resolved": "https://registry.npmjs.org/async/-/async-2.6.1.tgz", + "integrity": "sha512-fNEiL2+AZt6AlAw/29Cr0UDe4sRAHCpEHh54WMz+Bb7QfNcFw4h3loofyJpLeQs4Yx7yuqu/2dLgM5hKOs6HlQ==", "dev": true, "requires": { - "lodash": "^4.14.0" + "lodash": "^4.17.10" } } } @@ -5724,12 +5996,12 @@ "dev": true }, "istanbul-lib-hook": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/istanbul-lib-hook/-/istanbul-lib-hook-1.2.0.tgz", - "integrity": "sha512-p3En6/oGkFQV55Up8ZPC2oLxvgSxD8CzA0yBrhRZSh3pfv3OFj9aSGVC0yoerAi/O4u7jUVnOGVX1eVFM+0tmQ==", + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/istanbul-lib-hook/-/istanbul-lib-hook-1.2.1.tgz", + "integrity": "sha512-eLAMkPG9FU0v5L02lIkcj/2/Zlz9OuluaXikdr5iStk8FDbSwAixTK9TkYxbF0eNnzAJTwM2fkV2A1tpsIp4Jg==", "dev": true, "requires": { - "append-transform": "^0.4.0" + "append-transform": "^1.0.0" } }, "istanbul-lib-instrument": { @@ -5777,9 +6049,9 @@ } }, "istanbul-lib-source-maps": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-1.2.4.tgz", - "integrity": "sha512-UzuK0g1wyQijiaYQxj/CdNycFhAd2TLtO2obKQMTZrZ1jzEMRY3rvpASEKkaxbRR6brvdovfA03znPa/pXcejg==", + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-1.2.5.tgz", + "integrity": "sha512-8O2T/3VhrQHn0XcJbP1/GN7kXMiRAlPi+fj3uEHrjBD8Oz7Py0prSC25C09NuAZS6bgW1NNKAvCSHZXB0irSGA==", "dev": true, "requires": { "debug": "^3.1.0", @@ -5850,10 +6122,11 @@ "dev": true }, "js-base64": { - "version": "2.4.3", - "resolved": "https://registry.npmjs.org/js-base64/-/js-base64-2.4.3.tgz", - "integrity": "sha512-H7ErYLM34CvDMto3GbD6xD0JLUGYXR3QTcH6B/tr4Hi/QpSThnCsIp+Sy5FRTw3B0d6py4HcNkW7nO/wdtGWEw==", - "dev": true + "version": "2.4.5", + "resolved": "https://registry.npmjs.org/js-base64/-/js-base64-2.4.5.tgz", + "integrity": "sha512-aUnNwqMOXw3yvErjMPSQu6qIIzUmT1e5KcU1OZxRDU1g/am6mzBvcrmLAYwzmB59BHPrh5/tKaiF4OPhqRWESQ==", + "dev": true, + "optional": true }, "js-tokens": { "version": "3.0.2", @@ -5904,6 +6177,16 @@ "integrity": "sha1-NJptRMU6Ud6JtAgFxdXlm0F9M0A=", "dev": true }, + "json-stable-stringify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify/-/json-stable-stringify-1.0.1.tgz", + "integrity": "sha1-mnWdOcXy/1A/1TAGRu1EX4jE+a8=", + "dev": true, + "optional": true, + "requires": { + "jsonify": "~0.0.0" + } + }, "json-stringify-safe": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", @@ -5922,11 +6205,19 @@ "integrity": "sha1-Hq3nrMASA0rYTiOWdn6tn6VJWCE=", "dev": true }, + "jsonify": { + "version": "0.0.0", + "resolved": "https://registry.npmjs.org/jsonify/-/jsonify-0.0.0.tgz", + "integrity": "sha1-LHS27kHZPKUbe1qu6PUDYx0lKnM=", + "dev": true, + "optional": true + }, "jsonpointer": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/jsonpointer/-/jsonpointer-4.0.1.tgz", "integrity": "sha1-T9kss04OnbPInIYi7PUfm5eMbLk=", - "dev": true + "dev": true, + "optional": true }, "jsprim": { "version": "1.4.1", @@ -5959,6 +6250,12 @@ "integrity": "sha1-+rg/uwstjchfpjbEudNMdUIMbWU=", "dev": true }, + "es6-promise": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-3.0.2.tgz", + "integrity": "sha1-AQ1YWEI6XxGJeWZfRkhqlcbuK7Y=", + "dev": true + }, "process-nextick-args": { "version": "1.0.7", "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-1.0.7.tgz", @@ -6166,12 +6463,12 @@ } }, "karma-coverage-istanbul-reporter": { - "version": "1.4.2", - "resolved": "https://registry.npmjs.org/karma-coverage-istanbul-reporter/-/karma-coverage-istanbul-reporter-1.4.2.tgz", - "integrity": "sha512-sQHexslLF+QHzaKfK8+onTYMyvSwv+p5cDayVxhpEELGa3z0QuB+l0IMsicIkkBNMOJKQaqueiRoW7iuo7lsog==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/karma-coverage-istanbul-reporter/-/karma-coverage-istanbul-reporter-2.0.1.tgz", + "integrity": "sha512-UcgrHkFehI5+ivMouD8NH/UOHiX4oCAtwaANylzPFdcAuD52fnCUuelacq2gh8tZ4ydhU3+xiXofSq7j5Ehygw==", "dev": true, "requires": { - "istanbul-api": "^1.1.14", + "istanbul-api": "^1.3.1", "minimatch": "^3.0.4" } }, @@ -6227,6 +6524,12 @@ "invert-kv": "^1.0.0" } }, + "leb": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/leb/-/leb-0.3.0.tgz", + "integrity": "sha1-Mr7p+tFoMo1q6oUi2DP0GA7tHaM=", + "dev": true + }, "less": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/less/-/less-3.0.4.tgz", @@ -6348,7 +6651,8 @@ "version": "4.2.0", "resolved": "https://registry.npmjs.org/lodash.assign/-/lodash.assign-4.2.0.tgz", "integrity": "sha1-DZnzzNem0mHRm9rrkkUAXShYCOc=", - "dev": true + "dev": true, + "optional": true }, "lodash.clonedeep": { "version": "4.5.0", @@ -6360,7 +6664,8 @@ "version": "4.6.1", "resolved": "https://registry.npmjs.org/lodash.mergewith/-/lodash.mergewith-4.6.1.tgz", "integrity": "sha512-eWw5r+PYICtEBgrBE5hhlT6aAa75f411bgDz/ZL2KZqYV03USvucsxcHUIlGTDTECs1eunpI7HOV7U+WLDvNdQ==", - "dev": true + "dev": true, + "optional": true }, "lodash.tail": { "version": "4.1.1", @@ -6435,6 +6740,12 @@ "object.assign": "^4.1.0" } }, + "long": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/long/-/long-3.2.0.tgz", + "integrity": "sha1-2CG3E4yhy1gcFymQ7xTbIAtcR0s=", + "dev": true + }, "longest": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/longest/-/longest-1.0.1.tgz", @@ -6477,9 +6788,9 @@ } }, "make-dir": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-1.2.0.tgz", - "integrity": "sha512-aNUAa4UMg/UougV25bbrU4ZaaKNjJ/3/xnvg/twpmKROPdKZPZ9wGgI0opdZzO8q/zUFawoUuixuOv33eZ61Iw==", + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-1.3.0.tgz", + "integrity": "sha512-2w31R7SJtieJJnQtGc7RVL2StM2vGYVfqUOvUDxH6bC6aJTxPxTF0GnIgCyu7tjockiUWAYQRbxa7vKn34s5sQ==", "dev": true, "requires": { "pify": "^3.0.0" @@ -6753,9 +7064,9 @@ } }, "moment": { - "version": "2.22.1", - "resolved": "https://registry.npmjs.org/moment/-/moment-2.22.1.tgz", - "integrity": "sha512-shJkRTSebXvsVqk56I+lkb2latjBs8I+pc2TzWc545y2iFnSjm7Wg0QMh+ZWcdSLQyGEau5jI8ocnmkyTgr9YQ==" + "version": "2.22.2", + "resolved": "https://registry.npmjs.org/moment/-/moment-2.22.2.tgz", + "integrity": "sha1-PCV/mDn8DpP/UxSWMiOeuQeD/2Y=" }, "move-concurrently": { "version": "1.0.1", @@ -6797,7 +7108,8 @@ "version": "2.10.0", "resolved": "https://registry.npmjs.org/nan/-/nan-2.10.0.tgz", "integrity": "sha512-bAdJv7fBLhWC+/Bls0Oza+mvTaNQtP+1RyhhhvD95pgUJz6XM5IzgmxOkItJ9tkoCiplvAnXI1tNmmUD/eScyA==", - "dev": true + "dev": true, + "optional": true }, "nanomatch": { "version": "1.2.9", @@ -6846,17 +7158,17 @@ } }, "ngrx-store-freeze": { - "version": "0.2.2", - "resolved": "https://registry.npmjs.org/ngrx-store-freeze/-/ngrx-store-freeze-0.2.2.tgz", - "integrity": "sha512-t3e6yanpqFv+nsLulh9vz0WBSefjjKtv9ZPd0CylW+mTmylBQgAb+VRWPrbmp78HCsKU0d0lZNbYD8Qd6edcGA==", + "version": "0.2.4", + "resolved": "https://registry.npmjs.org/ngrx-store-freeze/-/ngrx-store-freeze-0.2.4.tgz", + "integrity": "sha512-90awpbbMa/x2H81eWWYniyli3LJ1PZU/FaztL10d9Rp/4kw2+97pqyLjdxSPxcOv9St//m9kfuWZ7gyoVDjgcg==", "requires": { "deep-freeze-strict": "^1.1.1" } }, "ngx-color-picker": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/ngx-color-picker/-/ngx-color-picker-6.0.0.tgz", - "integrity": "sha512-mIhoXOTjv7u/HSMEEA/wAQjhFN7coRN6+i3r9juNoV4RjeCPLZI7T7Tsl1p0xZkgpEYGEEss2R3nPHOTciKOUg==" + "version": "6.3.3", + "resolved": "https://registry.npmjs.org/ngx-color-picker/-/ngx-color-picker-6.3.3.tgz", + "integrity": "sha512-0uoxt+3BtanTTbQj9elpsZe/6a/BWAl8jdl0m6OyrCXlCiO3q4zGZjWee4905RF0NXGxQvDWT27coqmDeXGsvw==" }, "ngx-cookie-service": { "version": "1.0.10", @@ -6879,31 +7191,192 @@ "dev": true }, "node-gyp": { - "version": "3.6.2", - "resolved": "https://registry.npmjs.org/node-gyp/-/node-gyp-3.6.2.tgz", - "integrity": "sha1-m/vlRWIoYoSDjnUOrAUpWFP6HGA=", + "version": "3.7.0", + "resolved": "https://registry.npmjs.org/node-gyp/-/node-gyp-3.7.0.tgz", + "integrity": "sha512-qDQE/Ft9xXP6zphwx4sD0t+VhwV7yFaloMpfbL2QnnDZcyaiakWlLdtFGGQfTAwpFHdpbRhRxVhIHN1OKAjgbg==", "dev": true, + "optional": true, "requires": { "fstream": "^1.0.0", "glob": "^7.0.3", "graceful-fs": "^4.1.2", - "minimatch": "^3.0.2", "mkdirp": "^0.5.0", "nopt": "2 || 3", "npmlog": "0 || 1 || 2 || 3 || 4", "osenv": "0", - "request": "2", + "request": ">=2.9.0 <2.82.0", "rimraf": "2", "semver": "~5.3.0", "tar": "^2.0.0", "which": "1" }, "dependencies": { + "ajv": { + "version": "4.11.8", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-4.11.8.tgz", + "integrity": "sha1-gv+wKynmYq5TvcIK8VlHcGc5xTY=", + "dev": true, + "optional": true, + "requires": { + "co": "^4.6.0", + "json-stable-stringify": "^1.0.1" + } + }, + "assert-plus": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-0.2.0.tgz", + "integrity": "sha1-104bh+ev/A24qttwIfP+SBAasjQ=", + "dev": true, + "optional": true + }, + "aws-sign2": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.6.0.tgz", + "integrity": "sha1-FDQt0428yU0OW4fXY81jYSwOeU8=", + "dev": true, + "optional": true + }, + "boom": { + "version": "2.10.1", + "resolved": "https://registry.npmjs.org/boom/-/boom-2.10.1.tgz", + "integrity": "sha1-OciRjO/1eZ+D+UkqhI9iWt0Mdm8=", + "dev": true, + "requires": { + "hoek": "2.x.x" + } + }, + "cryptiles": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/cryptiles/-/cryptiles-2.0.5.tgz", + "integrity": "sha1-O9/s3GCBR8HGcgL6KR59ylnqo7g=", + "dev": true, + "optional": true, + "requires": { + "boom": "2.x.x" + } + }, + "form-data": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.1.4.tgz", + "integrity": "sha1-M8GDrPGTJ27KqYFDpp6Uv+4XUNE=", + "dev": true, + "optional": true, + "requires": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.5", + "mime-types": "^2.1.12" + } + }, + "har-schema": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-1.0.5.tgz", + "integrity": "sha1-0mMTX0MwfALGAq/I/pWXDAFRNp4=", + "dev": true, + "optional": true + }, + "har-validator": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-4.2.1.tgz", + "integrity": "sha1-M0gdDxu/9gDdID11gSpqX7oALio=", + "dev": true, + "optional": true, + "requires": { + "ajv": "^4.9.1", + "har-schema": "^1.0.5" + } + }, + "hawk": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/hawk/-/hawk-3.1.3.tgz", + "integrity": "sha1-B4REvXwWQLD+VA0sm3PVlnjo4cQ=", + "dev": true, + "optional": true, + "requires": { + "boom": "2.x.x", + "cryptiles": "2.x.x", + "hoek": "2.x.x", + "sntp": "1.x.x" + } + }, + "hoek": { + "version": "2.16.3", + "resolved": "https://registry.npmjs.org/hoek/-/hoek-2.16.3.tgz", + "integrity": "sha1-ILt0A9POo5jpHcRxCo/xuCdKJe0=", + "dev": true + }, + "http-signature": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.1.1.tgz", + "integrity": "sha1-33LiZwZs0Kxn+3at+OE0qPvPkb8=", + "dev": true, + "optional": true, + "requires": { + "assert-plus": "^0.2.0", + "jsprim": "^1.2.2", + "sshpk": "^1.7.0" + } + }, + "performance-now": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-0.2.0.tgz", + "integrity": "sha1-M+8wxcd9TqIcWlOGnZG1bY8lVeU=", + "dev": true, + "optional": true + }, + "qs": { + "version": "6.4.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.4.0.tgz", + "integrity": "sha1-E+JtKK1rD/qpExLNO/cI7TUecjM=", + "dev": true, + "optional": true + }, + "request": { + "version": "2.81.0", + "resolved": "https://registry.npmjs.org/request/-/request-2.81.0.tgz", + "integrity": "sha1-xpKJRqDgbF+Nb4qTM0af/aRimKA=", + "dev": true, + "optional": true, + "requires": { + "aws-sign2": "~0.6.0", + "aws4": "^1.2.1", + "caseless": "~0.12.0", + "combined-stream": "~1.0.5", + "extend": "~3.0.0", + "forever-agent": "~0.6.1", + "form-data": "~2.1.1", + "har-validator": "~4.2.1", + "hawk": "~3.1.3", + "http-signature": "~1.1.0", + "is-typedarray": "~1.0.0", + "isstream": "~0.1.2", + "json-stringify-safe": "~5.0.1", + "mime-types": "~2.1.7", + "oauth-sign": "~0.8.1", + "performance-now": "^0.2.0", + "qs": "~6.4.0", + "safe-buffer": "^5.0.1", + "stringstream": "~0.0.4", + "tough-cookie": "~2.3.0", + "tunnel-agent": "^0.6.0", + "uuid": "^3.0.0" + } + }, "semver": { "version": "5.3.0", "resolved": "https://registry.npmjs.org/semver/-/semver-5.3.0.tgz", "integrity": "sha1-myzl094C0XxgEq0yaqa00M9U+U8=", - "dev": true + "dev": true, + "optional": true + }, + "sntp": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/sntp/-/sntp-1.0.9.tgz", + "integrity": "sha1-ZUEYTMkK7qbG57NeJlkIJEPGYZg=", + "dev": true, + "optional": true, + "requires": { + "hoek": "2.x.x" + } } } }, @@ -6951,6 +7424,7 @@ "resolved": "https://registry.npmjs.org/node-sass/-/node-sass-4.9.0.tgz", "integrity": "sha512-QFHfrZl6lqRU3csypwviz2XLgGNOoWQbo2GOvtsfQqOfL4cy1BtWnhx/XUeAO9LT3ahBzSRXcEO6DdvAH9DzSg==", "dev": true, + "optional": true, "requires": { "async-foreach": "^0.1.3", "chalk": "^1.1.1", @@ -6983,13 +7457,15 @@ "version": "0.2.0", "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-0.2.0.tgz", "integrity": "sha1-104bh+ev/A24qttwIfP+SBAasjQ=", - "dev": true + "dev": true, + "optional": true }, "aws-sign2": { "version": "0.6.0", "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.6.0.tgz", "integrity": "sha1-FDQt0428yU0OW4fXY81jYSwOeU8=", - "dev": true + "dev": true, + "optional": true }, "boom": { "version": "2.10.1", @@ -7004,7 +7480,8 @@ "version": "0.11.0", "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.11.0.tgz", "integrity": "sha1-cVuW6phBWTzDMGeSP17GDr2k99c=", - "dev": true + "dev": true, + "optional": true }, "chalk": { "version": "1.1.3", @@ -7024,6 +7501,7 @@ "resolved": "https://registry.npmjs.org/cryptiles/-/cryptiles-2.0.5.tgz", "integrity": "sha1-O9/s3GCBR8HGcgL6KR59ylnqo7g=", "dev": true, + "optional": true, "requires": { "boom": "2.x.x" } @@ -7033,6 +7511,7 @@ "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.1.4.tgz", "integrity": "sha1-M8GDrPGTJ27KqYFDpp6Uv+4XUNE=", "dev": true, + "optional": true, "requires": { "asynckit": "^0.4.0", "combined-stream": "^1.0.5", @@ -7044,6 +7523,7 @@ "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-2.0.6.tgz", "integrity": "sha1-zcvAgYgmWtEZtqWnyKtw7s+10n0=", "dev": true, + "optional": true, "requires": { "chalk": "^1.1.1", "commander": "^2.9.0", @@ -7056,6 +7536,7 @@ "resolved": "https://registry.npmjs.org/hawk/-/hawk-3.1.3.tgz", "integrity": "sha1-B4REvXwWQLD+VA0sm3PVlnjo4cQ=", "dev": true, + "optional": true, "requires": { "boom": "2.x.x", "cryptiles": "2.x.x", @@ -7074,6 +7555,7 @@ "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.1.1.tgz", "integrity": "sha1-33LiZwZs0Kxn+3at+OE0qPvPkb8=", "dev": true, + "optional": true, "requires": { "assert-plus": "^0.2.0", "jsprim": "^1.2.2", @@ -7084,13 +7566,15 @@ "version": "6.3.2", "resolved": "https://registry.npmjs.org/qs/-/qs-6.3.2.tgz", "integrity": "sha1-51vV9uJoEioqDgvaYwslUMFmUCw=", - "dev": true + "dev": true, + "optional": true }, "request": { "version": "2.79.0", "resolved": "https://registry.npmjs.org/request/-/request-2.79.0.tgz", "integrity": "sha1-Tf5b9r6LjNw3/Pk+BLZVd3InEN4=", "dev": true, + "optional": true, "requires": { "aws-sign2": "~0.6.0", "aws4": "^1.2.1", @@ -7119,6 +7603,7 @@ "resolved": "https://registry.npmjs.org/sntp/-/sntp-1.0.9.tgz", "integrity": "sha1-ZUEYTMkK7qbG57NeJlkIJEPGYZg=", "dev": true, + "optional": true, "requires": { "hoek": "2.x.x" } @@ -7133,7 +7618,8 @@ "version": "0.4.3", "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.4.3.tgz", "integrity": "sha1-Y3PbdpCf5XDgjXNYM2Xtgop07us=", - "dev": true + "dev": true, + "optional": true } } }, @@ -7174,9 +7660,9 @@ "dev": true }, "npm": { - "version": "5.8.0", - "resolved": "https://registry.npmjs.org/npm/-/npm-5.8.0.tgz", - "integrity": "sha512-DowXzQwtSWDtbAjuWecuEiismR0VdNEYaL3VxNTYTdW6AGkYxfGk9LUZ/rt6etEyiH4IEk95HkJeGfXE5Rz9xQ==", + "version": "5.10.0", + "resolved": "https://registry.npmjs.org/npm/-/npm-5.10.0.tgz", + "integrity": "sha512-lvjvjgR5wG2RJ2uqak1xtZcVAWMwVOzN5HkUlUj/n8rU1f3A0fNn+7HwOzH9Lyf0Ppyu9ApgsEpHczOSnx1cwA==", "requires": { "JSONStream": "^1.3.2", "abbrev": "~1.1.1", @@ -7187,9 +7673,11 @@ "archy": "~1.0.0", "bin-links": "^1.1.0", "bluebird": "~3.5.1", + "byte-size": "^4.0.2", "cacache": "^10.0.4", "call-limit": "~1.1.0", "chownr": "~1.0.1", + "cli-columns": "^3.1.2", "cli-table2": "~0.2.0", "cmd-shim": "~2.0.2", "columnify": "~1.5.4", @@ -7214,11 +7702,12 @@ "ini": "^1.3.5", "init-package-json": "^1.10.3", "is-cidr": "~1.0.0", - "json-parse-better-errors": "^1.0.1", + "json-parse-better-errors": "^1.0.2", "lazy-property": "~1.0.0", - "libcipm": "^1.6.0", - "libnpx": "^10.0.1", - "lockfile": "~1.0.3", + "libcipm": "^1.6.2", + "libnpx": "^10.2.0", + "lock-verify": "^2.0.2", + "lockfile": "^1.0.4", "lodash._baseindexof": "*", "lodash._baseuniq": "~4.6.0", "lodash._bindcallback": "*", @@ -7230,20 +7719,23 @@ "lodash.union": "~4.6.0", "lodash.uniq": "~4.5.0", "lodash.without": "~4.4.0", - "lru-cache": "~4.1.1", + "lru-cache": "^4.1.2", "meant": "~1.0.1", "mississippi": "^3.0.0", "mkdirp": "~0.5.1", "move-concurrently": "^1.0.1", + "node-gyp": "^3.6.2", "nopt": "~4.0.1", "normalize-package-data": "~2.4.0", + "npm-audit-report": "^1.0.9", "npm-cache-filename": "~1.0.2", "npm-install-checks": "~3.0.0", "npm-lifecycle": "^2.0.1", - "npm-package-arg": "~6.0.0", + "npm-package-arg": "^6.1.0", "npm-packlist": "~1.1.10", "npm-profile": "^3.0.1", "npm-registry-client": "^8.5.1", + "npm-registry-fetch": "^1.1.0", "npm-user-validate": "~1.0.0", "npmlog": "~4.1.2", "once": "~1.4.0", @@ -7252,39 +7744,40 @@ "pacote": "^7.6.1", "path-is-inside": "~1.0.2", "promise-inflight": "~1.0.1", - "qrcode-terminal": "~0.11.0", - "query-string": "^5.1.0", + "qrcode-terminal": "^0.12.0", + "query-string": "^6.1.0", "qw": "~1.0.1", "read": "~1.0.7", "read-cmd-shim": "~1.0.1", "read-installed": "~4.0.3", "read-package-json": "^2.0.13", - "read-package-tree": "~5.1.6", - "readable-stream": "^2.3.5", + "read-package-tree": "^5.2.1", + "readable-stream": "^2.3.6", "readdir-scoped-modules": "*", - "request": "~2.83.0", - "retry": "~0.10.1", + "request": "^2.85.0", + "retry": "^0.12.0", "rimraf": "~2.6.2", - "safe-buffer": "~5.1.1", + "safe-buffer": "^5.1.2", "semver": "^5.5.0", "sha": "~2.0.1", "slide": "~1.1.6", "sorted-object": "~2.0.1", "sorted-union-stream": "~2.1.3", - "ssri": "^5.2.4", + "ssri": "^5.3.0", "strip-ansi": "~4.0.0", - "tar": "^4.4.0", + "tar": "^4.4.2", "text-table": "~0.2.0", + "tiny-relative-date": "^1.3.0", "uid-number": "0.0.6", "umask": "~1.1.0", "unique-filename": "~1.1.0", "unpipe": "~1.0.0", - "update-notifier": "~2.3.0", + "update-notifier": "^2.5.0", "uuid": "^3.2.1", - "validate-npm-package-license": "*", + "validate-npm-package-license": "^3.0.3", "validate-npm-package-name": "~3.0.0", "which": "~1.3.0", - "worker-farm": "^1.5.4", + "worker-farm": "^1.6.0", "wrappy": "~1.0.2", "write-file-atomic": "^2.3.0" }, @@ -7347,6 +7840,10 @@ "version": "3.5.1", "bundled": true }, + "byte-size": { + "version": "4.0.2", + "bundled": true + }, "cacache": { "version": "10.0.4", "bundled": true, @@ -7512,6 +8009,50 @@ "version": "1.0.1", "bundled": true }, + "cli-columns": { + "version": "3.1.2", + "bundled": true, + "requires": { + "string-width": "^2.0.0", + "strip-ansi": "^3.0.1" + }, + "dependencies": { + "string-width": { + "version": "2.1.1", + "bundled": true, + "requires": { + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^4.0.0" + }, + "dependencies": { + "is-fullwidth-code-point": { + "version": "2.0.0", + "bundled": true + }, + "strip-ansi": { + "version": "4.0.0", + "bundled": true, + "requires": { + "ansi-regex": "^3.0.0" + } + } + } + }, + "strip-ansi": { + "version": "3.0.1", + "bundled": true, + "requires": { + "ansi-regex": "^2.0.0" + }, + "dependencies": { + "ansi-regex": { + "version": "2.1.1", + "bundled": true + } + } + } + } + }, "cli-table2": { "version": "0.2.0", "bundled": true, @@ -7829,7 +8370,7 @@ } }, "json-parse-better-errors": { - "version": "1.0.1", + "version": "1.0.2", "bundled": true }, "lazy-property": { @@ -7837,7 +8378,7 @@ "bundled": true }, "libcipm": { - "version": "1.6.0", + "version": "1.6.2", "bundled": true, "requires": { "bin-links": "^1.1.0", @@ -7856,7 +8397,7 @@ }, "dependencies": { "lock-verify": { - "version": "2.0.0", + "version": "2.0.1", "bundled": true, "requires": { "npm-package-arg": "^5.1.2", @@ -7891,38 +8432,11 @@ "bundled": true } } - }, - "worker-farm": { - "version": "1.5.4", - "bundled": true, - "requires": { - "errno": "~0.1.7", - "xtend": "~4.0.1" - }, - "dependencies": { - "errno": { - "version": "0.1.7", - "bundled": true, - "requires": { - "prr": "~1.0.1" - }, - "dependencies": { - "prr": { - "version": "1.0.1", - "bundled": true - } - } - }, - "xtend": { - "version": "4.0.1", - "bundled": true - } - } } } }, "libnpx": { - "version": "10.0.1", + "version": "10.2.0", "bundled": true, "requires": { "dotenv": "^5.0.1", @@ -7962,7 +8476,7 @@ }, "dependencies": { "cliui": { - "version": "4.0.0", + "version": "4.1.0", "bundled": true, "requires": { "string-width": "^2.1.1", @@ -8236,9 +8750,26 @@ } } }, + "lock-verify": { + "version": "2.0.2", + "bundled": true, + "requires": { + "npm-package-arg": "^5.1.2 || 6", + "semver": "^5.4.1" + } + }, "lockfile": { - "version": "1.0.3", - "bundled": true + "version": "1.0.4", + "bundled": true, + "requires": { + "signal-exit": "^3.0.2" + }, + "dependencies": { + "signal-exit": { + "version": "3.0.2", + "bundled": true + } + } }, "lodash._baseindexof": { "version": "3.1.0", @@ -8302,7 +8833,7 @@ "bundled": true }, "lru-cache": { - "version": "4.1.1", + "version": "4.1.2", "bundled": true, "requires": { "pseudomap": "^1.0.2", @@ -8511,6 +9042,93 @@ } } }, + "node-gyp": { + "version": "3.6.2", + "bundled": true, + "requires": { + "fstream": "^1.0.0", + "glob": "^7.0.3", + "graceful-fs": "^4.1.2", + "minimatch": "^3.0.2", + "mkdirp": "^0.5.0", + "nopt": "2 || 3", + "npmlog": "0 || 1 || 2 || 3 || 4", + "osenv": "0", + "request": "2", + "rimraf": "2", + "semver": "~5.3.0", + "tar": "^2.0.0", + "which": "1" + }, + "dependencies": { + "fstream": { + "version": "1.0.11", + "bundled": true, + "requires": { + "graceful-fs": "^4.1.2", + "inherits": "~2.0.0", + "mkdirp": ">=0.5 0", + "rimraf": "2" + } + }, + "minimatch": { + "version": "3.0.4", + "bundled": true, + "requires": { + "brace-expansion": "^1.1.7" + }, + "dependencies": { + "brace-expansion": { + "version": "1.1.11", + "bundled": true, + "requires": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + }, + "dependencies": { + "balanced-match": { + "version": "1.0.0", + "bundled": true + }, + "concat-map": { + "version": "0.0.1", + "bundled": true + } + } + } + } + }, + "nopt": { + "version": "3.0.6", + "bundled": true, + "requires": { + "abbrev": "1" + } + }, + "semver": { + "version": "5.3.0", + "bundled": true + }, + "tar": { + "version": "2.2.1", + "bundled": true, + "requires": { + "block-stream": "*", + "fstream": "^1.0.2", + "inherits": "2" + }, + "dependencies": { + "block-stream": { + "version": "0.0.9", + "bundled": true, + "requires": { + "inherits": "~2.0.0" + } + } + } + } + } + }, "nopt": { "version": "4.0.1", "bundled": true, @@ -8544,6 +9162,20 @@ } } }, + "npm-audit-report": { + "version": "1.0.9", + "bundled": true, + "requires": { + "cli-table2": "^0.2.0", + "console-control-strings": "^1.1.0" + }, + "dependencies": { + "console-control-strings": { + "version": "1.1.0", + "bundled": true + } + } + }, "npm-cache-filename": { "version": "1.0.2", "bundled": true @@ -8573,93 +9205,6 @@ "version": "5.0.0", "bundled": true }, - "node-gyp": { - "version": "3.6.2", - "bundled": true, - "requires": { - "fstream": "^1.0.0", - "glob": "^7.0.3", - "graceful-fs": "^4.1.2", - "minimatch": "^3.0.2", - "mkdirp": "^0.5.0", - "nopt": "2 || 3", - "npmlog": "0 || 1 || 2 || 3 || 4", - "osenv": "0", - "request": "2", - "rimraf": "2", - "semver": "~5.3.0", - "tar": "^2.0.0", - "which": "1" - }, - "dependencies": { - "fstream": { - "version": "1.0.11", - "bundled": true, - "requires": { - "graceful-fs": "^4.1.2", - "inherits": "~2.0.0", - "mkdirp": ">=0.5 0", - "rimraf": "2" - } - }, - "minimatch": { - "version": "3.0.4", - "bundled": true, - "requires": { - "brace-expansion": "^1.1.7" - }, - "dependencies": { - "brace-expansion": { - "version": "1.1.11", - "bundled": true, - "requires": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - }, - "dependencies": { - "balanced-match": { - "version": "1.0.0", - "bundled": true - }, - "concat-map": { - "version": "0.0.1", - "bundled": true - } - } - } - } - }, - "nopt": { - "version": "3.0.6", - "bundled": true, - "requires": { - "abbrev": "1" - } - }, - "semver": { - "version": "5.3.0", - "bundled": true - }, - "tar": { - "version": "2.2.1", - "bundled": true, - "requires": { - "block-stream": "*", - "fstream": "^1.0.2", - "inherits": "2" - }, - "dependencies": { - "block-stream": { - "version": "0.0.9", - "bundled": true, - "requires": { - "inherits": "~2.0.0" - } - } - } - } - } - }, "resolve-from": { "version": "4.0.0", "bundled": true @@ -8667,12 +9212,12 @@ } }, "npm-package-arg": { - "version": "6.0.0", + "version": "6.1.0", "bundled": true, "requires": { - "hosted-git-info": "^2.5.0", - "osenv": "^0.1.4", - "semver": "^5.4.1", + "hosted-git-info": "^2.6.0", + "osenv": "^0.1.5", + "semver": "^5.5.0", "validate-npm-package-name": "^3.0.0" } }, @@ -9048,6 +9593,10 @@ "err-code": { "version": "1.1.2", "bundled": true + }, + "retry": { + "version": "0.10.1", + "bundled": true } } }, @@ -9137,6 +9686,264 @@ "bundled": true } } + }, + "retry": { + "version": "0.10.1", + "bundled": true + } + } + }, + "npm-registry-fetch": { + "version": "1.1.0", + "bundled": true, + "requires": { + "bluebird": "^3.5.1", + "figgy-pudding": "^2.0.1", + "lru-cache": "^4.1.2", + "make-fetch-happen": "^3.0.0", + "npm-package-arg": "^6.0.0", + "safe-buffer": "^5.1.1" + }, + "dependencies": { + "figgy-pudding": { + "version": "2.0.1", + "bundled": true + }, + "make-fetch-happen": { + "version": "3.0.0", + "bundled": true, + "requires": { + "agentkeepalive": "^3.4.1", + "cacache": "^10.0.4", + "http-cache-semantics": "^3.8.1", + "http-proxy-agent": "^2.1.0", + "https-proxy-agent": "^2.2.0", + "lru-cache": "^4.1.2", + "mississippi": "^3.0.0", + "node-fetch-npm": "^2.0.2", + "promise-retry": "^1.1.1", + "socks-proxy-agent": "^3.0.1", + "ssri": "^5.2.4" + }, + "dependencies": { + "agentkeepalive": { + "version": "3.4.1", + "bundled": true, + "requires": { + "humanize-ms": "^1.2.1" + }, + "dependencies": { + "humanize-ms": { + "version": "1.2.1", + "bundled": true, + "requires": { + "ms": "^2.0.0" + }, + "dependencies": { + "ms": { + "version": "2.1.1", + "bundled": true + } + } + } + } + }, + "http-cache-semantics": { + "version": "3.8.1", + "bundled": true + }, + "http-proxy-agent": { + "version": "2.1.0", + "bundled": true, + "requires": { + "agent-base": "4", + "debug": "3.1.0" + }, + "dependencies": { + "agent-base": { + "version": "4.2.0", + "bundled": true, + "requires": { + "es6-promisify": "^5.0.0" + }, + "dependencies": { + "es6-promisify": { + "version": "5.0.0", + "bundled": true, + "requires": { + "es6-promise": "^4.0.3" + }, + "dependencies": { + "es6-promise": { + "version": "4.2.4", + "bundled": true + } + } + } + } + }, + "debug": { + "version": "3.1.0", + "bundled": true, + "requires": { + "ms": "2.0.0" + }, + "dependencies": { + "ms": { + "version": "2.0.0", + "bundled": true + } + } + } + } + }, + "https-proxy-agent": { + "version": "2.2.1", + "bundled": true, + "requires": { + "agent-base": "^4.1.0", + "debug": "^3.1.0" + }, + "dependencies": { + "agent-base": { + "version": "4.2.0", + "bundled": true, + "requires": { + "es6-promisify": "^5.0.0" + }, + "dependencies": { + "es6-promisify": { + "version": "5.0.0", + "bundled": true, + "requires": { + "es6-promise": "^4.0.3" + }, + "dependencies": { + "es6-promise": { + "version": "4.2.4", + "bundled": true + } + } + } + } + }, + "debug": { + "version": "3.1.0", + "bundled": true, + "requires": { + "ms": "2.0.0" + }, + "dependencies": { + "ms": { + "version": "2.0.0", + "bundled": true + } + } + } + } + }, + "node-fetch-npm": { + "version": "2.0.2", + "bundled": true, + "requires": { + "encoding": "^0.1.11", + "json-parse-better-errors": "^1.0.0", + "safe-buffer": "^5.1.1" + }, + "dependencies": { + "encoding": { + "version": "0.1.12", + "bundled": true, + "requires": { + "iconv-lite": "~0.4.13" + }, + "dependencies": { + "iconv-lite": { + "version": "0.4.21", + "bundled": true, + "requires": { + "safer-buffer": "^2.1.0" + }, + "dependencies": { + "safer-buffer": { + "version": "2.1.2", + "bundled": true + } + } + } + } + } + } + }, + "promise-retry": { + "version": "1.1.1", + "bundled": true, + "requires": { + "err-code": "^1.0.0", + "retry": "^0.10.0" + }, + "dependencies": { + "err-code": { + "version": "1.1.2", + "bundled": true + }, + "retry": { + "version": "0.10.1", + "bundled": true + } + } + }, + "socks-proxy-agent": { + "version": "3.0.1", + "bundled": true, + "requires": { + "agent-base": "^4.1.0", + "socks": "^1.1.10" + }, + "dependencies": { + "agent-base": { + "version": "4.2.0", + "bundled": true, + "requires": { + "es6-promisify": "^5.0.0" + }, + "dependencies": { + "es6-promisify": { + "version": "5.0.0", + "bundled": true, + "requires": { + "es6-promise": "^4.0.3" + }, + "dependencies": { + "es6-promise": { + "version": "4.2.4", + "bundled": true + } + } + } + } + }, + "socks": { + "version": "1.1.10", + "bundled": true, + "requires": { + "ip": "^1.1.4", + "smart-buffer": "^1.0.13" + }, + "dependencies": { + "ip": { + "version": "1.1.5", + "bundled": true + }, + "smart-buffer": { + "version": "1.1.15", + "bundled": true + } + } + } + } + } + } } } }, @@ -9714,6 +10521,10 @@ "err-code": { "version": "1.1.2", "bundled": true + }, + "retry": { + "version": "0.10.1", + "bundled": true } } }, @@ -9741,28 +10552,23 @@ "bundled": true }, "qrcode-terminal": { - "version": "0.11.0", + "version": "0.12.0", "bundled": true }, "query-string": { - "version": "5.1.0", + "version": "6.1.0", "bundled": true, "requires": { "decode-uri-component": "^0.2.0", - "object-assign": "^4.1.0", - "strict-uri-encode": "^1.0.0" + "strict-uri-encode": "^2.0.0" }, "dependencies": { "decode-uri-component": { "version": "0.2.0", "bundled": true }, - "object-assign": { - "version": "4.1.1", - "bundled": true - }, "strict-uri-encode": { - "version": "1.1.0", + "version": "2.0.0", "bundled": true } } @@ -9832,7 +10638,7 @@ } }, "read-package-tree": { - "version": "5.1.6", + "version": "5.2.1", "bundled": true, "requires": { "debuglog": "^1.0.1", @@ -9843,7 +10649,7 @@ } }, "readable-stream": { - "version": "2.3.5", + "version": "2.3.6", "bundled": true, "requires": { "core-util-is": "~1.0.0", @@ -9851,7 +10657,7 @@ "isarray": "~1.0.0", "process-nextick-args": "~2.0.0", "safe-buffer": "~5.1.1", - "string_decoder": "~1.0.3", + "string_decoder": "~1.1.1", "util-deprecate": "~1.0.1" }, "dependencies": { @@ -9868,7 +10674,7 @@ "bundled": true }, "string_decoder": { - "version": "1.0.3", + "version": "1.1.1", "bundled": true, "requires": { "safe-buffer": "~5.1.0" @@ -9891,7 +10697,7 @@ } }, "request": { - "version": "2.83.0", + "version": "2.85.0", "bundled": true, "requires": { "aws-sign2": "~0.7.0", @@ -9931,7 +10737,7 @@ "bundled": true }, "combined-stream": { - "version": "1.0.5", + "version": "1.0.6", "bundled": true, "requires": { "delayed-stream": "~1.0.0" @@ -9952,11 +10758,11 @@ "bundled": true }, "form-data": { - "version": "2.3.1", + "version": "2.3.2", "bundled": true, "requires": { "asynckit": "^0.4.0", - "combined-stream": "^1.0.5", + "combined-stream": "1.0.6", "mime-types": "^2.1.12" }, "dependencies": { @@ -9975,13 +10781,13 @@ }, "dependencies": { "ajv": { - "version": "5.2.3", + "version": "5.5.2", "bundled": true, "requires": { "co": "^4.6.0", "fast-deep-equal": "^1.0.0", - "json-schema-traverse": "^0.3.0", - "json-stable-stringify": "^1.0.1" + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.3.0" }, "dependencies": { "co": { @@ -9989,25 +10795,16 @@ "bundled": true }, "fast-deep-equal": { - "version": "1.0.0", + "version": "1.1.0", + "bundled": true + }, + "fast-json-stable-stringify": { + "version": "2.0.0", "bundled": true }, "json-schema-traverse": { "version": "0.3.1", "bundled": true - }, - "json-stable-stringify": { - "version": "1.0.1", - "bundled": true, - "requires": { - "jsonify": "~0.0.0" - }, - "dependencies": { - "jsonify": { - "version": "0.0.0", - "bundled": true - } - } } } }, @@ -10051,11 +10848,11 @@ } }, "hoek": { - "version": "4.2.0", + "version": "4.2.1", "bundled": true }, "sntp": { - "version": "2.0.2", + "version": "2.1.0", "bundled": true, "requires": { "hoek": "4.x.x" @@ -10112,7 +10909,7 @@ } }, "sshpk": { - "version": "1.13.1", + "version": "1.14.1", "bundled": true, "requires": { "asn1": "~0.2.3", @@ -10186,14 +10983,14 @@ "bundled": true }, "mime-types": { - "version": "2.1.17", + "version": "2.1.18", "bundled": true, "requires": { - "mime-db": "~1.30.0" + "mime-db": "~1.33.0" }, "dependencies": { "mime-db": { - "version": "1.30.0", + "version": "1.33.0", "bundled": true } } @@ -10215,7 +11012,7 @@ "bundled": true }, "tough-cookie": { - "version": "2.3.3", + "version": "2.3.4", "bundled": true, "requires": { "punycode": "^1.4.1" @@ -10237,7 +11034,7 @@ } }, "retry": { - "version": "0.10.1", + "version": "0.12.0", "bundled": true }, "rimraf": { @@ -10248,7 +11045,7 @@ } }, "safe-buffer": { - "version": "5.1.1", + "version": "5.1.2", "bundled": true }, "semver": { @@ -10330,7 +11127,7 @@ } }, "ssri": { - "version": "5.2.4", + "version": "5.3.0", "bundled": true, "requires": { "safe-buffer": "^5.1.1" @@ -10350,14 +11147,15 @@ } }, "tar": { - "version": "4.4.0", + "version": "4.4.2", "bundled": true, "requires": { "chownr": "^1.0.1", - "fs-minipass": "^1.2.3", - "minipass": "^2.2.1", + "fs-minipass": "^1.2.5", + "minipass": "^2.2.4", "minizlib": "^1.1.0", "mkdirp": "^0.5.0", + "safe-buffer": "^5.1.2", "yallist": "^3.0.2" }, "dependencies": { @@ -10369,9 +11167,10 @@ } }, "minipass": { - "version": "2.2.1", + "version": "2.2.4", "bundled": true, "requires": { + "safe-buffer": "^5.1.1", "yallist": "^3.0.0" } }, @@ -10382,6 +11181,10 @@ "minipass": "^2.2.1" } }, + "safe-buffer": { + "version": "5.1.2", + "bundled": true + }, "yallist": { "version": "3.0.2", "bundled": true @@ -10392,6 +11195,10 @@ "version": "0.2.0", "bundled": true }, + "tiny-relative-date": { + "version": "1.3.0", + "bundled": true + }, "uid-number": { "version": "0.0.6", "bundled": true @@ -10421,13 +11228,14 @@ "bundled": true }, "update-notifier": { - "version": "2.3.0", + "version": "2.5.0", "bundled": true, "requires": { "boxen": "^1.2.1", "chalk": "^2.0.1", "configstore": "^3.0.0", "import-lazy": "^2.1.0", + "is-ci": "^1.0.10", "is-installed-globally": "^0.1.0", "is-npm": "^1.0.0", "latest-version": "^3.0.0", @@ -10436,7 +11244,7 @@ }, "dependencies": { "boxen": { - "version": "1.2.1", + "version": "1.3.0", "bundled": true, "requires": { "ansi-align": "^2.0.0", @@ -10445,7 +11253,7 @@ "cli-boxes": "^1.0.0", "string-width": "^2.0.0", "term-size": "^1.2.0", - "widest-line": "^1.0.0" + "widest-line": "^2.0.0" }, "dependencies": { "ansi-align": { @@ -10559,75 +11367,32 @@ } }, "widest-line": { - "version": "1.0.0", + "version": "2.0.0", "bundled": true, "requires": { - "string-width": "^1.0.1" - }, - "dependencies": { - "string-width": { - "version": "1.0.2", - "bundled": true, - "requires": { - "code-point-at": "^1.0.0", - "is-fullwidth-code-point": "^1.0.0", - "strip-ansi": "^3.0.0" - }, - "dependencies": { - "code-point-at": { - "version": "1.1.0", - "bundled": true - }, - "is-fullwidth-code-point": { - "version": "1.0.0", - "bundled": true, - "requires": { - "number-is-nan": "^1.0.0" - }, - "dependencies": { - "number-is-nan": { - "version": "1.0.1", - "bundled": true - } - } - }, - "strip-ansi": { - "version": "3.0.1", - "bundled": true, - "requires": { - "ansi-regex": "^2.0.0" - }, - "dependencies": { - "ansi-regex": { - "version": "2.1.1", - "bundled": true - } - } - } - } - } + "string-width": "^2.1.1" } } } }, "chalk": { - "version": "2.1.0", + "version": "2.4.1", "bundled": true, "requires": { - "ansi-styles": "^3.1.0", + "ansi-styles": "^3.2.1", "escape-string-regexp": "^1.0.5", - "supports-color": "^4.0.0" + "supports-color": "^5.3.0" }, "dependencies": { "ansi-styles": { - "version": "3.2.0", + "version": "3.2.1", "bundled": true, "requires": { "color-convert": "^1.9.0" }, "dependencies": { "color-convert": { - "version": "1.9.0", + "version": "1.9.1", "bundled": true, "requires": { "color-name": "^1.1.1" @@ -10646,14 +11411,14 @@ "bundled": true }, "supports-color": { - "version": "4.4.0", + "version": "5.4.0", "bundled": true, "requires": { - "has-flag": "^2.0.0" + "has-flag": "^3.0.0" }, "dependencies": { "has-flag": { - "version": "2.0.0", + "version": "3.0.0", "bundled": true } } @@ -10661,7 +11426,7 @@ } }, "configstore": { - "version": "3.1.1", + "version": "3.1.2", "bundled": true, "requires": { "dot-prop": "^4.1.0", @@ -10686,14 +11451,14 @@ } }, "make-dir": { - "version": "1.0.0", + "version": "1.2.0", "bundled": true, "requires": { - "pify": "^2.3.0" + "pify": "^3.0.0" }, "dependencies": { "pify": { - "version": "2.3.0", + "version": "3.0.0", "bundled": true } } @@ -10717,6 +11482,19 @@ "version": "2.1.0", "bundled": true }, + "is-ci": { + "version": "1.1.0", + "bundled": true, + "requires": { + "ci-info": "^1.0.0" + }, + "dependencies": { + "ci-info": { + "version": "1.1.3", + "bundled": true + } + } + }, "is-installed-globally": { "version": "0.1.0", "bundled": true, @@ -10726,14 +11504,14 @@ }, "dependencies": { "global-dirs": { - "version": "0.1.0", + "version": "0.1.1", "bundled": true, "requires": { "ini": "^1.3.4" } }, "is-path-inside": { - "version": "1.0.0", + "version": "1.0.1", "bundled": true, "requires": { "path-is-inside": "^1.0.1" @@ -10813,7 +11591,7 @@ "bundled": true }, "lowercase-keys": { - "version": "1.0.0", + "version": "1.0.1", "bundled": true }, "timed-out": { @@ -10840,7 +11618,7 @@ } }, "registry-auth-token": { - "version": "3.3.1", + "version": "3.3.2", "bundled": true, "requires": { "rc": "^1.1.6", @@ -10848,17 +11626,17 @@ }, "dependencies": { "rc": { - "version": "1.2.1", + "version": "1.2.7", "bundled": true, "requires": { - "deep-extend": "~0.4.0", + "deep-extend": "^0.5.1", "ini": "~1.3.0", "minimist": "^1.2.0", "strip-json-comments": "~2.0.1" }, "dependencies": { "deep-extend": { - "version": "0.4.2", + "version": "0.5.1", "bundled": true }, "minimist": { @@ -10881,17 +11659,17 @@ }, "dependencies": { "rc": { - "version": "1.2.1", + "version": "1.2.7", "bundled": true, "requires": { - "deep-extend": "~0.4.0", + "deep-extend": "^0.5.1", "ini": "~1.3.0", "minimist": "^1.2.0", "strip-json-comments": "~2.0.1" }, "dependencies": { "deep-extend": { - "version": "0.4.2", + "version": "0.5.1", "bundled": true }, "minimist": { @@ -10928,29 +11706,44 @@ "bundled": true }, "validate-npm-package-license": { - "version": "3.0.1", + "version": "3.0.3", "bundled": true, "requires": { - "spdx-correct": "~1.0.0", - "spdx-expression-parse": "~1.0.0" + "spdx-correct": "^3.0.0", + "spdx-expression-parse": "^3.0.0" }, "dependencies": { "spdx-correct": { - "version": "1.0.2", + "version": "3.0.0", "bundled": true, "requires": { - "spdx-license-ids": "^1.0.2" + "spdx-expression-parse": "^3.0.0", + "spdx-license-ids": "^3.0.0" }, "dependencies": { "spdx-license-ids": { - "version": "1.2.2", + "version": "3.0.0", "bundled": true } } }, "spdx-expression-parse": { - "version": "1.0.4", - "bundled": true + "version": "3.0.0", + "bundled": true, + "requires": { + "spdx-exceptions": "^2.1.0", + "spdx-license-ids": "^3.0.0" + }, + "dependencies": { + "spdx-exceptions": { + "version": "2.1.0", + "bundled": true + }, + "spdx-license-ids": { + "version": "3.0.0", + "bundled": true + } + } } } }, @@ -10981,11 +11774,10 @@ } }, "worker-farm": { - "version": "1.5.4", + "version": "1.6.0", "bundled": true, "requires": { - "errno": "~0.1.7", - "xtend": "~4.0.1" + "errno": "~0.1.7" }, "dependencies": { "errno": { @@ -11000,10 +11792,6 @@ "bundled": true } } - }, - "xtend": { - "version": "4.0.1", - "bundled": true } } }, @@ -11308,24 +12096,12 @@ "dev": true }, "original": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/original/-/original-1.0.0.tgz", - "integrity": "sha1-kUf5P6FpbQS+YeAb1QuurKZWvTs=", + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/original/-/original-1.0.1.tgz", + "integrity": "sha512-IEvtB5vM5ULvwnqMxWBLxkS13JIEXbakizMSo3yoPNPCIWzg8TG3Usn/UhXoZFM/m+FuEA20KdzPSFq/0rS+UA==", "dev": true, "requires": { - "url-parse": "1.0.x" - }, - "dependencies": { - "url-parse": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.0.5.tgz", - "integrity": "sha1-CFSGBCKv3P7+tsllxmLUgAFpkns=", - "dev": true, - "requires": { - "querystringify": "0.0.x", - "requires-port": "1.0.x" - } - } + "url-parse": "~1.4.0" } }, "os-browserify": { @@ -11345,6 +12121,7 @@ "resolved": "https://registry.npmjs.org/os-locale/-/os-locale-1.4.0.tgz", "integrity": "sha1-IPnxeuKe00XoveWDsT0gCYA8FNk=", "dev": true, + "optional": true, "requires": { "lcid": "^1.0.0" } @@ -11372,9 +12149,9 @@ "dev": true }, "p-limit": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.2.0.tgz", - "integrity": "sha512-Y/OtIaXtUPr4/YpMv1pCL5L5ed0rumAaAeBSj12F+bSlMdys7i8oQF/GUJmfpTS/QoaRrS/k6pma29haJpsMng==", + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.3.0.tgz", + "integrity": "sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q==", "dev": true, "requires": { "p-try": "^1.0.0" @@ -11594,9 +12371,9 @@ } }, "perfect-scrollbar": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/perfect-scrollbar/-/perfect-scrollbar-1.3.0.tgz", - "integrity": "sha512-7Ub8YOvZB5k+pTy0K3LYUDnH9Xl3qvHcclJyIX+AV5UxHxll146iVGq4rtc+848nTDBQq89J7QxKKMA++cTXzQ==" + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/perfect-scrollbar/-/perfect-scrollbar-1.4.0.tgz", + "integrity": "sha512-/2Sk/khljhdrsamjJYS5NjrH+GKEHEwh7zFSiYyxROyYKagkE4kSn2zDQDRTOMo8mpT2jikxx6yI1dG7lNP/hw==" }, "performance-now": { "version": "2.1.0", @@ -11820,9 +12597,9 @@ "dev": true }, "protractor": { - "version": "5.3.1", - "resolved": "https://registry.npmjs.org/protractor/-/protractor-5.3.1.tgz", - "integrity": "sha512-AW9qJ0prx2QEMy1gnhJ1Sl1WBQL2R3fx/VnG09FEmWprPIQPK14t0B83OB/pAGddpxiDCAAV0KiNNLf2c2Y/lQ==", + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/protractor/-/protractor-5.3.2.tgz", + "integrity": "sha512-pw4uwwiy5lHZjIguxNpkEwJJa7hVz+bJsvaTI+IbXlfn2qXwzbF8eghW/RmrZwE2sGx82I8etb8lVjQ+JrjejA==", "dev": true, "requires": { "@types/node": "^6.0.46", @@ -11835,7 +12612,7 @@ "jasminewd2": "^2.1.0", "optimist": "~0.6.0", "q": "1.4.1", - "saucelabs": "~1.3.0", + "saucelabs": "^1.5.0", "selenium-webdriver": "3.6.0", "source-map-support": "~0.4.0", "webdriver-js-extender": "^1.0.0", @@ -11843,15 +12620,15 @@ }, "dependencies": { "@types/node": { - "version": "6.0.109", - "resolved": "https://registry.npmjs.org/@types/node/-/node-6.0.109.tgz", - "integrity": "sha512-z8zzzMkjsMI4TgrjjRIvC5kcpqKE8euFbGvImGiujpdKsxbxiy6KguRJ93SFoEOKqeOsKBpaaHjobthVq6EOCg==", + "version": "6.0.110", + "resolved": "https://registry.npmjs.org/@types/node/-/node-6.0.110.tgz", + "integrity": "sha512-LiaH3mF+OAqR+9Wo1OTJDbZDtCewAVjTbMhF1ZgUJ3fc8xqOJq6VqbpBh9dJVCVzByGmYIg2fREbuXNX0TKiJA==", "dev": true }, "adm-zip": { - "version": "0.4.9", - "resolved": "https://registry.npmjs.org/adm-zip/-/adm-zip-0.4.9.tgz", - "integrity": "sha512-eknaJ3Io/JasGGinVeqY5TsPlQgHbiNlHnK5zdFPRNs9XRggDykKz8zPesneOMEZJxWji7G3CfsUW0Ds9Dw0Bw==", + "version": "0.4.11", + "resolved": "https://registry.npmjs.org/adm-zip/-/adm-zip-0.4.11.tgz", + "integrity": "sha512-L8vcjDTCOIJk7wFvmlEUN7AsSb8T+2JrdP7KINBjzr24TJ5Mwj590sLu3BC7zNZowvJWa/JtPmD8eJCzdtDWjA==", "dev": true }, "ansi-styles": { @@ -11996,9 +12773,9 @@ } }, "pumpify": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/pumpify/-/pumpify-1.5.0.tgz", - "integrity": "sha512-UWi0klDoq8xtVzlMRgENV9F7iCTZExaJQSQL187UXsxpk9NnrKGqTqqUNYAKGOzucSOxs2+jUnRNI+rLviPhJg==", + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/pumpify/-/pumpify-1.5.1.tgz", + "integrity": "sha512-oClZI37HvuUJJxSKKrC17bZ9Cu0ZYhEAGPsPUy9KlMUmv9dKX2o77RUmq7f3XjIxbwyGwYzbzQ1L2Ks8sIradQ==", "dev": true, "requires": { "duplexify": "^3.6.0", @@ -12007,9 +12784,9 @@ } }, "punycode": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.0.tgz", - "integrity": "sha1-X4Y+3Im5bbCQdLrXlHvwkFbKTn0=", + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", + "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==", "dev": true }, "q": { @@ -12043,9 +12820,9 @@ "dev": true }, "querystringify": { - "version": "0.0.4", - "resolved": "https://registry.npmjs.org/querystringify/-/querystringify-0.0.4.tgz", - "integrity": "sha1-DPf4T5Rj/wrlHExLFC2VvjdyTZw=", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/querystringify/-/querystringify-2.0.0.tgz", + "integrity": "sha512-eTPo5t/4bgaMNZxyjWx6N2a6AuE0mq51KWvpc7nU/MAqixcI6v6KrGUKES0HaomdnolQBBXU/++X6/QQ9KL4tw==", "dev": true }, "randomatic": { @@ -12522,17 +13299,17 @@ "integrity": "sha1-P4Yt+pGrdmsUiF700BEkv9oHT7Q=" }, "rxjs": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.1.0.tgz", - "integrity": "sha512-lMZdl6xbHJCSb5lmnb6nOhsoBVCyoDC5LDJQK9WWyq+tsI7KnlDIZ0r0AZAlBpRPLbwQA9kzSBAZwNIZEZ+hcw==", + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.2.1.tgz", + "integrity": "sha512-OwMxHxmnmHTUpgO+V7dZChf3Tixf4ih95cmXjzzadULziVl/FKhHScGLj4goEw9weePVOH2Q0+GcCBUhKCZc/g==", "requires": { "tslib": "^1.9.0" } }, "rxjs-compat": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/rxjs-compat/-/rxjs-compat-6.1.0.tgz", - "integrity": "sha512-x5L1KQy1RqDRpPadN5iDOx71TV9Wqmlmu6OOEn3tFFgaTCB0/N+Lmby/rZHgJ6JEPzzt0nD9Zv+kS53E5JIR5g==" + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/rxjs-compat/-/rxjs-compat-6.2.1.tgz", + "integrity": "sha512-Pst0lkAwVodBbBOIZic9aM1vY9asJ2u8GfKN115+goIH83PAlizJDyvixuxPAuQ1UtkmBuro7+0PqKQ3PSkhEg==" }, "safe-buffer": { "version": "5.1.2", @@ -12559,6 +13336,7 @@ "resolved": "https://registry.npmjs.org/sass-graph/-/sass-graph-2.2.4.tgz", "integrity": "sha1-E/vWPNHK8JCLn9k0dq1DpR0eC0k=", "dev": true, + "optional": true, "requires": { "glob": "^7.0.0", "lodash": "^4.0.0", @@ -12570,13 +13348,15 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-3.0.0.tgz", "integrity": "sha1-MvxLn82vhF/N9+c7uXysImHwqwo=", - "dev": true + "dev": true, + "optional": true }, "cliui": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/cliui/-/cliui-3.2.0.tgz", "integrity": "sha1-EgYBU3qRbSmUD5NNo7SNWFo5IT0=", "dev": true, + "optional": true, "requires": { "string-width": "^1.0.1", "strip-ansi": "^3.0.1", @@ -12587,13 +13367,15 @@ "version": "3.2.1", "resolved": "https://registry.npmjs.org/y18n/-/y18n-3.2.1.tgz", "integrity": "sha1-bRX7qITAhnnA136I53WegR4H+kE=", - "dev": true + "dev": true, + "optional": true }, "yargs": { "version": "7.1.0", "resolved": "https://registry.npmjs.org/yargs/-/yargs-7.1.0.tgz", "integrity": "sha1-a6MY6xaWFyf10oT46gA+jWFU0Mg=", "dev": true, + "optional": true, "requires": { "camelcase": "^3.0.0", "cliui": "^3.2.0", @@ -12613,9 +13395,9 @@ } }, "sass-loader": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/sass-loader/-/sass-loader-7.0.1.tgz", - "integrity": "sha512-MeVVJFejJELlAbA7jrRchi88PGP6U9yIfqyiG+bBC4a9s2PX+ulJB9h8bbEohtPBfZmlLhNZ0opQM9hovRXvlw==", + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/sass-loader/-/sass-loader-7.0.3.tgz", + "integrity": "sha512-iaSFtQcGo4SSgDw5Aes5p4VTrA5jCGSA7sGmhPIcOloBlgI1VktM2MUrk2IHHjbNagckXlPz+HWq1vAAPrcYxA==", "dev": true, "requires": { "clone-deep": "^2.0.1", @@ -12626,12 +13408,12 @@ } }, "saucelabs": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/saucelabs/-/saucelabs-1.3.0.tgz", - "integrity": "sha1-0kDoAJ33+ocwbsRXimm6O1xCT+4=", + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/saucelabs/-/saucelabs-1.5.0.tgz", + "integrity": "sha512-jlX3FGdWvYf4Q3LFfFWS1QvPg3IGCGWxIc8QBFdPTbpTJnt/v17FHXYVAn7C8sHf1yUXo2c7yIM0isDryfYtHQ==", "dev": true, "requires": { - "https-proxy-agent": "^1.0.0" + "https-proxy-agent": "^2.2.1" } }, "sax": { @@ -12655,6 +13437,7 @@ "resolved": "https://registry.npmjs.org/scss-tokenizer/-/scss-tokenizer-0.2.3.tgz", "integrity": "sha1-jrBtualyMzOCTT9VMGQRSYR85dE=", "dev": true, + "optional": true, "requires": { "js-base64": "^2.1.8", "source-map": "^0.4.2" @@ -12665,6 +13448,7 @@ "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.4.4.tgz", "integrity": "sha1-66T12pwNyZneaAMti092FzZSA2s=", "dev": true, + "optional": true, "requires": { "amdefine": ">=0.0.4" } @@ -13225,12 +14009,12 @@ "dev": true }, "source-map-resolve": { - "version": "0.5.1", - "resolved": "https://registry.npmjs.org/source-map-resolve/-/source-map-resolve-0.5.1.tgz", - "integrity": "sha512-0KW2wvzfxm8NCTb30z0LMNyPqWCdDGE2viwzUaucqJdkTRXtZiSY3I+2A6nVAjmdOy0I4gU8DwnVVGsk9jvP2A==", + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/source-map-resolve/-/source-map-resolve-0.5.2.tgz", + "integrity": "sha512-MjqsvNwyz1s0k81Goz/9vRBe9SZdB09Bdw+/zYyO+3CuPk6fouTaxscHkgtE8jKvf01kVfl8riHzERQ/kefaSA==", "dev": true, "requires": { - "atob": "^2.0.0", + "atob": "^2.1.1", "decode-uri-component": "^0.2.0", "resolve-url": "^0.2.1", "source-map-url": "^0.4.0", @@ -13403,6 +14187,7 @@ "resolved": "https://registry.npmjs.org/stdout-stream/-/stdout-stream-1.4.0.tgz", "integrity": "sha1-osfIWH5U2UJ+qe2zrD8s1SLfN4s=", "dev": true, + "optional": true, "requires": { "readable-stream": "^2.0.1" } @@ -13428,14 +14213,14 @@ } }, "stream-http": { - "version": "2.8.1", - "resolved": "https://registry.npmjs.org/stream-http/-/stream-http-2.8.1.tgz", - "integrity": "sha512-cQ0jo17BLca2r0GfRdZKYAGLU6JRoIWxqSOakUMuKOT6MOK7AAlE856L33QuDmAy/eeOrhLee3dZKX0Uadu93A==", + "version": "2.8.3", + "resolved": "https://registry.npmjs.org/stream-http/-/stream-http-2.8.3.tgz", + "integrity": "sha512-+TSkfINHDo4J+ZobQLWiMouQYB+UVYFttRA94FpEzzJ7ZdqcL4uUUQ7WkdkI4DSozGmgBUE/a47L+38PenXhUw==", "dev": true, "requires": { "builtin-status-codes": "^3.0.0", "inherits": "^2.0.1", - "readable-stream": "^2.3.3", + "readable-stream": "^2.3.6", "to-arraybuffer": "^1.0.0", "xtend": "^4.0.0" } @@ -13591,6 +14376,7 @@ "resolved": "https://registry.npmjs.org/tar/-/tar-2.2.1.tgz", "integrity": "sha1-jk0qJWwOIYXGsYrWlK7JaLg8sdE=", "dev": true, + "optional": true, "requires": { "block-stream": "*", "fstream": "^1.0.2", @@ -13754,6 +14540,7 @@ "resolved": "https://registry.npmjs.org/true-case-path/-/true-case-path-1.0.2.tgz", "integrity": "sha1-fskRMJJHZsf1c74wIMNPj9/QDWI=", "dev": true, + "optional": true, "requires": { "glob": "^6.0.4" }, @@ -13763,6 +14550,7 @@ "resolved": "https://registry.npmjs.org/glob/-/glob-6.0.4.tgz", "integrity": "sha1-DwiGD2oVUSey+t1PnOJLGqtuTSI=", "dev": true, + "optional": true, "requires": { "inflight": "^1.0.4", "inherits": "2", @@ -13815,9 +14603,9 @@ } }, "tsickle": { - "version": "0.27.5", - "resolved": "https://registry.npmjs.org/tsickle/-/tsickle-0.27.5.tgz", - "integrity": "sha512-NP+CjM1EXza/M8mOXBLH3vkFEJiu1zfEAlC5WdJxHPn8l96QPz5eooP6uAgYtw1CcKfuSyIiheNUdKxtDWCNeg==", + "version": "0.29.0", + "resolved": "https://registry.npmjs.org/tsickle/-/tsickle-0.29.0.tgz", + "integrity": "sha512-JpID0Lv8/irRtPmqJJxb5fCwfZhjZeKmav9Zna7UjqVuJoSbI49Wue/c2PPybX1SbRrjl7bbI/JsCl0dSUJygA==", "dev": true, "requires": { "minimist": "^1.2.0", @@ -13941,9 +14729,9 @@ "dev": true }, "uglify-js": { - "version": "3.3.24", - "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.3.24.tgz", - "integrity": "sha512-hS7+TDiqIqvWScCcKRybCQzmMnEzJ4ryl9ErRmW4GFyG48p0/dKZiy/5mVLbsFzU8CCnCgQdxMiJzZythvLzCg==", + "version": "3.3.28", + "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.3.28.tgz", + "integrity": "sha512-68Rc/aA6cswiaQ5SrE979UJcXX+ADA1z33/ZsPd+fbAiVdjZ16OXdbtGO+rJUUBgK6qdf3SOPhQf3K/ybF5Miw==", "dev": true, "requires": { "commander": "~2.15.0", @@ -14111,9 +14899,9 @@ } }, "upath": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/upath/-/upath-1.0.5.tgz", - "integrity": "sha512-qbKn90aDQ0YEwvXoLqj0oiuUYroLX2lVHZ+b+xwjozFasAOC4GneDq5+OaIG5Zj+jFmbz/uO+f7a9qxjktJQww==", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/upath/-/upath-1.1.0.tgz", + "integrity": "sha512-bzpH/oBhoS/QI/YtbkqCg6VEiPYjSZtrHQM6/QnJS6OL9pKUFLqb3aFh4Scvwm45+7iAgiMkLhSbaZxUqmrprw==", "dev": true }, "upper-case": { @@ -14181,21 +14969,13 @@ } }, "url-parse": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.4.0.tgz", - "integrity": "sha512-ERuGxDiQ6Xw/agN4tuoCRbmwRuZP0cJ1lJxJubXr5Q/5cDa78+Dc4wfvtxzhzhkm5VvmW6Mf8EVj9SPGN4l8Lg==", + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.4.1.tgz", + "integrity": "sha512-x95Td74QcvICAA0+qERaVkRpTGKyBHHYdwL2LXZm5t/gBtCB9KQSO/0zQgSTYEV1p0WcvSg79TLNPSvd5IDJMQ==", "dev": true, "requires": { "querystringify": "^2.0.0", "requires-port": "^1.0.0" - }, - "dependencies": { - "querystringify": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/querystringify/-/querystringify-2.0.0.tgz", - "integrity": "sha512-eTPo5t/4bgaMNZxyjWx6N2a6AuE0mq51KWvpc7nU/MAqixcI6v6KrGUKES0HaomdnolQBBXU/++X6/QQ9KL4tw==", - "dev": true - } } }, "use": { @@ -14218,20 +14998,12 @@ } }, "util": { - "version": "0.10.3", - "resolved": "https://registry.npmjs.org/util/-/util-0.10.3.tgz", - "integrity": "sha1-evsa/lCAUkZInj23/g7TeTNqwPk=", + "version": "0.10.4", + "resolved": "https://registry.npmjs.org/util/-/util-0.10.4.tgz", + "integrity": "sha512-0Pm9hTQ3se5ll1XihRic3FDIku70C+iHUdT/W926rSgHV5QgXsYbKZN8MSC3tJtSkhuROzvsQjAaFENRXr+19A==", "dev": true, "requires": { - "inherits": "2.0.1" - }, - "dependencies": { - "inherits": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.1.tgz", - "integrity": "sha1-sX0I0ya0Qj5Wjv9xn5GwscvfafE=", - "dev": true - } + "inherits": "2.0.3" } }, "util-deprecate": { @@ -14344,6 +15116,19 @@ "resolved": "https://registry.npmjs.org/web-animations-js/-/web-animations-js-2.3.1.tgz", "integrity": "sha1-Om2bwVGWN3qQ+OKAP6UmIWWwRRA=" }, + "webassemblyjs": { + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/webassemblyjs/-/webassemblyjs-1.4.3.tgz", + "integrity": "sha512-4lOV1Lv6olz0PJkDGQEp82HempAn147e6BXijWDzz9g7/2nSebVP9GVg62Fz5ZAs55mxq13GA0XLyvY8XkyDjg==", + "dev": true, + "requires": { + "@webassemblyjs/ast": "1.4.3", + "@webassemblyjs/validation": "1.4.3", + "@webassemblyjs/wasm-parser": "1.4.3", + "@webassemblyjs/wast-parser": "1.4.3", + "long": "^3.2.0" + } + }, "webdriver-js-extender": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/webdriver-js-extender/-/webdriver-js-extender-1.0.0.tgz", @@ -14392,11 +15177,14 @@ } }, "webpack": { - "version": "4.6.0", - "resolved": "https://registry.npmjs.org/webpack/-/webpack-4.6.0.tgz", - "integrity": "sha512-Fu/k/3fZeGtIhuFkiYpIy1UDHhMiGKjG4FFPVuvG+5Os2lWA1ttWpmi9Qnn6AgfZqj9MvhZW/rmj/ip+nHr06g==", + "version": "4.8.3", + "resolved": "https://registry.npmjs.org/webpack/-/webpack-4.8.3.tgz", + "integrity": "sha512-/hfAjBISycdK597lxONjKEFX7dSIU1PsYwC3XlXUXoykWBlv9QV5HnO+ql3HvrrgfBJ7WXdnjO9iGPR2aAc5sw==", "dev": true, "requires": { + "@webassemblyjs/ast": "1.4.3", + "@webassemblyjs/wasm-edit": "1.4.3", + "@webassemblyjs/wasm-parser": "1.4.3", "acorn": "^5.0.0", "acorn-dynamic-import": "^3.0.0", "ajv": "^6.1.0", @@ -14419,9 +15207,9 @@ } }, "webpack-bundle-analyzer": { - "version": "2.11.1", - "resolved": "https://registry.npmjs.org/webpack-bundle-analyzer/-/webpack-bundle-analyzer-2.11.1.tgz", - "integrity": "sha512-VKUVkVMc6TWVXmF1OxsBXoiRjYiDRA4XT0KqtbLMDK+891VX7FCuklYwzldND8J2upUcHHnuXYNTP+4mSFi4Kg==", + "version": "2.13.1", + "resolved": "https://registry.npmjs.org/webpack-bundle-analyzer/-/webpack-bundle-analyzer-2.13.1.tgz", + "integrity": "sha512-rwxyfecTAxoarCC9VlHlIpfQCmmJ/qWD5bpbjkof+7HrNhTNZIwZITxN6CdlYL2axGmwNUQ+tFgcSOiNXMf/sQ==", "dev": true, "requires": { "acorn": "^5.3.0", @@ -14754,15 +15542,16 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/which-module/-/which-module-1.0.0.tgz", "integrity": "sha1-u6Y8qGGUiZT/MHc2CJ47lgJsKk8=", - "dev": true + "dev": true, + "optional": true }, "wide-align": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.2.tgz", - "integrity": "sha512-ijDLlyQ7s6x1JgCLur53osjm/UXUYD9+0PbYKrBsYisYXzCxN+HC3mYDNy/dWdmf3AwqwU3CXwDCvsNgGK1S0w==", + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.3.tgz", + "integrity": "sha512-QGkOQc8XL6Bt5PwnsExKBPuMKBxnGxWWW3fU55Xt4feHozMUhdUMaBCk290qpm/wG5u/RSKzwdAC4i51YigihA==", "dev": true, "requires": { - "string-width": "^1.0.2" + "string-width": "^1.0.2 || 2" } }, "window-size": { @@ -14894,6 +15683,7 @@ "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-5.0.0.tgz", "integrity": "sha1-J17PDX/+Bcd+ZOfIbkzZS/DhIoo=", "dev": true, + "optional": true, "requires": { "camelcase": "^3.0.0" }, @@ -14902,7 +15692,8 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-3.0.0.tgz", "integrity": "sha1-MvxLn82vhF/N9+c7uXysImHwqwo=", - "dev": true + "dev": true, + "optional": true } } }, diff --git a/package.json b/package.json index a2eb8442..db81e5da 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "fuse", - "version": "6.0.1", + "version": "6.1.0", "license": "https://themeforest.net/licenses/terms/regular", "scripts": { "ng": "ng", @@ -18,71 +18,71 @@ }, "private": true, "dependencies": { - "@agm/core": "1.0.0-beta.2", - "@angular/animations": "6.0.0", - "@angular/cdk": "6.0.1", - "@angular/common": "6.0.0", - "@angular/compiler": "6.0.0", - "@angular/core": "6.0.0", - "@angular/flex-layout": "6.0.0-beta.15", - "@angular/forms": "6.0.0", - "@angular/http": "6.0.0", - "@angular/material": "6.0.1", - "@angular/material-moment-adapter": "6.0.1", - "@angular/platform-browser": "6.0.0", - "@angular/platform-browser-dynamic": "6.0.0", - "@angular/router": "6.0.0", - "@ngrx/effects": "6.0.0-beta.1", - "@ngrx/router-store": "6.0.0-beta.1", - "@ngrx/store": "6.0.0-beta.1", - "@ngrx/store-devtools": "6.0.0-beta.1", - "@ngx-translate/core": "10.0.1", - "@swimlane/ngx-charts": "8.0.0", - "@swimlane/ngx-datatable": "12.0.0", + "@agm/core": "1.0.0-beta.3", + "@angular/animations": "6.0.5", + "@angular/cdk": "6.2.1", + "@angular/common": "6.0.5", + "@angular/compiler": "6.0.5", + "@angular/core": "6.0.5", + "@angular/flex-layout": "6.0.0-beta.16", + "@angular/forms": "6.0.5", + "@angular/http": "6.0.5", + "@angular/material": "6.2.1", + "@angular/material-moment-adapter": "6.2.1", + "@angular/platform-browser": "6.0.5", + "@angular/platform-browser-dynamic": "6.0.5", + "@angular/router": "6.0.5", + "@ngrx/effects": "6.0.1", + "@ngrx/router-store": "6.0.1", + "@ngrx/store": "6.0.1", + "@ngrx/store-devtools": "6.0.1", + "@ngx-translate/core": "10.0.2", + "@swimlane/ngx-charts": "8.1.0", + "@swimlane/ngx-datatable": "13.0.1", "@swimlane/ngx-dnd": "4.0.0", "@types/prismjs": "1.9.0", - "angular-calendar": "0.24.0", + "angular-calendar": "0.25.2", "angular-in-memory-web-api": "0.6.0", "chart.js": "2.7.2", "classlist.js": "1.1.20150312", - "core-js": "2.5.6", - "d3": "5.2.0", + "core-js": "2.5.7", + "d3": "5.4.0", "hammerjs": "2.0.8", "lodash": "4.17.10", - "moment": "2.22.1", + "moment": "2.22.2", "ng2-charts": "1.6.0", - "ngrx-store-freeze": "0.2.2", - "ngx-color-picker": "6.0.0", + "ngrx-store-freeze": "0.2.4", + "ngx-color-picker": "6.3.3", "ngx-cookie-service": "1.0.10", - "perfect-scrollbar": "1.3.0", + "perfect-scrollbar": "1.4.0", "prismjs": "1.14.0", - "rxjs": "6.1.0", - "rxjs-compat": "6.1.0", + "rxjs": "6.2.1", + "rxjs-compat": "6.2.1", "web-animations-js": "2.3.1", "zone.js": "0.8.26" }, "devDependencies": { - "@angular/cli": "6.0.0", - "@angular/compiler-cli": "6.0.0", - "@angular/language-service": "6.0.0", - "@angular-devkit/build-angular": "0.6.0", + "@angular/cli": "6.0.8", + "@angular/compiler-cli": "6.0.5", + "@angular/language-service": "6.0.5", + "@angular-devkit/build-angular": "0.6.8", "@angularclass/hmr": "2.1.3", - "@types/jasmine": "2.8.7", + "@types/jasmine": "2.8.8", "@types/jasminewd2": "2.0.3", - "@types/lodash": "4.14.108", + "@types/lodash": "4.14.109", "@types/node": "8.9.5", "codelyzer": "4.2.1", "jasmine-core": "2.99.1", "jasmine-spec-reporter": "4.2.1", "karma": "1.7.1", "karma-chrome-launcher": "2.2.0", - "karma-coverage-istanbul-reporter": "1.4.2", + "karma-coverage-istanbul-reporter": "2.0.1", "karma-jasmine": "1.1.2", "karma-jasmine-html-reporter": "0.2.2", - "protractor": "5.3.1", + "protractor": "5.3.2", "ts-node": "5.0.1", "tslint": "5.9.1", "typescript": "2.7.2", - "webpack-bundle-analyzer": "2.11.1" + "webpack-bundle-analyzer": "2.13.1" } } diff --git a/src/@fuse/animations/index.ts b/src/@fuse/animations/index.ts index 283c92f3..a33c80aa 100644 --- a/src/@fuse/animations/index.ts +++ b/src/@fuse/animations/index.ts @@ -187,10 +187,14 @@ export const fuseAnimations = [ transition('* => void', animate('300ms ease-in')) ]), + // ----------------------------------------------------------------------------------------------------- + // @ Router animations + // ----------------------------------------------------------------------------------------------------- + trigger('routerTransitionLeft', [ transition('* => *', [ - query('fuse-content > :enter, fuse-content > :leave', [ + query('content > :enter, content > :leave', [ style({ position: 'absolute', top : 0, @@ -199,7 +203,7 @@ export const fuseAnimations = [ right : 0 }) ], {optional: true}), - query('fuse-content > :enter', [ + query('content > :enter', [ style({ transform: 'translateX(100%)', opacity : 0 @@ -207,7 +211,7 @@ export const fuseAnimations = [ ], {optional: true}), sequence([ group([ - query('fuse-content > :leave', [ + query('content > :leave', [ style({ transform: 'translateX(0)', opacity : 1 @@ -218,7 +222,7 @@ export const fuseAnimations = [ opacity : 0 })) ], {optional: true}), - query('fuse-content > :enter', [ + query('content > :enter', [ style({transform: 'translateX(100%)'}), animate('600ms cubic-bezier(0.0, 0.0, 0.2, 1)', style({ @@ -227,8 +231,8 @@ export const fuseAnimations = [ })) ], {optional: true}) ]), - query('fuse-content > :leave', animateChild(), {optional: true}), - query('fuse-content > :enter', animateChild(), {optional: true}) + query('content > :leave', animateChild(), {optional: true}), + query('content > :enter', animateChild(), {optional: true}) ]) ]) ]), @@ -236,7 +240,7 @@ export const fuseAnimations = [ trigger('routerTransitionRight', [ transition('* => *', [ - query('fuse-content > :enter, fuse-content > :leave', [ + query('content > :enter, content > :leave', [ style({ position: 'absolute', top : 0, @@ -245,7 +249,7 @@ export const fuseAnimations = [ right : 0 }) ], {optional: true}), - query('fuse-content > :enter', [ + query('content > :enter', [ style({ transform: 'translateX(-100%)', opacity : 0 @@ -253,7 +257,7 @@ export const fuseAnimations = [ ], {optional: true}), sequence([ group([ - query('fuse-content > :leave', [ + query('content > :leave', [ style({ transform: 'translateX(0)', opacity : 1 @@ -264,7 +268,7 @@ export const fuseAnimations = [ opacity : 0 })) ], {optional: true}), - query('fuse-content > :enter', [ + query('content > :enter', [ style({transform: 'translateX(-100%)'}), animate('600ms cubic-bezier(0.0, 0.0, 0.2, 1)', style({ @@ -273,8 +277,8 @@ export const fuseAnimations = [ })) ], {optional: true}) ]), - query('fuse-content > :leave', animateChild(), {optional: true}), - query('fuse-content > :enter', animateChild(), {optional: true}) + query('content > :leave', animateChild(), {optional: true}), + query('content > :enter', animateChild(), {optional: true}) ]) ]) ]), @@ -282,7 +286,7 @@ export const fuseAnimations = [ trigger('routerTransitionUp', [ transition('* => *', [ - query('fuse-content > :enter, fuse-content > :leave', [ + query('content > :enter, content > :leave', [ style({ position: 'absolute', top : 0, @@ -291,14 +295,14 @@ export const fuseAnimations = [ right : 0 }) ], {optional: true}), - query('fuse-content > :enter', [ + query('content > :enter', [ style({ transform: 'translateY(100%)', opacity : 0 }) ], {optional: true}), group([ - query('fuse-content > :leave', [ + query('content > :leave', [ style({ transform: 'translateY(0)', opacity : 1 @@ -309,7 +313,7 @@ export const fuseAnimations = [ opacity : 0 })) ], {optional: true}), - query('fuse-content > :enter', [ + query('content > :enter', [ style({transform: 'translateY(100%)'}), animate('600ms cubic-bezier(0.0, 0.0, 0.2, 1)', style({ @@ -318,15 +322,15 @@ export const fuseAnimations = [ })) ], {optional: true}) ]), - query('fuse-content > :leave', animateChild(), {optional: true}), - query('fuse-content > :enter', animateChild(), {optional: true}) + query('content > :leave', animateChild(), {optional: true}), + query('content > :enter', animateChild(), {optional: true}) ]) ]), trigger('routerTransitionDown', [ transition('* => *', [ - query('fuse-content > :enter, fuse-content > :leave', [ + query('content > :enter, content > :leave', [ style({ position: 'absolute', top : 0, @@ -335,7 +339,7 @@ export const fuseAnimations = [ right : 0 }) ], {optional: true}), - query('fuse-content > :enter', [ + query('content > :enter', [ style({ transform: 'translateY(-100%)', opacity : 0 @@ -343,7 +347,7 @@ export const fuseAnimations = [ ], {optional: true}), sequence([ group([ - query('fuse-content > :leave', [ + query('content > :leave', [ style({ transform: 'translateY(0)', opacity : 1 @@ -354,7 +358,7 @@ export const fuseAnimations = [ opacity : 0 })) ], {optional: true}), - query('fuse-content > :enter', [ + query('content > :enter', [ style({transform: 'translateY(-100%)'}), animate('600ms cubic-bezier(0.0, 0.0, 0.2, 1)', style({ @@ -363,8 +367,8 @@ export const fuseAnimations = [ })) ], {optional: true}) ]), - query('fuse-content > :leave', animateChild(), {optional: true}), - query('fuse-content > :enter', animateChild(), {optional: true}) + query('content > :leave', animateChild(), {optional: true}), + query('content > :enter', animateChild(), {optional: true}) ]) ]) ]), @@ -373,7 +377,7 @@ export const fuseAnimations = [ transition('* => *', group([ - query('fuse-content > :enter, fuse-content > :leave ', [ + query('content > :enter, content > :leave ', [ style({ position: 'absolute', top : 0, @@ -383,12 +387,12 @@ export const fuseAnimations = [ }) ], {optional: true}), - query('fuse-content > :enter', [ + query('content > :enter', [ style({ opacity: 0 }) ], {optional: true}), - query('fuse-content > :leave', [ + query('content > :leave', [ style({ opacity: 1 }), @@ -397,7 +401,7 @@ export const fuseAnimations = [ opacity: 0 })) ], {optional: true}), - query('fuse-content > :enter', [ + query('content > :enter', [ style({ opacity: 0 }), @@ -406,8 +410,8 @@ export const fuseAnimations = [ opacity: 1 })) ], {optional: true}), - query('fuse-content > :enter', animateChild(), {optional: true}), - query('fuse-content > :leave', animateChild(), {optional: true}) + query('content > :enter', animateChild(), {optional: true}), + query('content > :leave', animateChild(), {optional: true}) ])) ]) ]; diff --git a/src/@fuse/components/confirm-dialog/confirm-dialog.component.ts b/src/@fuse/components/confirm-dialog/confirm-dialog.component.ts index 90eac6e5..0730cb1e 100644 --- a/src/@fuse/components/confirm-dialog/confirm-dialog.component.ts +++ b/src/@fuse/components/confirm-dialog/confirm-dialog.component.ts @@ -10,7 +10,14 @@ export class FuseConfirmDialogComponent { public confirmMessage: string; - constructor(public dialogRef: MatDialogRef) + /** + * Constructor + * + * @param {MatDialogRef} dialogRef + */ + constructor( + public dialogRef: MatDialogRef + ) { } diff --git a/src/@fuse/components/countdown/countdown.component.ts b/src/@fuse/components/countdown/countdown.component.ts index b00ad897..b519f64a 100644 --- a/src/@fuse/components/countdown/countdown.component.ts +++ b/src/@fuse/components/countdown/countdown.component.ts @@ -1,8 +1,6 @@ -import { Component, Input, OnInit } from '@angular/core'; - -import { interval } from 'rxjs'; -import { map } from 'rxjs/operators'; - +import { Component, Input, OnDestroy, OnInit } from '@angular/core'; +import { interval, Subject } from 'rxjs'; +import { map, takeUntil } from 'rxjs/operators'; import * as moment from 'moment'; @Component({ @@ -10,46 +8,82 @@ import * as moment from 'moment'; templateUrl: './countdown.component.html', styleUrls : ['./countdown.component.scss'] }) -export class FuseCountdownComponent implements OnInit +export class FuseCountdownComponent implements OnInit, OnDestroy { - @Input('eventDate') eventDate; + // Event date + @Input('eventDate') + eventDate; + countdown: any; + // Private + private _unsubscribeAll: Subject; + + /** + * Constructor + */ constructor() { + // Set the defaults this.countdown = { days : '', hours : '', minutes: '', seconds: '' }; + + // Set the private defaults + this._unsubscribeAll = new Subject(); } - ngOnInit() + // ----------------------------------------------------------------------------------------------------- + // @ Lifecycle hooks + // ----------------------------------------------------------------------------------------------------- + + /** + * On init + */ + ngOnInit(): void { const currDate = moment(); const eventDate = moment(this.eventDate); + // Get the difference in between the current date and event date let diff = eventDate.diff(currDate, 'seconds'); - const countDown = interval(1000).pipe( - map(value => { - return diff = diff - 1; - }), - map(value => { - const timeLeft = moment.duration(value, 'seconds'); + // Create a subscribable interval + const countDown = interval(1000) + .pipe( + map(value => { + return diff = diff - 1; + }), + map(value => { + const timeLeft = moment.duration(value, 'seconds'); - return { - days : timeLeft.asDays().toFixed(0), - hours : timeLeft.hours(), - minutes: timeLeft.minutes(), - seconds: timeLeft.seconds() - }; - }) - ); + return { + days : timeLeft.asDays().toFixed(0), + hours : timeLeft.hours(), + minutes: timeLeft.minutes(), + seconds: timeLeft.seconds() + }; + }) + ); - countDown.subscribe(value => { - this.countdown = value; - }); + // Subscribe to the countdown interval + countDown + .pipe(takeUntil(this._unsubscribeAll)) + .subscribe(value => { + this.countdown = value; + }); + } + + /** + * On destroy + */ + ngOnDestroy(): void + { + // Unsubscribe from all subscriptions + this._unsubscribeAll.next(); + this._unsubscribeAll.complete(); } } diff --git a/src/@fuse/components/demo/demo-content/demo-content.component.ts b/src/@fuse/components/demo/demo-content/demo-content.component.ts index 1e697894..eca3708b 100644 --- a/src/@fuse/components/demo/demo-content/demo-content.component.ts +++ b/src/@fuse/components/demo/demo-content/demo-content.component.ts @@ -7,6 +7,9 @@ import { Component } from '@angular/core'; }) export class FuseDemoContentComponent { + /** + * Constructor + */ constructor() { } diff --git a/src/@fuse/components/demo/demo-sidenav/demo-sidenav.component.html b/src/@fuse/components/demo/demo-sidebar/demo-sidebar.component.html similarity index 66% rename from src/@fuse/components/demo/demo-sidenav/demo-sidenav.component.html rename to src/@fuse/components/demo/demo-sidebar/demo-sidebar.component.html index 9c1b47a4..f79ee108 100644 --- a/src/@fuse/components/demo/demo-sidenav/demo-sidenav.component.html +++ b/src/@fuse/components/demo/demo-sidebar/demo-sidebar.component.html @@ -1,99 +1,99 @@ -
+
-

Sidenav Demo

+

Sidebar Demo

- Sidenav Item 1 + Sidebar Item 1 - Sidenav Item 2 + Sidebar Item 2 - Sidenav Item 3 + Sidebar Item 3 - Sidenav Item 4 + Sidebar Item 4 - Sidenav Item 5 + Sidebar Item 5 - Sidenav Item 6 + Sidebar Item 6 - Sidenav Item 7 + Sidebar Item 7 - Sidenav Item 8 + Sidebar Item 8 - Sidenav Item 9 + Sidebar Item 9 - Sidenav Item 10 + Sidebar Item 10 - Sidenav Item 11 + Sidebar Item 11 - Sidenav Item 12 + Sidebar Item 12 - Sidenav Item 13 + Sidebar Item 13 - Sidenav Item 14 + Sidebar Item 14 - Sidenav Item 15 + Sidebar Item 15 - Sidenav Item 16 + Sidebar Item 16
diff --git a/src/@fuse/components/demo/demo-sidenav/demo-sidenav.component.scss b/src/@fuse/components/demo/demo-sidebar/demo-sidebar.component.scss similarity index 100% rename from src/@fuse/components/demo/demo-sidenav/demo-sidenav.component.scss rename to src/@fuse/components/demo/demo-sidebar/demo-sidebar.component.scss diff --git a/src/@fuse/components/demo/demo-sidebar/demo-sidebar.component.ts b/src/@fuse/components/demo/demo-sidebar/demo-sidebar.component.ts new file mode 100644 index 00000000..4bd2650e --- /dev/null +++ b/src/@fuse/components/demo/demo-sidebar/demo-sidebar.component.ts @@ -0,0 +1,16 @@ +import { Component } from '@angular/core'; + +@Component({ + selector : 'fuse-demo-sidebar', + templateUrl: './demo-sidebar.component.html', + styleUrls : ['./demo-sidebar.component.scss'] +}) +export class FuseDemoSidebarComponent +{ + /** + * Constructor + */ + constructor() + { + } +} diff --git a/src/@fuse/components/demo/demo-sidenav/demo-sidenav.component.ts b/src/@fuse/components/demo/demo-sidenav/demo-sidenav.component.ts deleted file mode 100644 index dde5b68f..00000000 --- a/src/@fuse/components/demo/demo-sidenav/demo-sidenav.component.ts +++ /dev/null @@ -1,13 +0,0 @@ -import { Component } from '@angular/core'; - -@Component({ - selector : 'fuse-demo-sidenav', - templateUrl: './demo-sidenav.component.html', - styleUrls : ['./demo-sidenav.component.scss'] -}) -export class FuseDemoSidenavComponent -{ - constructor() - { - } -} diff --git a/src/@fuse/components/demo/demo.module.ts b/src/@fuse/components/demo/demo.module.ts index ea5b615c..68aefeca 100644 --- a/src/@fuse/components/demo/demo.module.ts +++ b/src/@fuse/components/demo/demo.module.ts @@ -4,12 +4,12 @@ import { RouterModule } from '@angular/router'; import { MatDividerModule, MatListModule } from '@angular/material'; import { FuseDemoContentComponent } from './demo-content/demo-content.component'; -import { FuseDemoSidenavComponent } from './demo-sidenav/demo-sidenav.component'; +import { FuseDemoSidebarComponent } from './demo-sidebar/demo-sidebar.component'; @NgModule({ declarations: [ FuseDemoContentComponent, - FuseDemoSidenavComponent + FuseDemoSidebarComponent ], imports : [ RouterModule, @@ -19,7 +19,7 @@ import { FuseDemoSidenavComponent } from './demo-sidenav/demo-sidenav.component' ], exports : [ FuseDemoContentComponent, - FuseDemoSidenavComponent + FuseDemoSidebarComponent ] }) export class FuseDemoModule diff --git a/src/@fuse/components/highlight/highlight.component.scss b/src/@fuse/components/highlight/highlight.component.scss index 1844f192..b723a942 100644 --- a/src/@fuse/components/highlight/highlight.component.scss +++ b/src/@fuse/components/highlight/highlight.component.scss @@ -3,4 +3,5 @@ padding: 8px; background: #263238; cursor: text; + overflow: auto; } \ No newline at end of file diff --git a/src/@fuse/components/highlight/highlight.component.ts b/src/@fuse/components/highlight/highlight.component.ts index e58be26d..69f8d0da 100644 --- a/src/@fuse/components/highlight/highlight.component.ts +++ b/src/@fuse/components/highlight/highlight.component.ts @@ -1,28 +1,55 @@ -import { Component, ContentChild, ElementRef, Input, OnInit } from '@angular/core'; +import { Component, ContentChild, ElementRef, Input, OnDestroy, OnInit } from '@angular/core'; import { HttpClient } from '@angular/common/http'; - +import { Subject } from 'rxjs'; +import { takeUntil } from 'rxjs/operators'; import * as Prism from 'prismjs/prism'; -import './prism-languages'; +import '@fuse/components/highlight/prism-languages'; @Component({ selector : 'fuse-highlight', - template : ' ', + template : '', styleUrls: ['./highlight.component.scss'] }) -export class FuseHighlightComponent implements OnInit +export class FuseHighlightComponent implements OnInit, OnDestroy { - @ContentChild('source') source: ElementRef; - @Input('lang') lang: string; - @Input('path') path: string; + // Source + @ContentChild('source') + source: ElementRef; + // Lang + @Input('lang') + lang: string; + + // Path + @Input('path') + path: string; + + // Private + private _unsubscribeAll: Subject; + + /** + * Constructor + * + * @param {ElementRef} _elementRef + * @param {HttpClient} _httpClient + */ constructor( - private elementRef: ElementRef, - private http: HttpClient + private _elementRef: ElementRef, + private _httpClient: HttpClient ) { + // Set the private defaults + this._unsubscribeAll = new Subject(); } - ngOnInit() + // ----------------------------------------------------------------------------------------------------- + // @ Lifecycle hooks + // ----------------------------------------------------------------------------------------------------- + + /** + * On init + */ + ngOnInit(): void { // If there is no language defined, return... if ( !this.lang ) @@ -34,11 +61,13 @@ export class FuseHighlightComponent implements OnInit if ( this.path ) { // Get the source - this.http.get(this.path, {responseType: 'text'}).subscribe((response) => { + this._httpClient.get(this.path, {responseType: 'text'}) + .pipe(takeUntil(this._unsubscribeAll)) + .subscribe((response) => { - // Highlight it - this.highlight(response); - }); + // Highlight it + this.highlight(response); + }); } // If the path is not defined and the source element exists... @@ -49,7 +78,26 @@ export class FuseHighlightComponent implements OnInit } } - highlight(sourceCode) + /** + * On destroy + */ + ngOnDestroy(): void + { + // Unsubscribe from all subscriptions + this._unsubscribeAll.next(); + this._unsubscribeAll.complete(); + } + + // ----------------------------------------------------------------------------------------------------- + // @ Public methods + // ----------------------------------------------------------------------------------------------------- + + /** + * Highlight the given source code + * + * @param sourceCode + */ + highlight(sourceCode): void { // Split the source into lines const sourceLines = sourceCode.split('\n'); @@ -94,9 +142,8 @@ export class FuseHighlightComponent implements OnInit const highlightedCode = Prism.highlight(source, Prism.languages[this.lang]); // Replace the innerHTML of the component with the highlighted code - this.elementRef.nativeElement.innerHTML = + this._elementRef.nativeElement.innerHTML = '
' + highlightedCode + '
'; - } } diff --git a/src/@fuse/components/highlight/prism-languages.ts b/src/@fuse/components/highlight/prism-languages.ts index 96c4461e..3de74275 100644 --- a/src/@fuse/components/highlight/prism-languages.ts +++ b/src/@fuse/components/highlight/prism-languages.ts @@ -1,4 +1,5 @@ import 'prismjs/prism'; +import 'prismjs/components/prism-bash'; import 'prismjs/components/prism-c'; import 'prismjs/components/prism-cpp'; import 'prismjs/components/prism-csharp'; diff --git a/src/@fuse/components/material-color-picker/material-color-picker.component.ts b/src/@fuse/components/material-color-picker/material-color-picker.component.ts index 08671cdb..f914fa4e 100644 --- a/src/@fuse/components/material-color-picker/material-color-picker.component.ts +++ b/src/@fuse/components/material-color-picker/material-color-picker.component.ts @@ -13,22 +13,78 @@ import { MatColors } from '@fuse/mat-colors'; export class FuseMaterialColorPickerComponent implements OnChanges { colors: any; - selectedColor: any; hues: string[]; - view = 'palettes'; + selectedColor: any; + view: string; - @Input() selectedPalette = ''; - @Input() selectedHue = ''; - @Input() selectedFg = ''; - @Input() value: any; - @Output() onValueChange = new EventEmitter(); - @Output() selectedPaletteChange = new EventEmitter(); - @Output() selectedHueChange = new EventEmitter(); - @Output() selectedClassChange = new EventEmitter(); - @Output() selectedBgChange = new EventEmitter(); - @Output() selectedFgChange = new EventEmitter(); + @Input() + selectedPalette: string; - _selectedClass = ''; + @Input() + selectedHue: string; + + @Input() + selectedFg: string; + + @Input() + value: any; + + @Output() + onValueChange: EventEmitter; + + @Output() + selectedPaletteChange: EventEmitter; + + @Output() + selectedHueChange: EventEmitter; + + @Output() + selectedClassChange: EventEmitter; + + @Output() + selectedBgChange: EventEmitter; + + @Output() + selectedFgChange: EventEmitter; + + // Private + _selectedClass: string; + _selectedBg: string; + + /** + * Constructor + */ + constructor() + { + // Set the defaults + this.colors = MatColors.all; + this.hues = ['50', '100', '200', '300', '400', '500', '600', '700', '800', '900', 'A100', 'A200', 'A400', 'A700']; + this.selectedFg = ''; + this.selectedHue = ''; + this.selectedPalette = ''; + this.view = 'palettes'; + + this.onValueChange = new EventEmitter(); + this.selectedPaletteChange = new EventEmitter(); + this.selectedHueChange = new EventEmitter(); + this.selectedClassChange = new EventEmitter(); + this.selectedBgChange = new EventEmitter(); + this.selectedFgChange = new EventEmitter(); + + // Set the private defaults + this._selectedClass = ''; + this._selectedBg = ''; + } + + // ----------------------------------------------------------------------------------------------------- + // @ Accessors + // ----------------------------------------------------------------------------------------------------- + + /** + * Selected class + * + * @param value + */ @Input() set selectedClass(value) { @@ -54,7 +110,11 @@ export class FuseMaterialColorPickerComponent implements OnChanges return this._selectedClass; } - _selectedBg = ''; + /** + * Selected bg + * + * @param value + */ @Input() set selectedBg(value) { @@ -86,13 +146,16 @@ export class FuseMaterialColorPickerComponent implements OnChanges return this._selectedBg; } - constructor() - { - this.colors = MatColors.all; - this.hues = ['50', '100', '200', '300', '400', '500', '600', '700', '800', '900', 'A100', 'A200', 'A400', 'A700']; - } + // ----------------------------------------------------------------------------------------------------- + // @ Lifecycle hooks + // ----------------------------------------------------------------------------------------------------- - ngOnChanges(changes: any) + /** + * On changes + * + * @param changes + */ + ngOnChanges(changes: any): void { if ( changes.selectedBg && changes.selectedBg.currentValue === '' || changes.selectedClass && changes.selectedClass.currentValue === '' || @@ -106,21 +169,38 @@ export class FuseMaterialColorPickerComponent implements OnChanges this.updateSelectedColor(); } } - - selectPalette(palette) + + // ----------------------------------------------------------------------------------------------------- + // @ Public methods + // ----------------------------------------------------------------------------------------------------- + + /** + * Select palette + * + * @param palette + */ + selectPalette(palette): void { this.selectedPalette = palette; this.updateSelectedColor(); this.view = 'hues'; } - selectHue(hue) + /** + * Select hue + * + * @param hue + */ + selectHue(hue): void { this.selectedHue = hue; this.updateSelectedColor(); } - removeColor() + /** + * Remove color + */ + removeColor(): void { this.selectedPalette = ''; this.selectedHue = ''; @@ -128,7 +208,10 @@ export class FuseMaterialColorPickerComponent implements OnChanges this.view = 'palettes'; } - updateSelectedColor() + /** + * Update selected color + */ + updateSelectedColor(): void { setTimeout(() => { @@ -168,12 +251,18 @@ export class FuseMaterialColorPickerComponent implements OnChanges }); } - backToPaletteSelection() + /** + * Go back to palette selection + */ + backToPaletteSelection(): void { this.view = 'palettes'; } - onMenuOpen() + /** + * On menu open + */ + onMenuOpen(): void { if ( this.selectedPalette === '' ) { diff --git a/src/@fuse/components/material-color-picker/material-color-picker.module.ts b/src/@fuse/components/material-color-picker/material-color-picker.module.ts index 94db7875..6562e678 100644 --- a/src/@fuse/components/material-color-picker/material-color-picker.module.ts +++ b/src/@fuse/components/material-color-picker/material-color-picker.module.ts @@ -1,7 +1,6 @@ import { NgModule } from '@angular/core'; import { CommonModule } from '@angular/common'; import { FlexLayoutModule } from '@angular/flex-layout'; - import { MatButtonModule, MatIconModule, MatMenuModule, MatRippleModule } from '@angular/material'; import { FusePipesModule } from '@fuse/pipes/pipes.module'; diff --git a/src/@fuse/components/navigation/horizontal/nav-collapse/nav-horizontal-collapse.component.html b/src/@fuse/components/navigation/horizontal/collapsable/collapsable.component.html similarity index 78% rename from src/@fuse/components/navigation/horizontal/nav-collapse/nav-horizontal-collapse.component.html rename to src/@fuse/components/navigation/horizontal/collapsable/collapsable.component.html index da55085f..28a5e64b 100644 --- a/src/@fuse/components/navigation/horizontal/nav-collapse/nav-horizontal-collapse.component.html +++ b/src/@fuse/components/navigation/horizontal/collapsable/collapsable.component.html @@ -31,18 +31,19 @@ [ngStyle]="{'background-color': item.badge.bg,'color': item.badge.fg}"> {{item.badge.title}} - keyboard_arrow_right + keyboard_arrow_right
-
+
- - + +
diff --git a/src/@fuse/components/navigation/horizontal/nav-collapse/nav-horizontal-collapse.component.scss b/src/@fuse/components/navigation/horizontal/collapsable/collapsable.component.scss similarity index 100% rename from src/@fuse/components/navigation/horizontal/nav-collapse/nav-horizontal-collapse.component.scss rename to src/@fuse/components/navigation/horizontal/collapsable/collapsable.component.scss diff --git a/src/@fuse/components/navigation/horizontal/collapsable/collapsable.component.ts b/src/@fuse/components/navigation/horizontal/collapsable/collapsable.component.ts new file mode 100644 index 00000000..4b5cdb9a --- /dev/null +++ b/src/@fuse/components/navigation/horizontal/collapsable/collapsable.component.ts @@ -0,0 +1,86 @@ +import { Component, HostBinding, HostListener, Input, OnDestroy, OnInit } from '@angular/core'; +import { Subject } from 'rxjs'; +import { takeUntil } from 'rxjs/operators'; + +import { fuseAnimations } from '@fuse/animations'; +import { FuseConfigService } from '@fuse/services/config.service'; + +@Component({ + selector : 'fuse-nav-horizontal-collapsable', + templateUrl: './collapsable.component.html', + styleUrls : ['./collapsable.component.scss'], + animations : fuseAnimations +}) +export class FuseNavHorizontalCollapsableComponent implements OnInit, OnDestroy +{ + fuseConfig: any; + isOpen = false; + + @HostBinding('class') + classes = 'nav-collapsable nav-item'; + + @Input() + item: any; + + // Private + private _unsubscribeAll: Subject; + + constructor( + private _fuseConfigService: FuseConfigService + ) + { + // Set the private defaults + this._unsubscribeAll = new Subject(); + } + + // ----------------------------------------------------------------------------------------------------- + // @ Lifecycle hooks + // ----------------------------------------------------------------------------------------------------- + + /** + * On init + */ + ngOnInit(): void + { + // Subscribe to config changes + this._fuseConfigService.config + .pipe(takeUntil(this._unsubscribeAll)) + .subscribe( + (config) => { + this.fuseConfig = config; + } + ); + } + + /** + * On destroy + */ + ngOnDestroy(): void + { + // Unsubscribe from all subscriptions + this._unsubscribeAll.next(); + this._unsubscribeAll.complete(); + } + + // ----------------------------------------------------------------------------------------------------- + // @ Public methods + // ----------------------------------------------------------------------------------------------------- + + /** + * Open + */ + @HostListener('mouseenter') + open(): void + { + this.isOpen = true; + } + + /** + * Close + */ + @HostListener('mouseleave') + close(): void + { + this.isOpen = false; + } +} diff --git a/src/@fuse/components/navigation/horizontal/nav-item/nav-horizontal-item.component.html b/src/@fuse/components/navigation/horizontal/item/item.component.html similarity index 100% rename from src/@fuse/components/navigation/horizontal/nav-item/nav-horizontal-item.component.html rename to src/@fuse/components/navigation/horizontal/item/item.component.html diff --git a/src/@fuse/components/navigation/horizontal/nav-item/nav-horizontal-item.component.scss b/src/@fuse/components/navigation/horizontal/item/item.component.scss similarity index 100% rename from src/@fuse/components/navigation/horizontal/nav-item/nav-horizontal-item.component.scss rename to src/@fuse/components/navigation/horizontal/item/item.component.scss diff --git a/src/@fuse/components/navigation/horizontal/item/item.component.ts b/src/@fuse/components/navigation/horizontal/item/item.component.ts new file mode 100644 index 00000000..ade234a4 --- /dev/null +++ b/src/@fuse/components/navigation/horizontal/item/item.component.ts @@ -0,0 +1,23 @@ +import { Component, HostBinding, Input } from '@angular/core'; + +@Component({ + selector : 'fuse-nav-horizontal-item', + templateUrl: './item.component.html', + styleUrls : ['./item.component.scss'] +}) +export class FuseNavHorizontalItemComponent +{ + @HostBinding('class') + classes = 'nav-item'; + + @Input() + item: any; + + /** + * Constructor + */ + constructor() + { + + } +} diff --git a/src/@fuse/components/navigation/horizontal/nav-collapse/nav-horizontal-collapse.component.ts b/src/@fuse/components/navigation/horizontal/nav-collapse/nav-horizontal-collapse.component.ts deleted file mode 100644 index e24976bc..00000000 --- a/src/@fuse/components/navigation/horizontal/nav-collapse/nav-horizontal-collapse.component.ts +++ /dev/null @@ -1,51 +0,0 @@ -import { Component, HostBinding, HostListener, Input, OnDestroy } from '@angular/core'; -import { Subscription } from 'rxjs'; - -import { fuseAnimations } from '../../../../animations/index'; -import { FuseConfigService } from '../../../../services/config.service'; - -@Component({ - selector : 'fuse-nav-horizontal-collapse', - templateUrl: './nav-horizontal-collapse.component.html', - styleUrls : ['./nav-horizontal-collapse.component.scss'], - animations : fuseAnimations -}) -export class FuseNavHorizontalCollapseComponent implements OnDestroy -{ - onConfigChanged: Subscription; - fuseSettings: any; - isOpen = false; - - @HostBinding('class') classes = 'nav-item nav-collapse'; - @Input() item: any; - - @HostListener('mouseenter') - open() - { - this.isOpen = true; - } - - @HostListener('mouseleave') - close() - { - this.isOpen = false; - } - - constructor( - private fuseConfig: FuseConfigService - ) - { - this.onConfigChanged = - this.fuseConfig.onConfigChanged - .subscribe( - (newSettings) => { - this.fuseSettings = newSettings; - } - ); - } - - ngOnDestroy() - { - this.onConfigChanged.unsubscribe(); - } -} diff --git a/src/@fuse/components/navigation/horizontal/nav-item/nav-horizontal-item.component.ts b/src/@fuse/components/navigation/horizontal/nav-item/nav-horizontal-item.component.ts deleted file mode 100644 index 8f9d0b25..00000000 --- a/src/@fuse/components/navigation/horizontal/nav-item/nav-horizontal-item.component.ts +++ /dev/null @@ -1,12 +0,0 @@ -import { Component, HostBinding, Input } from '@angular/core'; - -@Component({ - selector : 'fuse-nav-horizontal-item', - templateUrl: './nav-horizontal-item.component.html', - styleUrls : ['./nav-horizontal-item.component.scss'] -}) -export class FuseNavHorizontalItemComponent -{ - @HostBinding('class') classes = 'nav-item'; - @Input() item: any; -} diff --git a/src/@fuse/components/navigation/navigation.component.html b/src/@fuse/components/navigation/navigation.component.html index 10ecaf89..79459998 100644 --- a/src/@fuse/components/navigation/navigation.component.html +++ b/src/@fuse/components/navigation/navigation.component.html @@ -7,7 +7,7 @@ - + @@ -20,8 +20,8 @@ - - + + diff --git a/src/@fuse/components/navigation/navigation.component.ts b/src/@fuse/components/navigation/navigation.component.ts index 9a2e5a5c..36f6b0f4 100644 --- a/src/@fuse/components/navigation/navigation.component.ts +++ b/src/@fuse/components/navigation/navigation.component.ts @@ -1,4 +1,8 @@ -import { Component, Input, ViewEncapsulation } from '@angular/core'; +import { Component, Input, OnInit, ViewEncapsulation } from '@angular/core'; +import { Subject } from 'rxjs'; +import { takeUntil } from 'rxjs/operators'; + +import { FuseNavigationService } from '@fuse/components/navigation/navigation.service'; @Component({ selector : 'fuse-navigation', @@ -6,13 +10,45 @@ import { Component, Input, ViewEncapsulation } from '@angular/core'; styleUrls : ['./navigation.component.scss'], encapsulation: ViewEncapsulation.None }) -export class FuseNavigationComponent +export class FuseNavigationComponent implements OnInit { - @Input() layout = 'vertical'; - @Input() navigation: any; + @Input() + layout = 'vertical'; - constructor() + @Input() + navigation: any; + + // Private + private _unsubscribeAll: Subject; + + /** + * Constructor + */ + constructor( + private _fuseNavigationService: FuseNavigationService + ) { + // Set the private defaults + this._unsubscribeAll = new Subject(); + } + // ----------------------------------------------------------------------------------------------------- + // @ Lifecycle hooks + // ----------------------------------------------------------------------------------------------------- + + /** + * On init + */ + ngOnInit(): void + { + // Load the navigation either from the input or from the service + this.navigation = this.navigation || this._fuseNavigationService.getCurrentNavigation(); + + // Subscribe to the current navigation changes + this._fuseNavigationService.onNavigationChanged + .pipe(takeUntil(this._unsubscribeAll)) + .subscribe(() => { + this.navigation = this._fuseNavigationService.getCurrentNavigation(); + }); } } diff --git a/src/@fuse/components/navigation/navigation.module.ts b/src/@fuse/components/navigation/navigation.module.ts index 12519314..577a1186 100644 --- a/src/@fuse/components/navigation/navigation.module.ts +++ b/src/@fuse/components/navigation/navigation.module.ts @@ -6,11 +6,11 @@ import { MatIconModule, MatRippleModule } from '@angular/material'; import { TranslateModule } from '@ngx-translate/core'; import { FuseNavigationComponent } from './navigation.component'; -import { FuseNavVerticalItemComponent } from './vertical/nav-item/nav-vertical-item.component'; -import { FuseNavVerticalCollapseComponent } from './vertical/nav-collapse/nav-vertical-collapse.component'; -import { FuseNavVerticalGroupComponent } from './vertical/nav-group/nav-vertical-group.component'; -import { FuseNavHorizontalItemComponent } from './horizontal/nav-item/nav-horizontal-item.component'; -import { FuseNavHorizontalCollapseComponent } from './horizontal/nav-collapse/nav-horizontal-collapse.component'; +import { FuseNavVerticalItemComponent } from './vertical/item/item.component'; +import { FuseNavVerticalCollapsableComponent } from './vertical/collapsable/collapsable.component'; +import { FuseNavVerticalGroupComponent } from './vertical/group/group.component'; +import { FuseNavHorizontalItemComponent } from './horizontal/item/item.component'; +import { FuseNavHorizontalCollapsableComponent } from './horizontal/collapsable/collapsable.component'; @NgModule({ imports : [ @@ -29,9 +29,9 @@ import { FuseNavHorizontalCollapseComponent } from './horizontal/nav-collapse/na FuseNavigationComponent, FuseNavVerticalGroupComponent, FuseNavVerticalItemComponent, - FuseNavVerticalCollapseComponent, + FuseNavVerticalCollapsableComponent, FuseNavHorizontalItemComponent, - FuseNavHorizontalCollapseComponent + FuseNavHorizontalCollapsableComponent ] }) export class FuseNavigationModule diff --git a/src/@fuse/components/navigation/navigation.service.ts b/src/@fuse/components/navigation/navigation.service.ts index cbf2e11e..49995acb 100644 --- a/src/@fuse/components/navigation/navigation.service.ts +++ b/src/@fuse/components/navigation/navigation.service.ts @@ -1,34 +1,161 @@ import { Injectable } from '@angular/core'; -import { Subject } from 'rxjs'; +import { BehaviorSubject, Observable, Subject } from 'rxjs'; @Injectable() export class FuseNavigationService { flatNavigation: any[] = []; - onItemCollapsed: Subject = new Subject; - onItemCollapseToggled: Subject = new Subject; + onItemCollapsed: Subject; + onItemCollapseToggled: Subject; + // Private + private _onNavigationChanged: BehaviorSubject; + private _onNavigationRegistered: BehaviorSubject; + private _onNavigationUnregistered: BehaviorSubject; + + private _currentNavigationKey: string; + private _registry: { [key: string]: any } = {}; + + /** + * Constructor + */ constructor() { + // Set the defaults + this.onItemCollapsed = new Subject(); + this.onItemCollapseToggled = new Subject(); + + // Set the private defaults + this._currentNavigationKey = null; + this._onNavigationChanged = new BehaviorSubject(null); + this._onNavigationRegistered = new BehaviorSubject(null); + this._onNavigationUnregistered = new BehaviorSubject(null); + } + + // ----------------------------------------------------------------------------------------------------- + // @ Accessors + // ----------------------------------------------------------------------------------------------------- + + /** + * Get onNavigationChanged + * + * @returns {Observable} + */ + get onNavigationChanged(): Observable + { + return this._onNavigationChanged.asObservable(); + } + + /** + * Get onNavigationRegistered + * + * @returns {Observable} + */ + get onNavigationRegistered(): Observable + { + return this._onNavigationRegistered.asObservable(); + } + + /** + * Get onNavigationUnregistered + * + * @returns {Observable} + */ + get onNavigationUnregistered(): Observable + { + return this._onNavigationUnregistered.asObservable(); + } + + // ----------------------------------------------------------------------------------------------------- + // @ Public methods + // ----------------------------------------------------------------------------------------------------- + + /** + * Register the given navigation + * with the given key + * + * @param key + * @param navigation + */ + register(key, navigation): void + { + // Check if the key already being used + if ( this._registry[key] ) + { + console.error(`The navigation with the key '${key}' already exists. Either unregister it first or use a unique key.`); + + return; + } + + // Add to the registry + this._registry[key] = navigation; + + // Notify the subject + this._onNavigationRegistered.next([key, navigation]); + } + + /** + * Unregister the navigation from the registry + * @param key + */ + unregister(key): void + { + // Check if the navigation exists + if ( !this._registry[key] ) + { + console.warn(`The navigation with the key '${key}' doesn't exist in the registry.`); + } + + // Unregister the sidebar + delete this._registry[key]; + + // Notify the subject + this._onNavigationUnregistered.next(key); + } + + /** + * Get navigation from registry by key + * + * @param key + * @returns {any} + */ + getNavigation(key): any + { + // Check if the navigation exists + if ( !this._registry[key] ) + { + console.warn(`The navigation with the key '${key}' doesn't exist in the registry.`); + + return; + } + + // Return the sidebar + return this._registry[key]; } /** * Get flattened navigation array + * * @param navigation * @returns {any[]} */ - getFlatNavigation(navigation) + getFlatNavigation(navigation): any { for ( const navItem of navigation ) { if ( navItem.type === 'item' ) { this.flatNavigation.push({ - title: navItem.title, - type : navItem.type, - icon : navItem.icon || false, - url : navItem.url + id : navItem.id || null, + title : navItem.title || null, + translate : navItem.translate || null, + type : navItem.type, + icon : navItem.icon || null, + url : navItem.url || null, + function : navItem.function || null, + exactMatch: navItem.exactMatch || false, + badge : navItem.badge || null }); continue; @@ -45,4 +172,186 @@ export class FuseNavigationService return this.flatNavigation; } + + /** + * Get the current navigation + * + * @returns {any} + */ + getCurrentNavigation(): any + { + if ( !this._currentNavigationKey ) + { + console.warn(`The current navigation is not set.`); + + return; + } + + return this.getNavigation(this._currentNavigationKey); + } + + /** + * Set the navigation with the key + * as the current navigation + * + * @param key + */ + setCurrentNavigation(key): void + { + // Check if the sidebar exists + if ( !this._registry[key] ) + { + console.warn(`The navigation with the key '${key}' doesn't exist in the registry.`); + + return; + } + + // Set the current navigation key + this._currentNavigationKey = key; + + // Notify the subject + this._onNavigationChanged.next(key); + } + + /** + * Get navigation item by id from the + * current navigation + * + * @param id + * @param {any} navigation + * @returns {any | boolean} + */ + getNavigationItem(id, navigation = null): any | boolean + { + if ( !navigation ) + { + navigation = this.getCurrentNavigation(); + } + + for ( const item of navigation ) + { + if ( item.id === id ) + { + return item; + } + + if ( item.children ) + { + const childItem = this.getNavigationItem(id, item.children); + + if ( childItem ) + { + return childItem; + } + } + } + + return false; + } + + /** + * Get the parent of the navigation item + * with the id + * + * @param id + * @param {any} navigation + * @param parent + */ + getNavigationItemParent(id, navigation = null, parent = null): any + { + if ( !navigation ) + { + navigation = this.getCurrentNavigation(); + parent = navigation; + } + + for ( const item of navigation ) + { + if ( item.id === id ) + { + return parent; + } + + if ( item.children ) + { + const childItem = this.getNavigationItemParent(id, item.children, item); + + if ( childItem ) + { + return childItem; + } + } + } + + return false; + } + + /** + * Add a navigation item to the specified location + * + * @param item + * @param id + */ + addNavigationItem(item, id): void + { + // Get the current navigation + const navigation: any[] = this.getCurrentNavigation(); + + // Add to the end of the navigation + if ( id === 'end' ) + { + navigation.push(item); + + return; + } + + // Add to the start of the navigation + if ( id === 'start' ) + { + navigation.unshift(item); + } + + // Add it to a specific location + const parent: any = this.getNavigationItem(id); + + if ( parent ) + { + // Check if parent has a children entry, + // and add it if it doesn't + if ( !parent.children ) + { + parent.children = []; + } + + // Add the item + parent.children.push(item); + } + } + + /** + * Remove navigation item with the given id + * + * @param id + */ + removeNavigationItem(id): void + { + const item = this.getNavigationItem(id); + + // Return, if there is not such an item + if ( !item ) + { + return; + } + + // Get the parent of the item + let parent = this.getNavigationItemParent(id); + + // This check is required because of the first level + // of the navigation, since the first level is not + // inside the 'children' array + parent = parent.children || parent; + + // Remove the item + parent.splice(parent.indexOf(item), 1); + } } diff --git a/src/@fuse/components/navigation/vertical/nav-collapse/nav-vertical-collapse.component.html b/src/@fuse/components/navigation/vertical/collapsable/collapsable.component.html similarity index 50% rename from src/@fuse/components/navigation/vertical/nav-collapse/nav-vertical-collapse.component.html rename to src/@fuse/components/navigation/vertical/collapsable/collapsable.component.html index ef09b5e9..bc4ddf44 100644 --- a/src/@fuse/components/navigation/vertical/nav-collapse/nav-vertical-collapse.component.html +++ b/src/@fuse/components/navigation/vertical/collapsable/collapsable.component.html @@ -6,24 +6,40 @@ - + + + + + + - + - + + + + + {{item.icon}} {{item.title}} @@ -31,13 +47,14 @@ [ngStyle]="{'background-color': item.badge.bg,'color': item.badge.fg}"> {{item.badge.title}} - keyboard_arrow_right + keyboard_arrow_right
- +
diff --git a/src/@fuse/components/navigation/vertical/nav-collapse/nav-vertical-collapse.component.scss b/src/@fuse/components/navigation/vertical/collapsable/collapsable.component.scss similarity index 87% rename from src/@fuse/components/navigation/vertical/nav-collapse/nav-vertical-collapse.component.scss rename to src/@fuse/components/navigation/vertical/collapsable/collapsable.component.scss index 6fa59f1f..17eb6a38 100644 --- a/src/@fuse/components/navigation/vertical/nav-collapse/nav-vertical-collapse.component.scss +++ b/src/@fuse/components/navigation/vertical/collapsable/collapsable.component.scss @@ -20,7 +20,7 @@ .nav-link { - .collapse-arrow { + .collapsable-arrow { transition: transform .3s ease-in-out, opacity .25s ease-in-out .1s; transform: rotate(0); } @@ -34,13 +34,9 @@ > .nav-link { - .collapse-arrow { + .collapsable-arrow { transform: rotate(90deg); } } - - > .children { - } - } } diff --git a/src/@fuse/components/navigation/vertical/nav-collapse/nav-vertical-collapse.component.ts b/src/@fuse/components/navigation/vertical/collapsable/collapsable.component.ts similarity index 50% rename from src/@fuse/components/navigation/vertical/nav-collapse/nav-vertical-collapse.component.ts rename to src/@fuse/components/navigation/vertical/collapsable/collapsable.component.ts index 65afb2c8..fbda7a18 100644 --- a/src/@fuse/components/navigation/vertical/nav-collapse/nav-vertical-collapse.component.ts +++ b/src/@fuse/components/navigation/vertical/collapsable/collapsable.component.ts @@ -1,46 +1,79 @@ -import { Component, HostBinding, Input, OnInit } from '@angular/core'; -import { FuseNavigationService } from '../../navigation.service'; +import { Component, HostBinding, Input, OnDestroy, OnInit } from '@angular/core'; import { NavigationEnd, Router } from '@angular/router'; -import { fuseAnimations } from '../../../../animations/index'; +import { Subject } from 'rxjs'; +import { filter, takeUntil } from 'rxjs/operators'; + +import { FuseNavigationItem } from '@fuse/types'; +import { fuseAnimations } from '@fuse/animations'; +import { FuseNavigationService } from '@fuse/components/navigation/navigation.service'; @Component({ - selector : 'fuse-nav-vertical-collapse', - templateUrl: './nav-vertical-collapse.component.html', - styleUrls : ['./nav-vertical-collapse.component.scss'], + selector : 'fuse-nav-vertical-collapsable', + templateUrl: './collapsable.component.html', + styleUrls : ['./collapsable.component.scss'], animations : fuseAnimations }) -export class FuseNavVerticalCollapseComponent implements OnInit +export class FuseNavVerticalCollapsableComponent implements OnInit, OnDestroy { - @Input() item: any; - @HostBinding('class') classes = 'nav-collapse nav-item'; - @HostBinding('class.open') public isOpen = false; + @Input() + item: FuseNavigationItem; + @HostBinding('class') + classes = 'nav-collapsable nav-item'; + + @HostBinding('class.open') + public isOpen = false; + + // Private + private _unsubscribeAll: Subject; + + /** + * Constructor + * + * @param {FuseNavigationService} _fuseNavigationService + * @param {Router} _router + */ constructor( - private navigationService: FuseNavigationService, - private router: Router + private _fuseNavigationService: FuseNavigationService, + private _router: Router ) { - // Listen for route changes - router.events.subscribe( - (event) => { - if ( event instanceof NavigationEnd ) + // Set the private defaults + this._unsubscribeAll = new Subject(); + } + + // ----------------------------------------------------------------------------------------------------- + // @ Lifecycle hooks + // ----------------------------------------------------------------------------------------------------- + + /** + * On init + */ + ngOnInit(): void + { + // Listen for router events + this._router.events + .pipe( + filter(event => event instanceof NavigationEnd), + takeUntil(this._unsubscribeAll) + ) + .subscribe((event: NavigationEnd) => { + + // Check if the url can be found in + // one of the children of this item + if ( this.isUrlInChildren(this.item, event.urlAfterRedirects) ) { - // Check if the url can be found in - // one of the children of this item - if ( this.isUrlInChildren(this.item, event.urlAfterRedirects) ) - { - this.expand(); - } - else - { - this.collapse(); - } + this.expand(); } - } - ); + else + { + this.collapse(); + } + }); // Listen for collapsing of any navigation item - this.navigationService.onItemCollapsed + this._fuseNavigationService.onItemCollapsed + .pipe(takeUntil(this._unsubscribeAll)) .subscribe( (clickedItem) => { if ( clickedItem && clickedItem.children ) @@ -54,7 +87,7 @@ export class FuseNavVerticalCollapseComponent implements OnInit // Check if the url can be found in // one of the children of this item - if ( this.isUrlInChildren(this.item, this.router.url) ) + if ( this.isUrlInChildren(this.item, this._router.url) ) { return; } @@ -67,13 +100,10 @@ export class FuseNavVerticalCollapseComponent implements OnInit } } ); - } - ngOnInit() - { // Check if the url can be found in // one of the children of this item - if ( this.isUrlInChildren(this.item, this.router.url) ) + if ( this.isUrlInChildren(this.item, this._router.url) ) { this.expand(); } @@ -83,26 +113,40 @@ export class FuseNavVerticalCollapseComponent implements OnInit } } + /** + * On destroy + */ + ngOnDestroy(): void + { + // Unsubscribe from all subscriptions + this._unsubscribeAll.next(); + this._unsubscribeAll.complete(); + } + + // ----------------------------------------------------------------------------------------------------- + // @ Public methods + // ----------------------------------------------------------------------------------------------------- + /** * Toggle collapse * * @param ev */ - toggleOpen(ev) + toggleOpen(ev): void { ev.preventDefault(); this.isOpen = !this.isOpen; // Navigation collapse toggled... - this.navigationService.onItemCollapsed.next(this.item); - this.navigationService.onItemCollapseToggled.next(); + this._fuseNavigationService.onItemCollapsed.next(this.item); + this._fuseNavigationService.onItemCollapseToggled.next(); } /** * Expand the collapsable navigation */ - expand() + expand(): void { if ( this.isOpen ) { @@ -110,13 +154,13 @@ export class FuseNavVerticalCollapseComponent implements OnInit } this.isOpen = true; - this.navigationService.onItemCollapseToggled.next(); + this._fuseNavigationService.onItemCollapseToggled.next(); } /** * Collapse the collapsable navigation */ - collapse() + collapse(): void { if ( !this.isOpen ) { @@ -124,7 +168,7 @@ export class FuseNavVerticalCollapseComponent implements OnInit } this.isOpen = false; - this.navigationService.onItemCollapseToggled.next(); + this._fuseNavigationService.onItemCollapseToggled.next(); } /** @@ -133,9 +177,9 @@ export class FuseNavVerticalCollapseComponent implements OnInit * * @param parent * @param item - * @return {any} + * @returns {boolean} */ - isChildrenOf(parent, item) + isChildrenOf(parent, item): boolean { if ( !parent.children ) { @@ -162,9 +206,9 @@ export class FuseNavVerticalCollapseComponent implements OnInit * * @param parent * @param url - * @returns {any} + * @returns {boolean} */ - isUrlInChildren(parent, url) + isUrlInChildren(parent, url): boolean { if ( !parent.children ) { diff --git a/src/@fuse/components/navigation/vertical/nav-group/nav-vertical-group.component.html b/src/@fuse/components/navigation/vertical/group/group.component.html similarity index 75% rename from src/@fuse/components/navigation/vertical/nav-group/nav-vertical-group.component.html rename to src/@fuse/components/navigation/vertical/group/group.component.html index 0747455c..26820b81 100644 --- a/src/@fuse/components/navigation/vertical/nav-group/nav-vertical-group.component.html +++ b/src/@fuse/components/navigation/vertical/group/group.component.html @@ -7,7 +7,8 @@
- +
diff --git a/src/@fuse/components/navigation/vertical/nav-group/nav-vertical-group.component.scss b/src/@fuse/components/navigation/vertical/group/group.component.scss similarity index 100% rename from src/@fuse/components/navigation/vertical/nav-group/nav-vertical-group.component.scss rename to src/@fuse/components/navigation/vertical/group/group.component.scss diff --git a/src/@fuse/components/navigation/vertical/group/group.component.ts b/src/@fuse/components/navigation/vertical/group/group.component.ts new file mode 100644 index 00000000..d43e223e --- /dev/null +++ b/src/@fuse/components/navigation/vertical/group/group.component.ts @@ -0,0 +1,25 @@ +import { Component, HostBinding, Input } from '@angular/core'; + +import { FuseNavigationItem } from '@fuse/types'; + +@Component({ + selector : 'fuse-nav-vertical-group', + templateUrl: './group.component.html', + styleUrls : ['./group.component.scss'] +}) +export class FuseNavVerticalGroupComponent +{ + @HostBinding('class') + classes = 'nav-group nav-item'; + + @Input() + item: FuseNavigationItem; + + /** + * Constructor + */ + constructor() + { + } + +} diff --git a/src/@fuse/components/navigation/vertical/item/item.component.html b/src/@fuse/components/navigation/vertical/item/item.component.html new file mode 100644 index 00000000..a90e4f99 --- /dev/null +++ b/src/@fuse/components/navigation/vertical/item/item.component.html @@ -0,0 +1,46 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + {{item.icon}} + {{item.title}} + + {{item.badge.title}} + + + + \ No newline at end of file diff --git a/src/@fuse/components/navigation/vertical/nav-item/nav-vertical-item.component.scss b/src/@fuse/components/navigation/vertical/item/item.component.scss similarity index 100% rename from src/@fuse/components/navigation/vertical/nav-item/nav-vertical-item.component.scss rename to src/@fuse/components/navigation/vertical/item/item.component.scss diff --git a/src/@fuse/components/navigation/vertical/item/item.component.ts b/src/@fuse/components/navigation/vertical/item/item.component.ts new file mode 100644 index 00000000..c807e381 --- /dev/null +++ b/src/@fuse/components/navigation/vertical/item/item.component.ts @@ -0,0 +1,24 @@ +import { Component, HostBinding, Input } from '@angular/core'; + +import { FuseNavigationItem } from '@fuse/types'; + +@Component({ + selector : 'fuse-nav-vertical-item', + templateUrl: './item.component.html', + styleUrls : ['./item.component.scss'] +}) +export class FuseNavVerticalItemComponent +{ + @HostBinding('class') + classes = 'nav-item'; + + @Input() + item: FuseNavigationItem; + + /** + * Constructor + */ + constructor() + { + } +} diff --git a/src/@fuse/components/navigation/vertical/nav-group/nav-vertical-group.component.ts b/src/@fuse/components/navigation/vertical/nav-group/nav-vertical-group.component.ts deleted file mode 100644 index 56151d6f..00000000 --- a/src/@fuse/components/navigation/vertical/nav-group/nav-vertical-group.component.ts +++ /dev/null @@ -1,17 +0,0 @@ -import { Component, HostBinding, Input } from '@angular/core'; - -@Component({ - selector : 'fuse-nav-vertical-group', - templateUrl: './nav-vertical-group.component.html', - styleUrls : ['./nav-vertical-group.component.scss'] -}) -export class FuseNavVerticalGroupComponent -{ - @HostBinding('class') classes = 'nav-group nav-item'; - @Input() item: any; - - constructor() - { - } - -} diff --git a/src/@fuse/components/navigation/vertical/nav-item/nav-vertical-item.component.html b/src/@fuse/components/navigation/vertical/nav-item/nav-vertical-item.component.html deleted file mode 100644 index f4de0858..00000000 --- a/src/@fuse/components/navigation/vertical/nav-item/nav-vertical-item.component.html +++ /dev/null @@ -1,31 +0,0 @@ - - - - - - - - - - - - - - - - - - - {{item.icon}} - {{item.title}} - - {{item.badge.title}} - - - - \ No newline at end of file diff --git a/src/@fuse/components/navigation/vertical/nav-item/nav-vertical-item.component.ts b/src/@fuse/components/navigation/vertical/nav-item/nav-vertical-item.component.ts deleted file mode 100644 index 071ed1ee..00000000 --- a/src/@fuse/components/navigation/vertical/nav-item/nav-vertical-item.component.ts +++ /dev/null @@ -1,16 +0,0 @@ -import { Component, HostBinding, Input } from '@angular/core'; - -@Component({ - selector : 'fuse-nav-vertical-item', - templateUrl: './nav-vertical-item.component.html', - styleUrls : ['./nav-vertical-item.component.scss'] -}) -export class FuseNavVerticalItemComponent -{ - @HostBinding('class') classes = 'nav-item'; - @Input() item: any; - - constructor() - { - } -} diff --git a/src/@fuse/components/search-bar/search-bar.component.html b/src/@fuse/components/search-bar/search-bar.component.html index f64e9d09..f3df8660 100644 --- a/src/@fuse/components/search-bar/search-bar.component.html +++ b/src/@fuse/components/search-bar/search-bar.component.html @@ -1,11 +1,11 @@ - @@ -32,7 +33,7 @@ \ No newline at end of file diff --git a/src/app/main/navbar/navbar.component.scss b/src/app/layout/components/navbar/navbar.component.scss similarity index 70% rename from src/app/main/navbar/navbar.component.scss rename to src/app/layout/components/navbar/navbar.component.scss index bc12ef87..fc111989 100644 --- a/src/app/main/navbar/navbar.component.scss +++ b/src/app/layout/components/navbar/navbar.component.scss @@ -1,28 +1,5 @@ @import "src/@fuse/scss/fuse"; -body { - - &.fuse-sidebar-folded { - - .content-wrapper { - - &:last-child { - padding-left: 64px !important; - } - - &:first-child { - padding-right: 64px !important; - } - - &:first-child:last-child { - padding-left: 0 !important; - padding-right: 0 !important; - } - - } - } -} - fuse-sidebar { &.folded:not(.unfolded) { @@ -44,10 +21,11 @@ fuse-sidebar { } } -fuse-navbar { +navbar { &:not(.top-navbar) { height: 100%; + overflow: hidden; } .navbar-vertical { @@ -86,19 +64,18 @@ fuse-navbar { } .navbar-content { - flex: 1; + flex: 1 1 auto; + overflow-y: auto; + } + } + + &.right-navbar { + + .toggle-sidebar-opened { + + mat-icon { + transform: rotate(180deg); + } } } } - -.top-navbar + #wrapper { - - & > .left-navbar { - display: none !important; - - @include media-breakpoint-down(md) { - display: flex !important; - } - } -} - diff --git a/src/app/layout/components/navbar/navbar.component.ts b/src/app/layout/components/navbar/navbar.component.ts new file mode 100644 index 00000000..c611f7c9 --- /dev/null +++ b/src/app/layout/components/navbar/navbar.component.ts @@ -0,0 +1,137 @@ +import { Component, Input, OnDestroy, OnInit, ViewChild, ViewEncapsulation } from '@angular/core'; +import { NavigationEnd, Router } from '@angular/router'; +import { Subject } from 'rxjs'; +import { filter, takeUntil } from 'rxjs/operators'; + +import { FuseNavigationService } from '@fuse/components/navigation/navigation.service'; +import { FusePerfectScrollbarDirective } from '@fuse/directives/fuse-perfect-scrollbar/fuse-perfect-scrollbar.directive'; +import { FuseSidebarService } from '@fuse/components/sidebar/sidebar.service'; + +@Component({ + selector : 'navbar', + templateUrl : './navbar.component.html', + styleUrls : ['./navbar.component.scss'], + encapsulation: ViewEncapsulation.None +}) +export class NavbarComponent implements OnInit, OnDestroy +{ + // Layout + @Input() + layout; + + fusePerfectScrollbarUpdateTimeout: any; + navigation: any; + + // Private + private _fusePerfectScrollbar: FusePerfectScrollbarDirective; + private _unsubscribeAll: Subject; + + /** + * Constructor + * + * @param {FuseNavigationService} _fuseNavigationService + * @param {FuseSidebarService} _fuseSidebarService + * @param {Router} _router + */ + constructor( + private _fuseNavigationService: FuseNavigationService, + private _fuseSidebarService: FuseSidebarService, + private _router: Router + ) + { + // Set the defaults + this.layout = 'vertical'; + + // Set the private defaults + this._unsubscribeAll = new Subject(); + } + + // ----------------------------------------------------------------------------------------------------- + // @ Accessors + // ----------------------------------------------------------------------------------------------------- + + // Directive + @ViewChild(FusePerfectScrollbarDirective) + set directive(theDirective: FusePerfectScrollbarDirective) + { + if ( !theDirective ) + { + return; + } + + this._fusePerfectScrollbar = theDirective; + + this._fuseNavigationService.onItemCollapseToggled + .pipe(takeUntil(this._unsubscribeAll)) + .subscribe(() => { + this.fusePerfectScrollbarUpdateTimeout = setTimeout(() => { + this._fusePerfectScrollbar.update(); + }, 310); + }); + } + + // ----------------------------------------------------------------------------------------------------- + // @ Lifecycle hooks + // ----------------------------------------------------------------------------------------------------- + + /** + * On init + */ + ngOnInit(): void + { + this._router.events + .pipe( + filter((event) => event instanceof NavigationEnd), + takeUntil(this._unsubscribeAll) + ) + .subscribe(() => { + if ( this._fuseSidebarService.getSidebar('navbar') ) + { + this._fuseSidebarService.getSidebar('navbar').close(); + } + } + ); + + // Get current navigation + this._fuseNavigationService.onNavigationChanged + .pipe(filter(value => value !== null)) + .subscribe(() => { + this.navigation = this._fuseNavigationService.getCurrentNavigation(); + }); + } + + /** + * On destroy + */ + ngOnDestroy(): void + { + if ( this.fusePerfectScrollbarUpdateTimeout ) + { + clearTimeout(this.fusePerfectScrollbarUpdateTimeout); + } + + // Unsubscribe from all subscriptions + this._unsubscribeAll.next(); + this._unsubscribeAll.complete(); + } + + // ----------------------------------------------------------------------------------------------------- + // @ Public methods + // ----------------------------------------------------------------------------------------------------- + + /** + * Toggle sidebar opened status + */ + toggleSidebarOpened(): void + { + this._fuseSidebarService.getSidebar('navbar').toggleOpen(); + } + + /** + * Toggle sidebar folded status + */ + toggleSidebarFolded(): void + { + this._fuseSidebarService.getSidebar('navbar').toggleFold(); + } +} diff --git a/src/app/main/navbar/navbar.module.ts b/src/app/layout/components/navbar/navbar.module.ts similarity index 65% rename from src/app/main/navbar/navbar.module.ts rename to src/app/layout/components/navbar/navbar.module.ts index c3da75e6..acb91738 100644 --- a/src/app/main/navbar/navbar.module.ts +++ b/src/app/layout/components/navbar/navbar.module.ts @@ -1,20 +1,16 @@ import { NgModule } from '@angular/core'; -import { RouterModule } from '@angular/router'; - import { MatButtonModule, MatIconModule } from '@angular/material'; +import { FuseNavigationModule } from '@fuse/components'; import { FuseSharedModule } from '@fuse/shared.module'; -import { FuseNavbarComponent } from 'app/main/navbar/navbar.component'; -import { FuseNavigationModule } from '@fuse/components'; +import { NavbarComponent } from 'app/layout/components/navbar/navbar.component'; @NgModule({ declarations: [ - FuseNavbarComponent + NavbarComponent ], imports : [ - RouterModule, - MatButtonModule, MatIconModule, @@ -22,9 +18,9 @@ import { FuseNavigationModule } from '@fuse/components'; FuseNavigationModule ], exports : [ - FuseNavbarComponent + NavbarComponent ] }) -export class FuseNavbarModule +export class NavbarModule { } diff --git a/src/app/main/quick-panel/quick-panel.component.html b/src/app/layout/components/quick-panel/quick-panel.component.html similarity index 100% rename from src/app/main/quick-panel/quick-panel.component.html rename to src/app/layout/components/quick-panel/quick-panel.component.html diff --git a/src/app/main/quick-panel/quick-panel.component.scss b/src/app/layout/components/quick-panel/quick-panel.component.scss similarity index 90% rename from src/app/main/quick-panel/quick-panel.component.scss rename to src/app/layout/components/quick-panel/quick-panel.component.scss index be16d852..2b116c1a 100644 --- a/src/app/main/quick-panel/quick-panel.component.scss +++ b/src/app/layout/components/quick-panel/quick-panel.component.scss @@ -1,4 +1,4 @@ -fuse-quick-panel { +quick-panel { display: flex; width: 280px; min-width: 280px; diff --git a/src/app/layout/components/quick-panel/quick-panel.component.ts b/src/app/layout/components/quick-panel/quick-panel.component.ts new file mode 100644 index 00000000..ba235aa4 --- /dev/null +++ b/src/app/layout/components/quick-panel/quick-panel.component.ts @@ -0,0 +1,76 @@ +import { Component, OnDestroy, OnInit, ViewEncapsulation } from '@angular/core'; +import { HttpClient } from '@angular/common/http'; +import { Subject } from 'rxjs'; +import { takeUntil } from 'rxjs/operators'; + +@Component({ + selector : 'quick-panel', + templateUrl : './quick-panel.component.html', + styleUrls : ['./quick-panel.component.scss'], + encapsulation: ViewEncapsulation.None +}) +export class QuickPanelComponent implements OnInit, OnDestroy +{ + date: Date; + events: any[]; + notes: any[]; + settings: any; + + // Private + private _unsubscribeAll: Subject; + + /** + * Constructor + * + * @param {HttpClient} _httpClient + */ + constructor( + private _httpClient: HttpClient + ) + { + // Set the defaults + this.date = new Date(); + this.settings = { + notify: true, + cloud : false, + retro : true + }; + + // Set the private defaults + this._unsubscribeAll = new Subject(); + } + + // ----------------------------------------------------------------------------------------------------- + // @ Lifecycle hooks + // ----------------------------------------------------------------------------------------------------- + + /** + * On init + */ + ngOnInit(): void + { + // Subscribe to the events + this._httpClient.get('api/quick-panel-events') + .pipe(takeUntil(this._unsubscribeAll)) + .subscribe((response: any) => { + this.events = response; + }); + + // Subscribe to the notes + this._httpClient.get('api/quick-panel-notes') + .pipe(takeUntil(this._unsubscribeAll)) + .subscribe((response: any) => { + this.notes = response; + }); + } + + /** + * On destroy + */ + ngOnDestroy(): void + { + // Unsubscribe from all subscriptions + this._unsubscribeAll.next(); + this._unsubscribeAll.complete(); + } +} diff --git a/src/app/main/quick-panel/quick-panel.module.ts b/src/app/layout/components/quick-panel/quick-panel.module.ts similarity index 60% rename from src/app/main/quick-panel/quick-panel.module.ts rename to src/app/layout/components/quick-panel/quick-panel.module.ts index 716461e3..48009f2e 100644 --- a/src/app/main/quick-panel/quick-panel.module.ts +++ b/src/app/layout/components/quick-panel/quick-panel.module.ts @@ -1,18 +1,15 @@ import { NgModule } from '@angular/core'; -import { RouterModule } from '@angular/router'; import { MatDividerModule, MatListModule, MatSlideToggleModule } from '@angular/material'; import { FuseSharedModule } from '@fuse/shared.module'; -import { FuseQuickPanelComponent } from 'app/main/quick-panel/quick-panel.component'; +import { QuickPanelComponent } from 'app/layout/components/quick-panel/quick-panel.component'; @NgModule({ declarations: [ - FuseQuickPanelComponent + QuickPanelComponent ], imports : [ - RouterModule, - MatDividerModule, MatListModule, MatSlideToggleModule, @@ -20,9 +17,9 @@ import { FuseQuickPanelComponent } from 'app/main/quick-panel/quick-panel.compon FuseSharedModule, ], exports: [ - FuseQuickPanelComponent + QuickPanelComponent ] }) -export class FuseQuickPanelModule +export class QuickPanelModule { } diff --git a/src/app/main/toolbar/toolbar.component.html b/src/app/layout/components/toolbar/toolbar.component.html similarity index 75% rename from src/app/main/toolbar/toolbar.component.html rename to src/app/layout/components/toolbar/toolbar.component.html index a33dfbd5..6324fe04 100644 --- a/src/app/main/toolbar/toolbar.component.html +++ b/src/app/layout/components/toolbar/toolbar.component.html @@ -6,15 +6,14 @@
- -
+
-
+
@@ -58,7 +57,7 @@
- +
@@ -73,11 +72,11 @@ -
+ @@ -86,11 +85,20 @@ +
+ + +
+
+ diff --git a/src/app/main/toolbar/toolbar.component.scss b/src/app/layout/components/toolbar/toolbar.component.scss similarity index 94% rename from src/app/main/toolbar/toolbar.component.scss rename to src/app/layout/components/toolbar/toolbar.component.scss index f1bd3177..3813e171 100644 --- a/src/app/main/toolbar/toolbar.component.scss +++ b/src/app/layout/components/toolbar/toolbar.component.scss @@ -1,4 +1,4 @@ -@import 'src/@fuse/scss/fuse'; +@import "src/@fuse/scss/fuse"; :host { position: relative; @@ -45,7 +45,7 @@ } } - .toggle-button-navbar { + .navbar-toggle-button { min-width: 56px; height: 56px; } diff --git a/src/app/layout/components/toolbar/toolbar.component.ts b/src/app/layout/components/toolbar/toolbar.component.ts new file mode 100644 index 00000000..3783d894 --- /dev/null +++ b/src/app/layout/components/toolbar/toolbar.component.ts @@ -0,0 +1,184 @@ +import { Component, OnDestroy, OnInit } from '@angular/core'; +import { NavigationEnd, NavigationStart, Router } from '@angular/router'; +import { Subject } from 'rxjs'; +import { filter, takeUntil } from 'rxjs/operators'; +import { TranslateService } from '@ngx-translate/core'; +import * as _ from 'lodash'; + +import { FuseConfigService } from '@fuse/services/config.service'; +import { FuseSidebarService } from '@fuse/components/sidebar/sidebar.service'; + +import { navigation } from 'app/navigation/navigation'; + +@Component({ + selector : 'toolbar', + templateUrl: './toolbar.component.html', + styleUrls : ['./toolbar.component.scss'] +}) + +export class ToolbarComponent implements OnInit, OnDestroy +{ + horizontalNavbar: boolean; + rightNavbar: boolean; + hiddenNavbar: boolean; + languages: any; + navigation: any; + selectedLanguage: any; + showLoadingBar: boolean; + userStatusOptions: any[]; + + // Private + private _unsubscribeAll: Subject; + + /** + * Constructor + * + * @param {FuseConfigService} _fuseConfigService + * @param {FuseSidebarService} _fuseSidebarService + * @param {Router} _router + * @param {TranslateService} _translateService + */ + constructor( + private _fuseConfigService: FuseConfigService, + private _fuseSidebarService: FuseSidebarService, + private _router: Router, + private _translateService: TranslateService + ) + { + // Set the defaults + this.userStatusOptions = [ + { + 'title': 'Online', + 'icon' : 'icon-checkbox-marked-circle', + 'color': '#4CAF50' + }, + { + 'title': 'Away', + 'icon' : 'icon-clock', + 'color': '#FFC107' + }, + { + 'title': 'Do not Disturb', + 'icon' : 'icon-minus-circle', + 'color': '#F44336' + }, + { + 'title': 'Invisible', + 'icon' : 'icon-checkbox-blank-circle-outline', + 'color': '#BDBDBD' + }, + { + 'title': 'Offline', + 'icon' : 'icon-checkbox-blank-circle-outline', + 'color': '#616161' + } + ]; + + this.languages = [ + { + id : 'en', + title: 'English', + flag : 'us' + }, + { + id : 'tr', + title: 'Turkish', + flag : 'tr' + } + ]; + + this.navigation = navigation; + + // Set the private defaults + this._unsubscribeAll = new Subject(); + } + + // ----------------------------------------------------------------------------------------------------- + // @ Lifecycle hooks + // ----------------------------------------------------------------------------------------------------- + + /** + * On init + */ + ngOnInit(): void + { + // Subscribe to the router events to show/hide the loading bar + this._router.events + .pipe( + filter((event) => event instanceof NavigationStart), + takeUntil(this._unsubscribeAll) + ) + .subscribe((event) => { + this.showLoadingBar = true; + }); + + this._router.events + .pipe( + filter((event) => event instanceof NavigationEnd) + ) + .subscribe((event) => { + this.showLoadingBar = false; + }); + + // Subscribe to the config changes + this._fuseConfigService.config + .pipe(takeUntil(this._unsubscribeAll)) + .subscribe((settings) => { + this.horizontalNavbar = settings.layout.navbar.position === 'top'; + this.rightNavbar = settings.layout.navbar.position === 'right'; + this.hiddenNavbar = settings.layout.navbar.hidden === true; + }); + + // Set the selected language from default languages + this.selectedLanguage = _.find(this.languages, {'id': this._translateService.currentLang}); + } + + /** + * On destroy + */ + ngOnDestroy(): void + { + // Unsubscribe from all subscriptions + this._unsubscribeAll.next(); + this._unsubscribeAll.complete(); + } + + // ----------------------------------------------------------------------------------------------------- + // @ Public methods + // ----------------------------------------------------------------------------------------------------- + + /** + * Toggle sidebar open + * + * @param key + */ + toggleSidebarOpen(key): void + { + this._fuseSidebarService.getSidebar(key).toggleOpen(); + } + + /** + * Search + * + * @param value + */ + search(value): void + { + // Do your search here... + console.log(value); + } + + /** + * Set the language + * + * @param langId + */ + setLanguage(langId): void + { + // Set the selected language for toolbar + this.selectedLanguage = _.find(this.languages, {'id': langId}); + + // Use the selected language for translations + this._translateService.use(langId); + } +} diff --git a/src/app/main/toolbar/toolbar.module.ts b/src/app/layout/components/toolbar/toolbar.module.ts similarity index 80% rename from src/app/main/toolbar/toolbar.module.ts rename to src/app/layout/components/toolbar/toolbar.module.ts index 4d61d960..17e36e0c 100644 --- a/src/app/main/toolbar/toolbar.module.ts +++ b/src/app/layout/components/toolbar/toolbar.module.ts @@ -2,18 +2,17 @@ import { NgModule } from '@angular/core'; import { RouterModule } from '@angular/router'; import { MatButtonModule, MatIconModule, MatMenuModule, MatProgressBarModule, MatToolbarModule } from '@angular/material'; +import { FuseSearchBarModule, FuseShortcutsModule } from '@fuse/components'; import { FuseSharedModule } from '@fuse/shared.module'; -import { FuseToolbarComponent } from 'app/main/toolbar/toolbar.component'; -import { FuseSearchBarModule, FuseShortcutsModule } from '@fuse/components'; +import { ToolbarComponent } from 'app/layout/components/toolbar/toolbar.component'; @NgModule({ declarations: [ - FuseToolbarComponent + ToolbarComponent ], imports : [ RouterModule, - MatButtonModule, MatIconModule, MatMenuModule, @@ -25,9 +24,9 @@ import { FuseSearchBarModule, FuseShortcutsModule } from '@fuse/components'; FuseShortcutsModule ], exports : [ - FuseToolbarComponent + ToolbarComponent ] }) -export class FuseToolbarModule +export class ToolbarModule { } diff --git a/src/app/layout/horizontal/layout-1/layout-1.component.html b/src/app/layout/horizontal/layout-1/layout-1.component.html new file mode 100644 index 00000000..aa7ab758 --- /dev/null +++ b/src/app/layout/horizontal/layout-1/layout-1.component.html @@ -0,0 +1,100 @@ +
+ + + + + + + + + + + + + + + + + + + +
+ + + + + + + +
+ +
+ + + + + + + + + + + +
+ +
+ +
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + +
+
+ + + + + + + + + + + + + + + + diff --git a/src/app/layout/horizontal/layout-1/layout-1.component.scss b/src/app/layout/horizontal/layout-1/layout-1.component.scss new file mode 100644 index 00000000..b92cdd75 --- /dev/null +++ b/src/app/layout/horizontal/layout-1/layout-1.component.scss @@ -0,0 +1,68 @@ +@import "src/@fuse/scss/fuse"; + +horizontal-layout-1 { + display: flex; + flex: 1 1 auto; + width: 100%; + height: 100%; + + #main { + position: relative; + display: flex; + flex: 1 1 auto; + flex-direction: column; + width: 100%; + height: 100%; + z-index: 1; + + // Boxed + &.boxed { + max-width: 1200px; + margin: 0 auto; + @include mat-elevation(8); + } + + // Container 1 + > .container { + position: relative; + display: flex; + flex: 1 1 0%; + width: 100%; + min-height: 0; + min-width: 0; + + // Container 2 + > .container { + position: relative; + display: flex; + flex: 1 1 0%; + flex-direction: column; + min-width: 0; + + // Container 3 (Scrollable) + > .container { + position: relative; + display: flex; + flex: 1 1 0%; + flex-direction: column; + transform: translateZ(0); + overflow-x: hidden; + overflow-y: auto; + + // Content component + content { + + &.inner-scroll { + flex: 1 1 0%; + min-height: 0; + + > *:not(router-outlet) { + flex: 1 1 0%; + } + } + } + } + } + } + } +} diff --git a/src/app/layout/horizontal/layout-1/layout-1.component.ts b/src/app/layout/horizontal/layout-1/layout-1.component.ts new file mode 100644 index 00000000..9b2868c0 --- /dev/null +++ b/src/app/layout/horizontal/layout-1/layout-1.component.ts @@ -0,0 +1,64 @@ +import { Component, OnDestroy, OnInit, ViewEncapsulation } from '@angular/core'; +import { Subject } from 'rxjs'; +import { takeUntil } from 'rxjs/operators'; + +import { FuseConfigService } from '@fuse/services/config.service'; +import { navigation } from 'app/navigation/navigation'; + +@Component({ + selector : 'horizontal-layout-1', + templateUrl : './layout-1.component.html', + styleUrls : ['./layout-1.component.scss'], + encapsulation: ViewEncapsulation.None +}) +export class HorizontalLayout1Component implements OnInit, OnDestroy +{ + fuseConfig: any; + navigation: any; + + // Private + private _unsubscribeAll: Subject; + + /** + * Constructor + * + * @param {FuseConfigService} _fuseConfigService + */ + constructor( + private _fuseConfigService: FuseConfigService + ) + { + // Set the defaults + this.navigation = navigation; + + // Set the private defaults + this._unsubscribeAll = new Subject(); + } + + // ----------------------------------------------------------------------------------------------------- + // @ Lifecycle hooks + // ----------------------------------------------------------------------------------------------------- + + /** + * On init + */ + ngOnInit(): void + { + // Subscribe to config changes + this._fuseConfigService.config + .pipe(takeUntil(this._unsubscribeAll)) + .subscribe((config) => { + this.fuseConfig = config; + }); + } + + /** + * On destroy + */ + ngOnDestroy(): void + { + // Unsubscribe from all subscriptions + this._unsubscribeAll.next(); + this._unsubscribeAll.complete(); + } +} diff --git a/src/app/layout/horizontal/layout-1/layout-1.module.ts b/src/app/layout/horizontal/layout-1/layout-1.module.ts new file mode 100644 index 00000000..ee92e4b6 --- /dev/null +++ b/src/app/layout/horizontal/layout-1/layout-1.module.ts @@ -0,0 +1,38 @@ +import { NgModule } from '@angular/core'; +import { MatSidenavModule } from '@angular/material'; + +import { FuseSidebarModule, FuseThemeOptionsModule } from '@fuse/components'; +import { FuseSharedModule } from '@fuse/shared.module'; + +import { ContentModule } from 'app/layout/components/content/content.module'; +import { FooterModule } from 'app/layout/components/footer/footer.module'; +import { NavbarModule } from 'app/layout/components/navbar/navbar.module'; +import { QuickPanelModule } from 'app/layout/components/quick-panel/quick-panel.module'; +import { ToolbarModule } from 'app/layout/components/toolbar/toolbar.module'; + +import { HorizontalLayout1Component } from 'app/layout/horizontal/layout-1/layout-1.component'; + +@NgModule({ + declarations: [ + HorizontalLayout1Component + ], + imports : [ + MatSidenavModule, + + FuseSharedModule, + FuseSidebarModule, + FuseThemeOptionsModule, + + ContentModule, + FooterModule, + NavbarModule, + QuickPanelModule, + ToolbarModule + ], + exports : [ + HorizontalLayout1Component + ] +}) +export class HorizontalLayout1Module +{ +} diff --git a/src/app/layout/layout.module.ts b/src/app/layout/layout.module.ts new file mode 100644 index 00000000..d728adef --- /dev/null +++ b/src/app/layout/layout.module.ts @@ -0,0 +1,27 @@ +import { NgModule } from '@angular/core'; + +import { VerticalLayout1Module } from 'app/layout/vertical/layout-1/layout-1.module'; +import { VerticalLayout2Module } from 'app/layout/vertical/layout-2/layout-2.module'; +import { VerticalLayout3Module } from 'app/layout/vertical/layout-3/layout-3.module'; + +import { HorizontalLayout1Module } from 'app/layout/horizontal/layout-1/layout-1.module'; + +@NgModule({ + imports: [ + VerticalLayout1Module, + VerticalLayout2Module, + VerticalLayout3Module, + + HorizontalLayout1Module + ], + exports: [ + VerticalLayout1Module, + VerticalLayout2Module, + VerticalLayout3Module, + + HorizontalLayout1Module + ] +}) +export class LayoutModule +{ +} diff --git a/src/app/layout/vertical/layout-1/layout-1.component.html b/src/app/layout/vertical/layout-1/layout-1.component.html new file mode 100644 index 00000000..e6b32e29 --- /dev/null +++ b/src/app/layout/vertical/layout-1/layout-1.component.html @@ -0,0 +1,114 @@ +
+ + + + + + + +
+ + + + + + + +
+ + + + + + + +
+ + + + + + + + + + + + + + + + + +
+ + + + + + + +
+ + + + + + + +
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + +
+
+ + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/app/layout/vertical/layout-1/layout-1.component.scss b/src/app/layout/vertical/layout-1/layout-1.component.scss new file mode 100644 index 00000000..e9d12711 --- /dev/null +++ b/src/app/layout/vertical/layout-1/layout-1.component.scss @@ -0,0 +1,68 @@ +@import "src/@fuse/scss/fuse"; + +vertical-layout-1 { + display: flex; + flex: 1 1 auto; + width: 100%; + height: 100%; + + #main { + position: relative; + display: flex; + flex: 1 1 auto; + flex-direction: column; + width: 100%; + height: 100%; + z-index: 1; + + // Boxed + &.boxed { + max-width: 1200px; + margin: 0 auto; + @include mat-elevation(8); + } + + // Container 1 + > .container { + position: relative; + display: flex; + flex: 1 1 0%; + width: 100%; + min-height: 0; + min-width: 0; + + // Container 2 + > .container { + position: relative; + display: flex; + flex: 1 1 0%; + flex-direction: column; + min-width: 0; + + // Container 3 (Scrollable) + > .container { + position: relative; + display: flex; + flex: 1 1 0%; + flex-direction: column; + transform: translateZ(0); + overflow-x: hidden; + overflow-y: auto; + + // Content component + content { + + &.inner-scroll { + flex: 1 1 0%; + min-height: 0; + + > *:not(router-outlet) { + flex: 1 1 0%; + } + } + } + } + } + } + } +} \ No newline at end of file diff --git a/src/app/layout/vertical/layout-1/layout-1.component.ts b/src/app/layout/vertical/layout-1/layout-1.component.ts new file mode 100644 index 00000000..07c58e02 --- /dev/null +++ b/src/app/layout/vertical/layout-1/layout-1.component.ts @@ -0,0 +1,64 @@ +import { Component, OnDestroy, OnInit, ViewEncapsulation } from '@angular/core'; +import { Subject } from 'rxjs'; +import { takeUntil } from 'rxjs/operators'; + +import { FuseConfigService } from '@fuse/services/config.service'; +import { navigation } from 'app/navigation/navigation'; + +@Component({ + selector : 'vertical-layout-1', + templateUrl : './layout-1.component.html', + styleUrls : ['./layout-1.component.scss'], + encapsulation: ViewEncapsulation.None +}) +export class VerticalLayout1Component implements OnInit, OnDestroy +{ + fuseConfig: any; + navigation: any; + + // Private + private _unsubscribeAll: Subject; + + /** + * Constructor + * + * @param {FuseConfigService} _fuseConfigService + */ + constructor( + private _fuseConfigService: FuseConfigService + ) + { + // Set the defaults + this.navigation = navigation; + + // Set the private defaults + this._unsubscribeAll = new Subject(); + } + + // ----------------------------------------------------------------------------------------------------- + // @ Lifecycle hooks + // ----------------------------------------------------------------------------------------------------- + + /** + * On init + */ + ngOnInit(): void + { + // Subscribe to config changes + this._fuseConfigService.config + .pipe(takeUntil(this._unsubscribeAll)) + .subscribe((config) => { + this.fuseConfig = config; + }); + } + + /** + * On destroy + */ + ngOnDestroy(): void + { + // Unsubscribe from all subscriptions + this._unsubscribeAll.next(); + this._unsubscribeAll.complete(); + } +} diff --git a/src/app/layout/vertical/layout-1/layout-1.module.ts b/src/app/layout/vertical/layout-1/layout-1.module.ts new file mode 100644 index 00000000..a4d70f06 --- /dev/null +++ b/src/app/layout/vertical/layout-1/layout-1.module.ts @@ -0,0 +1,37 @@ +import { NgModule } from '@angular/core'; +import { RouterModule } from '@angular/router'; + +import { FuseSidebarModule } from '@fuse/components'; +import { FuseSharedModule } from '@fuse/shared.module'; + +import { ContentModule } from 'app/layout/components/content/content.module'; +import { FooterModule } from 'app/layout/components/footer/footer.module'; +import { NavbarModule } from 'app/layout/components/navbar/navbar.module'; +import { QuickPanelModule } from 'app/layout/components/quick-panel/quick-panel.module'; +import { ToolbarModule } from 'app/layout/components/toolbar/toolbar.module'; + +import { VerticalLayout1Component } from 'app/layout/vertical/layout-1/layout-1.component'; + +@NgModule({ + declarations: [ + VerticalLayout1Component + ], + imports : [ + RouterModule, + + FuseSharedModule, + FuseSidebarModule, + + ContentModule, + FooterModule, + NavbarModule, + QuickPanelModule, + ToolbarModule + ], + exports : [ + VerticalLayout1Component + ] +}) +export class VerticalLayout1Module +{ +} diff --git a/src/app/layout/vertical/layout-2/layout-2.component.html b/src/app/layout/vertical/layout-2/layout-2.component.html new file mode 100644 index 00000000..6eb66b31 --- /dev/null +++ b/src/app/layout/vertical/layout-2/layout-2.component.html @@ -0,0 +1,114 @@ +
+ + + + + + + +
+ + + + + + + +
+ + + + + + + +
+ + + + + + + + + + + + + + + + + +
+ + + + + + + +
+ + + + + + + +
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + +
+
+ + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/app/layout/vertical/layout-2/layout-2.component.scss b/src/app/layout/vertical/layout-2/layout-2.component.scss new file mode 100644 index 00000000..1ade45b0 --- /dev/null +++ b/src/app/layout/vertical/layout-2/layout-2.component.scss @@ -0,0 +1,54 @@ +@import "src/@fuse/scss/fuse"; + +vertical-layout-2 { + display: flex; + flex: 1 1 auto; + width: 100%; + height: 100%; + + #main { + position: relative; + display: flex; + flex: 1 1 auto; + flex-direction: column; + width: 100%; + height: 100%; + z-index: 1; + + // Boxed + &.boxed { + max-width: 1200px; + margin: 0 auto; + @include mat-elevation(8); + } + + // Container 1 (Scrollable) + > .container { + position: relative; + display: flex; + flex: 1 1 auto; + flex-direction: column; + width: 100%; + overflow-x: hidden; + overflow-y: auto; + transform: translateZ(0); + + // Container 2 + > .container { + position: relative; + display: flex; + flex: 1 0 auto; + width: 100%; + + // Container 3 + > .container { + position: relative; + display: flex; + flex: 1 1 auto; + flex-direction: column; + min-width: 0; + } + } + } + } +} \ No newline at end of file diff --git a/src/app/layout/vertical/layout-2/layout-2.component.ts b/src/app/layout/vertical/layout-2/layout-2.component.ts new file mode 100644 index 00000000..82fb5d8a --- /dev/null +++ b/src/app/layout/vertical/layout-2/layout-2.component.ts @@ -0,0 +1,64 @@ +import { Component, OnDestroy, OnInit, ViewEncapsulation } from '@angular/core'; +import { Subject } from 'rxjs'; +import { takeUntil } from 'rxjs/operators'; + +import { FuseConfigService } from '@fuse/services/config.service'; +import { navigation } from 'app/navigation/navigation'; + +@Component({ + selector : 'vertical-layout-2', + templateUrl : './layout-2.component.html', + styleUrls : ['./layout-2.component.scss'], + encapsulation: ViewEncapsulation.None +}) +export class VerticalLayout2Component implements OnInit, OnDestroy +{ + fuseConfig: any; + navigation: any; + + // Private + private _unsubscribeAll: Subject; + + /** + * Constructor + * + * @param {FuseConfigService} _fuseConfigService + */ + constructor( + private _fuseConfigService: FuseConfigService + ) + { + // Set the defaults + this.navigation = navigation; + + // Set the private defaults + this._unsubscribeAll = new Subject(); + } + + // ----------------------------------------------------------------------------------------------------- + // @ Lifecycle hooks + // ----------------------------------------------------------------------------------------------------- + + /** + * On init + */ + ngOnInit(): void + { + // Subscribe to config changes + this._fuseConfigService.config + .pipe(takeUntil(this._unsubscribeAll)) + .subscribe((config) => { + this.fuseConfig = config; + }); + } + + /** + * On destroy + */ + ngOnDestroy(): void + { + // Unsubscribe from all subscriptions + this._unsubscribeAll.next(); + this._unsubscribeAll.complete(); + } +} diff --git a/src/app/layout/vertical/layout-2/layout-2.module.ts b/src/app/layout/vertical/layout-2/layout-2.module.ts new file mode 100644 index 00000000..64c7540f --- /dev/null +++ b/src/app/layout/vertical/layout-2/layout-2.module.ts @@ -0,0 +1,37 @@ +import { NgModule } from '@angular/core'; +import { RouterModule } from '@angular/router'; + +import { FuseSidebarModule } from '@fuse/components'; +import { FuseSharedModule } from '@fuse/shared.module'; + +import { ContentModule } from 'app/layout/components/content/content.module'; +import { FooterModule } from 'app/layout/components/footer/footer.module'; +import { NavbarModule } from 'app/layout/components/navbar/navbar.module'; +import { QuickPanelModule } from 'app/layout/components/quick-panel/quick-panel.module'; +import { ToolbarModule } from 'app/layout/components/toolbar/toolbar.module'; + +import { VerticalLayout2Component } from 'app/layout/vertical/layout-2/layout-2.component'; + +@NgModule({ + declarations: [ + VerticalLayout2Component + ], + imports : [ + RouterModule, + + FuseSharedModule, + FuseSidebarModule, + + ContentModule, + FooterModule, + NavbarModule, + QuickPanelModule, + ToolbarModule + ], + exports : [ + VerticalLayout2Component + ] +}) +export class VerticalLayout2Module +{ +} diff --git a/src/app/layout/vertical/layout-3/layout-3.component.html b/src/app/layout/vertical/layout-3/layout-3.component.html new file mode 100644 index 00000000..f6468ccc --- /dev/null +++ b/src/app/layout/vertical/layout-3/layout-3.component.html @@ -0,0 +1,100 @@ +
+ + + + + + + +
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + +
+ + + + + + + +
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + +
+
+ + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/app/layout/vertical/layout-3/layout-3.component.scss b/src/app/layout/vertical/layout-3/layout-3.component.scss new file mode 100644 index 00000000..295c20d7 --- /dev/null +++ b/src/app/layout/vertical/layout-3/layout-3.component.scss @@ -0,0 +1,55 @@ +@import "../../../../@fuse/scss/fuse"; + +vertical-layout-3 { + display: flex; + flex: 1 1 auto; + width: 100%; + height: 100%; + + #main { + position: relative; + display: flex; + flex: 1 1 auto; + flex-direction: column; + width: 100%; + height: 100%; + z-index: 1; + + // Boxed + &.boxed { + max-width: 1200px; + margin: 0 auto; + @include mat-elevation(8); + } + + // Container 1 (Scrollable) + > .container { + position: relative; + display: flex; + flex: 1 1 auto; + flex-direction: column; + width: 100%; + overflow-x: hidden; + overflow-y: auto; + transform: translateZ(0); + + // Container 2 + > .container { + position: relative; + display: flex; + flex: 1 0 auto; + width: 100%; + min-width: 0; + padding: 32px; + + // Content component + > content { + flex: 1 1 auto; + min-width: 0; + + @include mat-elevation(3); + } + } + } + } +} \ No newline at end of file diff --git a/src/app/layout/vertical/layout-3/layout-3.component.ts b/src/app/layout/vertical/layout-3/layout-3.component.ts new file mode 100644 index 00000000..d99091b4 --- /dev/null +++ b/src/app/layout/vertical/layout-3/layout-3.component.ts @@ -0,0 +1,64 @@ +import { Component, OnDestroy, OnInit, ViewEncapsulation } from '@angular/core'; +import { Subject } from 'rxjs'; +import { takeUntil } from 'rxjs/operators'; + +import { FuseConfigService } from '@fuse/services/config.service'; +import { navigation } from 'app/navigation/navigation'; + +@Component({ + selector : 'vertical-layout-3', + templateUrl : './layout-3.component.html', + styleUrls : ['./layout-3.component.scss'], + encapsulation: ViewEncapsulation.None +}) +export class VerticalLayout3Component implements OnInit, OnDestroy +{ + fuseConfig: any; + navigation: any; + + // Private + private _unsubscribeAll: Subject; + + /** + * Constructor + * + * @param {FuseConfigService} _fuseConfigService + */ + constructor( + private _fuseConfigService: FuseConfigService + ) + { + // Set the defaults + this.navigation = navigation; + + // Set the private defaults + this._unsubscribeAll = new Subject(); + } + + // ----------------------------------------------------------------------------------------------------- + // @ Lifecycle hooks + // ----------------------------------------------------------------------------------------------------- + + /** + * On init + */ + ngOnInit(): void + { + // Subscribe to config changes + this._fuseConfigService.config + .pipe(takeUntil(this._unsubscribeAll)) + .subscribe((config) => { + this.fuseConfig = config; + }); + } + + /** + * On destroy + */ + ngOnDestroy(): void + { + // Unsubscribe from all subscriptions + this._unsubscribeAll.next(); + this._unsubscribeAll.complete(); + } +} diff --git a/src/app/layout/vertical/layout-3/layout-3.module.ts b/src/app/layout/vertical/layout-3/layout-3.module.ts new file mode 100644 index 00000000..145b01cf --- /dev/null +++ b/src/app/layout/vertical/layout-3/layout-3.module.ts @@ -0,0 +1,37 @@ +import { NgModule } from '@angular/core'; +import { RouterModule } from '@angular/router'; + +import { FuseSidebarModule } from '@fuse/components/index'; +import { FuseSharedModule } from '@fuse/shared.module'; + +import { ContentModule } from 'app/layout/components/content/content.module'; +import { FooterModule } from 'app/layout/components/footer/footer.module'; +import { NavbarModule } from 'app/layout/components/navbar/navbar.module'; +import { QuickPanelModule } from 'app/layout/components/quick-panel/quick-panel.module'; +import { ToolbarModule } from 'app/layout/components/toolbar/toolbar.module'; + +import { VerticalLayout3Component } from 'app/layout/vertical/layout-3/layout-3.component'; + +@NgModule({ + declarations: [ + VerticalLayout3Component + ], + imports : [ + RouterModule, + + FuseSharedModule, + FuseSidebarModule, + + ContentModule, + FooterModule, + NavbarModule, + QuickPanelModule, + ToolbarModule + ], + exports : [ + VerticalLayout3Component + ] +}) +export class VerticalLayout3Module +{ +} diff --git a/src/app/main/angular-material-elements/angular-material-elements.component.ts b/src/app/main/angular-material-elements/angular-material-elements.component.ts new file mode 100644 index 00000000..2db4f309 --- /dev/null +++ b/src/app/main/angular-material-elements/angular-material-elements.component.ts @@ -0,0 +1,60 @@ +import { Component, OnDestroy, OnInit } from '@angular/core'; +import { ActivatedRoute } from '@angular/router'; +import { Subject } from 'rxjs'; +import { takeUntil } from 'rxjs/operators'; + +import { COMPONENT_MAP } from 'app/main/angular-material-elements/example-components'; + +@Component({ + selector : 'angular-material', + templateUrl: './angular-material-elements.component.html', + styleUrls : ['./angular-material-elements.component.scss'] +}) +export class AngularMaterialElementsComponent implements OnInit, OnDestroy +{ + id: string; + title: string; + examples: any; + + // Private + private _unsubscribeAll: Subject; + + /** + * Constructor + * + * @param {ActivatedRoute} _activatedRoute + */ + constructor( + private _activatedRoute: ActivatedRoute + ) + { + // Set the private defaults + this._unsubscribeAll = new Subject(); + } + + /** + * On init + */ + ngOnInit(): void + { + this._activatedRoute.params + .pipe(takeUntil(this._unsubscribeAll)) + .subscribe(params => { + this.id = params['id']; + const _title = this.id.replace('-', ' '); + this.title = _title.charAt(0).toUpperCase() + _title.substring(1); + this.examples = COMPONENT_MAP[this.id]; + }); + } + + /** + * On destroy + */ + ngOnDestroy(): void + { + // Unsubscribe from all subscriptions + this._unsubscribeAll.next(); + this._unsubscribeAll.complete(); + } +} + diff --git a/src/app/main/angular-material-elements/angular-material-elements.module.ts b/src/app/main/angular-material-elements/angular-material-elements.module.ts new file mode 100644 index 00000000..d4ac41b4 --- /dev/null +++ b/src/app/main/angular-material-elements/angular-material-elements.module.ts @@ -0,0 +1,45 @@ +import { NgModule } from '@angular/core'; +import { RouterModule, Routes } from '@angular/router'; + +import { FuseSharedModule } from '@fuse/shared.module'; +import { FuseHighlightModule } from '@fuse/components/index'; +import { FuseWidgetModule } from '@fuse/components/widget/widget.module'; + +import { MaterialModule } from 'app/main/angular-material-elements/material.module'; +import { EXAMPLE_LIST } from 'app/main/angular-material-elements/example-components'; +import { AngularMaterialElementsComponent } from 'app/main/angular-material-elements/angular-material-elements.component'; +import { ExampleViewerComponent } from 'app/main/angular-material-elements/example-viewer/example-viewer'; + +const routes: Routes = [ + { + path : '', + children: [ + { + path : ':id', + component: AngularMaterialElementsComponent + } + ] + } +]; + +@NgModule({ + declarations : [ + [...EXAMPLE_LIST], + AngularMaterialElementsComponent, + ExampleViewerComponent + ], + imports : [ + RouterModule.forChild(routes), + + MaterialModule, + + FuseSharedModule, + FuseHighlightModule, + FuseWidgetModule + ], + entryComponents: EXAMPLE_LIST, +}) +export class AngularMaterialElementsModule +{ +} + diff --git a/src/app/main/angular-material-elements/example-viewer/example-viewer.ts b/src/app/main/angular-material-elements/example-viewer/example-viewer.ts new file mode 100644 index 00000000..1f76b447 --- /dev/null +++ b/src/app/main/angular-material-elements/example-viewer/example-viewer.ts @@ -0,0 +1,152 @@ +import { AfterViewInit, Component, ComponentFactoryResolver, ComponentRef, Input, OnDestroy, ViewChild, ViewContainerRef, ViewEncapsulation } from '@angular/core'; +import { MatSnackBar } from '@angular/material'; +import 'prismjs/components/prism-scss'; +import 'prismjs/components/prism-typescript'; + +import { fuseAnimations } from '@fuse/animations/index'; +import { FuseCopierService } from '@fuse/services/copier.service'; + +import { EXAMPLE_COMPONENTS } from 'app/main/angular-material-elements/example-components'; + +export interface LiveExample +{ + title: string; + component: any; + additionalFiles?: string[]; + selectorName?: string; +} + +@Component({ + selector : 'example-viewer', + templateUrl : './example-viewer.html', + styleUrls : ['./example-viewer.scss'], + encapsulation: ViewEncapsulation.None, + animations : fuseAnimations +}) +export class ExampleViewerComponent implements AfterViewInit, OnDestroy +{ + _example: string; + exampleData: LiveExample; + showSource: boolean; + previewRef: ComponentRef; + selectedIndex: number; + + @ViewChild('previewContainer', {read: ViewContainerRef}) + private _previewContainer: ViewContainerRef; + + /** + * Constructor + * + * @param {MatSnackBar} _matSnackBar + * @param {FuseCopierService} _fuseCopierService + * @param {ComponentFactoryResolver} _componentFactoryResolver + */ + constructor( + private _matSnackBar: MatSnackBar, + private _fuseCopierService: FuseCopierService, + private _componentFactoryResolver: ComponentFactoryResolver + ) + { + // Set the defaults + this.selectedIndex = 0; + this.showSource = false; + } + + // ----------------------------------------------------------------------------------------------------- + // @ Accessors + // ----------------------------------------------------------------------------------------------------- + + /** + * Container + * + * @param {ViewContainerRef} value + */ + set container(value: ViewContainerRef) + { + this._previewContainer = value; + } + + get container(): ViewContainerRef + { + return this._previewContainer; + } + + /** + * Example + * + * @param {string} example + */ + @Input() + set example(example: string) + { + if ( example && EXAMPLE_COMPONENTS[example] ) + { + this._example = example; + this.exampleData = EXAMPLE_COMPONENTS[example]; + } + else + { + console.log('MISSING EXAMPLE: ', example); + } + } + + get example(): string + { + return this._example; + } + + // ----------------------------------------------------------------------------------------------------- + // @ Lifecycle hooks + // ----------------------------------------------------------------------------------------------------- + + /** + * After view init + */ + ngAfterViewInit(): void + { + setTimeout(() => { + const cmpFactory = this._componentFactoryResolver.resolveComponentFactory(this.exampleData.component); + this.previewRef = this._previewContainer.createComponent(cmpFactory); + }, 0); + } + + /** + * On destroy + */ + ngOnDestroy(): void + { + if ( this.previewRef ) + { + this.previewRef.destroy(); + } + } + + // ----------------------------------------------------------------------------------------------------- + // @ Public methods + // ----------------------------------------------------------------------------------------------------- + + /** + * Toggle source view + */ + toggleSourceView(): void + { + this.showSource = !this.showSource; + } + + /** + * Copy the source + * + * @param {string} text + */ + copySource(text: string): void + { + if ( this._fuseCopierService.copyText(text) ) + { + this._matSnackBar.open('Code copied', '', {duration: 2500}); + } + else + { + this._matSnackBar.open('Copy failed. Please try again!', '', {duration: 2500}); + } + } +} diff --git a/src/app/main/apps/academy/course/course.component.html b/src/app/main/apps/academy/course/course.component.html new file mode 100644 index 00000000..dcde06c5 --- /dev/null +++ b/src/app/main/apps/academy/course/course.component.html @@ -0,0 +1,97 @@ + diff --git a/src/app/main/apps/academy/course/course.component.ts b/src/app/main/apps/academy/course/course.component.ts new file mode 100644 index 00000000..c9d4af8f --- /dev/null +++ b/src/app/main/apps/academy/course/course.component.ts @@ -0,0 +1,162 @@ +import { AfterViewInit, ChangeDetectorRef, Component, OnDestroy, OnInit, QueryList, ViewChildren, ViewEncapsulation } from '@angular/core'; +import { Subject } from 'rxjs'; +import { takeUntil } from 'rxjs/operators'; + +import { fuseAnimations } from '@fuse/animations'; +import { FusePerfectScrollbarDirective } from '@fuse/directives/fuse-perfect-scrollbar/fuse-perfect-scrollbar.directive'; +import { FuseSidebarService } from '@fuse/components/sidebar/sidebar.service'; + +import { AcademyCourseService } from 'app/main/apps/academy/course.service'; + +@Component({ + selector : 'academy-course', + templateUrl : './course.component.html', + styleUrls : ['./course.component.scss'], + encapsulation: ViewEncapsulation.None, + animations : fuseAnimations +}) +export class AcademyCourseComponent implements OnInit, OnDestroy, AfterViewInit +{ + animationDirection: 'left' | 'right' | 'none'; + course: any; + courseStepContent: any; + currentStep: number; + + @ViewChildren(FusePerfectScrollbarDirective) + fuseScrollbarDirectives: QueryList; + + // Private + private _unsubscribeAll: Subject; + + /** + * Constructor + * + * @param {AcademyCourseService} _academyCourseService + * @param {ChangeDetectorRef} _changeDetectorRef + * @param {FuseSidebarService} _fuseSidebarService + */ + constructor( + private _academyCourseService: AcademyCourseService, + private _changeDetectorRef: ChangeDetectorRef, + private _fuseSidebarService: FuseSidebarService + ) + { + // Set the defaults + this.animationDirection = 'none'; + this.currentStep = 0; + + // Set the private defaults + this._unsubscribeAll = new Subject(); + } + + // ----------------------------------------------------------------------------------------------------- + // @ Lifecycle hooks + // ----------------------------------------------------------------------------------------------------- + + /** + * On init + */ + ngOnInit(): void + { + // Subscribe to courses + this._academyCourseService.onCourseChanged + .pipe(takeUntil(this._unsubscribeAll)) + .subscribe(course => { + this.course = course; + }); + } + + /** + * After view init + */ + ngAfterViewInit(): void + { + this.courseStepContent = this.fuseScrollbarDirectives.find((fuseScrollbarDirective) => { + return fuseScrollbarDirective.elementRef.nativeElement.id === 'course-step-content'; + }); + } + + /** + * On destroy + */ + ngOnDestroy(): void + { + // Unsubscribe from all subscriptions + this._unsubscribeAll.next(); + this._unsubscribeAll.complete(); + } + + // ----------------------------------------------------------------------------------------------------- + // @ Public methods + // ----------------------------------------------------------------------------------------------------- + + /** + * Go to step + * + * @param step + */ + gotoStep(step): void + { + // Decide the animation direction + this.animationDirection = this.currentStep < step ? 'left' : 'right'; + + // Run change detection so the change + // in the animation direction registered + this._changeDetectorRef.detectChanges(); + + // Set the current step + this.currentStep = step; + } + + /** + * Go to next step + */ + gotoNextStep(): void + { + if ( this.currentStep === this.course.totalSteps - 1 ) + { + return; + } + + // Set the animation direction + this.animationDirection = 'left'; + + // Run change detection so the change + // in the animation direction registered + this._changeDetectorRef.detectChanges(); + + // Increase the current step + this.currentStep++; + } + + /** + * Go to previous step + */ + gotoPreviousStep(): void + { + if ( this.currentStep === 0 ) + { + return; + } + + // Set the animation direction + this.animationDirection = 'right'; + + // Run change detection so the change + // in the animation direction registered + this._changeDetectorRef.detectChanges(); + + // Decrease the current step + this.currentStep--; + } + + /** + * Toggle the sidebar + * + * @param name + */ + toggleSidebar(name): void + { + this._fuseSidebarService.getSidebar(name).toggleOpen(); + } +} diff --git a/src/app/main/apps/academy/courses/courses.component.ts b/src/app/main/apps/academy/courses/courses.component.ts new file mode 100644 index 00000000..defd378d --- /dev/null +++ b/src/app/main/apps/academy/courses/courses.component.ts @@ -0,0 +1,126 @@ +import { Component, OnDestroy, OnInit } from '@angular/core'; +import { Subject } from 'rxjs'; +import { takeUntil } from 'rxjs/operators'; + +import { fuseAnimations } from '@fuse/animations'; + +import { AcademyCoursesService } from 'app/main/apps/academy/courses.service'; + +@Component({ + selector : 'academy-courses', + templateUrl: './courses.component.html', + styleUrls : ['./courses.component.scss'], + animations : fuseAnimations +}) +export class AcademyCoursesComponent implements OnInit, OnDestroy +{ + categories: any[]; + courses: any[]; + coursesFilteredByCategory: any[]; + filteredCourses: any[]; + currentCategory: string; + searchTerm: string; + + // Private + private _unsubscribeAll: Subject; + + /** + * Constructor + * + * @param {AcademyCoursesService} _academyCoursesService + */ + constructor( + private _academyCoursesService: AcademyCoursesService + ) + { + // Set the defaults + this.currentCategory = 'all'; + this.searchTerm = ''; + + // Set the private defaults + this._unsubscribeAll = new Subject(); + } + + // ----------------------------------------------------------------------------------------------------- + // @ Lifecycle hooks + // ----------------------------------------------------------------------------------------------------- + + /** + * On init + */ + ngOnInit(): void + { + // Subscribe to categories + this._academyCoursesService.onCategoriesChanged + .pipe(takeUntil(this._unsubscribeAll)) + .subscribe(categories => { + this.categories = categories; + }); + + // Subscribe to courses + this._academyCoursesService.onCoursesChanged + .pipe(takeUntil(this._unsubscribeAll)) + .subscribe(courses => { + this.filteredCourses = this.coursesFilteredByCategory = this.courses = courses; + }); + } + + /** + * On destroy + */ + ngOnDestroy(): void + { + // Unsubscribe from all subscriptions + this._unsubscribeAll.next(); + this._unsubscribeAll.complete(); + } + + // ----------------------------------------------------------------------------------------------------- + // @ Public methods + // ----------------------------------------------------------------------------------------------------- + + /** + * Filter courses by category + */ + filterCoursesByCategory(): void + { + // Filter + if ( this.currentCategory === 'all' ) + { + this.coursesFilteredByCategory = this.courses; + this.filteredCourses = this.courses; + } + else + { + this.coursesFilteredByCategory = this.courses.filter((course) => { + return course.category === this.currentCategory; + }); + + this.filteredCourses = [...this.coursesFilteredByCategory]; + + } + + // Re-filter by search term + this.filterCoursesByTerm(); + } + + /** + * Filter courses by term + */ + filterCoursesByTerm(): void + { + const searchTerm = this.searchTerm.toLowerCase(); + + // Search + if ( searchTerm === '' ) + { + this.filteredCourses = this.coursesFilteredByCategory; + } + else + { + this.filteredCourses = this.coursesFilteredByCategory.filter((course) => { + return course.title.toLowerCase().includes(searchTerm); + }); + } + } +} diff --git a/src/app/main/apps/apps.module.ts b/src/app/main/apps/apps.module.ts new file mode 100644 index 00000000..37e4ea28 --- /dev/null +++ b/src/app/main/apps/apps.module.ts @@ -0,0 +1,65 @@ +import { NgModule } from '@angular/core'; +import { RouterModule } from '@angular/router'; + +import { FuseSharedModule } from '@fuse/shared.module'; + +const routes = [ + { + path : 'dashboards/analytics', + loadChildren: './dashboards/analytics/analytics.module#AnalyticsDashboardModule' + }, + { + path : 'dashboards/project', + loadChildren: './dashboards/project/project.module#ProjectDashboardModule' + }, + { + path : 'mail', + loadChildren: './mail/mail.module#MailModule' + }, + { + path : 'mail-ngrx', + loadChildren: './mail-ngrx/mail.module#MailNgrxModule' + }, + { + path : 'chat', + loadChildren: './chat/chat.module#ChatModule' + }, + { + path : 'calendar', + loadChildren: './calendar/calendar.module#CalendarModule' + }, + { + path : 'e-commerce', + loadChildren: './e-commerce/e-commerce.module#EcommerceModule' + }, + { + path : 'academy', + loadChildren: './academy/academy.module#AcademyModule' + }, + { + path : 'todo', + loadChildren: './todo/todo.module#TodoModule' + }, + { + path : 'file-manager', + loadChildren: './file-manager/file-manager.module#FileManagerModule' + }, + { + path : 'contacts', + loadChildren: './contacts/contacts.module#ContactsModule' + }, + { + path : 'scrumboard', + loadChildren: './scrumboard/scrumboard.module#ScrumboardModule' + } +]; + +@NgModule({ + imports : [ + RouterModule.forChild(routes), + FuseSharedModule + ] +}) +export class AppsModule +{ +} diff --git a/src/app/main/apps/chat/chat-start/chat-start.component.html b/src/app/main/apps/chat/chat-start/chat-start.component.html new file mode 100644 index 00000000..9415f0c2 --- /dev/null +++ b/src/app/main/apps/chat/chat-start/chat-start.component.html @@ -0,0 +1,20 @@ +
+ + + + Chat App + + + Select contact to start the chat!.. + + + + +
diff --git a/src/app/main/apps/chat/chat-view/chat-view.component.ts b/src/app/main/apps/chat/chat-view/chat-view.component.ts new file mode 100644 index 00000000..4f40e8fe --- /dev/null +++ b/src/app/main/apps/chat/chat-view/chat-view.component.ts @@ -0,0 +1,164 @@ +import { AfterViewInit, Component, OnDestroy, OnInit, ViewChild, ViewChildren } from '@angular/core'; +import { NgForm } from '@angular/forms'; +import { Subject } from 'rxjs'; +import { takeUntil } from 'rxjs/operators'; + +import { FusePerfectScrollbarDirective } from '@fuse/directives/fuse-perfect-scrollbar/fuse-perfect-scrollbar.directive'; + +import { ChatService } from 'app/main/apps/chat/chat.service'; + +@Component({ + selector : 'chat-view', + templateUrl: './chat-view.component.html', + styleUrls : ['./chat-view.component.scss'] +}) +export class ChatViewComponent implements OnInit, OnDestroy, AfterViewInit +{ + user: any; + chat: any; + dialog: any; + contact: any; + replyInput: any; + selectedChat: any; + + @ViewChild(FusePerfectScrollbarDirective) + directiveScroll: FusePerfectScrollbarDirective; + + @ViewChildren('replyInput') + replyInputField; + + @ViewChild('replyForm') + replyForm: NgForm; + + // Private + private _unsubscribeAll: Subject; + + /** + * Constructor + * + * @param {ChatService} _chatService + */ + constructor( + private _chatService: ChatService + ) + { + // Set the private defaults + this._unsubscribeAll = new Subject(); + } + + // ----------------------------------------------------------------------------------------------------- + // @ Lifecycle hooks + // ----------------------------------------------------------------------------------------------------- + + /** + * On init + */ + ngOnInit(): void + { + this.user = this._chatService.user; + this._chatService.onChatSelected + .pipe(takeUntil(this._unsubscribeAll)) + .subscribe(chatData => { + if ( chatData ) + { + this.selectedChat = chatData; + this.contact = chatData.contact; + this.dialog = chatData.dialog; + this.readyToReply(); + } + }); + } + + /** + * After view init + */ + ngAfterViewInit(): void + { + this.replyInput = this.replyInputField.first.nativeElement; + this.readyToReply(); + } + + /** + * On destroy + */ + ngOnDestroy(): void + { + // Unsubscribe from all subscriptions + this._unsubscribeAll.next(); + this._unsubscribeAll.complete(); + } + + // ----------------------------------------------------------------------------------------------------- + // @ Public methods + // ----------------------------------------------------------------------------------------------------- + + /** + * Select contact + */ + selectContact(): void + { + this._chatService.selectContact(this.contact); + } + + /** + * Ready to reply + */ + readyToReply(): void + { + setTimeout(() => { + this.replyForm.reset(); + this.focusReplyInput(); + this.scrollToBottom(); + }); + + } + + /** + * Focus to the reply input + */ + focusReplyInput(): void + { + setTimeout(() => { + this.replyInput.focus(); + }); + } + + /** + * Scroll to the bottom + * + * @param {number} speed + */ + scrollToBottom(speed?: number): void + { + speed = speed || 400; + if ( this.directiveScroll ) + { + this.directiveScroll.update(); + + setTimeout(() => { + this.directiveScroll.scrollToBottom(0, speed); + }); + } + } + + /** + * Reply + */ + reply(): void + { + // Message + const message = { + who : this.user.id, + message: this.replyForm.form.value.message, + time : new Date().toISOString() + }; + + // Add the message to the chat + this.dialog.push(message); + + // Update the server + this._chatService.updateDialog(this.selectedChat.chatId, this.dialog).then(response => { + this.readyToReply(); + }); + } +} diff --git a/src/app/main/apps/chat/chat.component.ts b/src/app/main/apps/chat/chat.component.ts new file mode 100644 index 00000000..fba6d3cb --- /dev/null +++ b/src/app/main/apps/chat/chat.component.ts @@ -0,0 +1,61 @@ +import { Component, OnDestroy, OnInit, ViewEncapsulation } from '@angular/core'; +import { Subject } from 'rxjs'; +import { takeUntil } from 'rxjs/operators'; + +import { fuseAnimations } from '@fuse/animations'; + +import { ChatService } from 'app/main/apps/chat/chat.service'; + +@Component({ + selector : 'chat', + templateUrl : './chat.component.html', + styleUrls : ['./chat.component.scss'], + encapsulation: ViewEncapsulation.None, + animations : fuseAnimations +}) +export class ChatComponent implements OnInit, OnDestroy +{ + selectedChat: any; + + // Private + private _unsubscribeAll: Subject; + + /** + * Constructor + * + * @param {ChatService} _chatService + */ + constructor( + private _chatService: ChatService + ) + { + // Set the private defaults + this._unsubscribeAll = new Subject(); + } + + // ----------------------------------------------------------------------------------------------------- + // @ Lifecycle hooks + // ----------------------------------------------------------------------------------------------------- + + /** + * On init + */ + ngOnInit(): void + { + this._chatService.onChatSelected + .pipe(takeUntil(this._unsubscribeAll)) + .subscribe(chatData => { + this.selectedChat = chatData; + }); + } + + /** + * On destroy + */ + ngOnDestroy(): void + { + // Unsubscribe from all subscriptions + this._unsubscribeAll.next(); + this._unsubscribeAll.complete(); + } +} diff --git a/src/app/main/apps/chat/chat.module.ts b/src/app/main/apps/chat/chat.module.ts new file mode 100644 index 00000000..a54b46e5 --- /dev/null +++ b/src/app/main/apps/chat/chat.module.ts @@ -0,0 +1,62 @@ +import { NgModule } from '@angular/core'; +import { RouterModule, Routes } from '@angular/router'; + +import { MatButtonModule, MatCardModule, MatFormFieldModule, MatIconModule, MatInputModule, MatListModule, MatMenuModule, MatRadioModule, MatSidenavModule, MatToolbarModule } from '@angular/material'; + +import { FuseSharedModule } from '@fuse/shared.module'; + +import { ChatService } from 'app/main/apps/chat/chat.service'; +import { ChatComponent } from 'app/main/apps/chat/chat.component'; +import { ChatStartComponent } from 'app/main/apps/chat/chat-start/chat-start.component'; +import { ChatViewComponent } from 'app/main/apps/chat/chat-view/chat-view.component'; +import { ChatChatsSidenavComponent } from 'app/main/apps/chat/sidenavs/left/chats/chats.component'; +import { ChatUserSidenavComponent } from 'app/main/apps/chat/sidenavs/left/user/user.component'; +import { ChatLeftSidenavComponent } from 'app/main/apps/chat/sidenavs/left/left.component'; +import { ChatRightSidenavComponent } from 'app/main/apps/chat/sidenavs/right/right.component'; +import { ChatContactSidenavComponent } from 'app/main/apps/chat/sidenavs/right/contact/contact.component'; + +const routes: Routes = [ + { + path : '**', + component: ChatComponent, + children : [], + resolve : { + chat: ChatService + } + } +]; + +@NgModule({ + declarations: [ + ChatComponent, + ChatViewComponent, + ChatStartComponent, + ChatChatsSidenavComponent, + ChatUserSidenavComponent, + ChatLeftSidenavComponent, + ChatRightSidenavComponent, + ChatContactSidenavComponent + ], + imports : [ + RouterModule.forChild(routes), + + MatButtonModule, + MatCardModule, + MatFormFieldModule, + MatIconModule, + MatInputModule, + MatListModule, + MatMenuModule, + MatRadioModule, + MatSidenavModule, + MatToolbarModule, + + FuseSharedModule + ], + providers : [ + ChatService + ] +}) +export class ChatModule +{ +} diff --git a/src/app/main/apps/chat/sidenavs/left/chats/chats.component.ts b/src/app/main/apps/chat/sidenavs/left/chats/chats.component.ts new file mode 100644 index 00000000..98a8c3a6 --- /dev/null +++ b/src/app/main/apps/chat/sidenavs/left/chats/chats.component.ts @@ -0,0 +1,133 @@ +import { Component, OnDestroy, OnInit } from '@angular/core'; +import { ObservableMedia } from '@angular/flex-layout'; +import { Subject } from 'rxjs'; +import { takeUntil } from 'rxjs/operators'; + +import { fuseAnimations } from '@fuse/animations'; +import { FuseMatSidenavHelperService } from '@fuse/directives/fuse-mat-sidenav/fuse-mat-sidenav.service'; + +import { ChatService } from 'app/main/apps/chat/chat.service'; + +@Component({ + selector : 'chat-chats-sidenav', + templateUrl: './chats.component.html', + styleUrls : ['./chats.component.scss'], + animations : fuseAnimations +}) +export class ChatChatsSidenavComponent implements OnInit, OnDestroy +{ + chats: any[]; + chatSearch: any; + contacts: any[]; + searchText: string; + user: any; + + // Private + private _unsubscribeAll: Subject; + + /** + * Constructor + * + * @param {ChatService} _chatService + * @param {FuseMatSidenavHelperService} _fuseMatSidenavHelperService + * @param {ObservableMedia} _observableMedia + */ + constructor( + private _chatService: ChatService, + private _fuseMatSidenavHelperService: FuseMatSidenavHelperService, + public _observableMedia: ObservableMedia + ) + { + // Set the defaults + this.chatSearch = { + name: '' + }; + this.searchText = ''; + + // Set the private defaults + this._unsubscribeAll = new Subject(); + } + + // ----------------------------------------------------------------------------------------------------- + // @ Lifecycle hooks + // ----------------------------------------------------------------------------------------------------- + + /** + * On init + */ + ngOnInit(): void + { + this.user = this._chatService.user; + this.chats = this._chatService.chats; + this.contacts = this._chatService.contacts; + + this._chatService.onChatsUpdated + .pipe(takeUntil(this._unsubscribeAll)) + .subscribe(updatedChats => { + this.chats = updatedChats; + }); + + this._chatService.onUserUpdated + .pipe(takeUntil(this._unsubscribeAll)) + .subscribe(updatedUser => { + this.user = updatedUser; + }); + } + + /** + * On destroy + */ + ngOnDestroy(): void + { + // Unsubscribe from all subscriptions + this._unsubscribeAll.next(); + this._unsubscribeAll.complete(); + } + + // ----------------------------------------------------------------------------------------------------- + // @ Public methods + // ----------------------------------------------------------------------------------------------------- + + /** + * Get chat + * + * @param contact + */ + getChat(contact): void + { + this._chatService.getChat(contact); + + if ( !this._observableMedia.isActive('gt-md') ) + { + this._fuseMatSidenavHelperService.getSidenav('chat-left-sidenav').toggle(); + } + } + + /** + * Set user status + * + * @param status + */ + setUserStatus(status): void + { + this._chatService.setUserStatus(status); + } + + /** + * Change left sidenav view + * + * @param view + */ + changeLeftSidenavView(view): void + { + this._chatService.onLeftSidenavViewChanged.next(view); + } + + /** + * Logout + */ + logout(): void + { + console.log('logout triggered'); + } +} diff --git a/src/app/main/apps/chat/sidenavs/left/left.component.html b/src/app/main/apps/chat/sidenavs/left/left.component.html new file mode 100644 index 00000000..5fdf0436 --- /dev/null +++ b/src/app/main/apps/chat/sidenavs/left/left.component.html @@ -0,0 +1,12 @@ +
+ + + + + +
diff --git a/src/app/main/apps/chat/sidenavs/left/left.component.ts b/src/app/main/apps/chat/sidenavs/left/left.component.ts new file mode 100644 index 00000000..a3f988a3 --- /dev/null +++ b/src/app/main/apps/chat/sidenavs/left/left.component.ts @@ -0,0 +1,63 @@ +import { Component, OnDestroy, OnInit } from '@angular/core'; +import { Subject } from 'rxjs'; +import { takeUntil } from 'rxjs/operators'; + +import { fuseAnimations } from '@fuse/animations'; + +import { ChatService } from 'app/main/apps/chat/chat.service'; + +@Component({ + selector : 'chat-left-sidenav', + templateUrl: './left.component.html', + styleUrls : ['./left.component.scss'], + animations : fuseAnimations +}) +export class ChatLeftSidenavComponent implements OnInit, OnDestroy +{ + view: string; + + // Private + private _unsubscribeAll: Subject; + + /** + * Constructor + * + * @param {ChatService} _chatService + */ + constructor( + private _chatService: ChatService + ) + { + // Set the defaults + this.view = 'chats'; + + // Set the private defaults + this._unsubscribeAll = new Subject(); + } + + // ----------------------------------------------------------------------------------------------------- + // @ Lifecycle hooks + // ----------------------------------------------------------------------------------------------------- + + /** + * On init + */ + ngOnInit(): void + { + this._chatService.onLeftSidenavViewChanged + .pipe(takeUntil(this._unsubscribeAll)) + .subscribe(view => { + this.view = view; + }); + } + + /** + * On destroy + */ + ngOnDestroy(): void + { + // Unsubscribe from all subscriptions + this._unsubscribeAll.next(); + this._unsubscribeAll.complete(); + } +} diff --git a/src/app/main/apps/chat/sidenavs/left/user/user.component.ts b/src/app/main/apps/chat/sidenavs/left/user/user.component.ts new file mode 100644 index 00000000..8cbf54e1 --- /dev/null +++ b/src/app/main/apps/chat/sidenavs/left/user/user.component.ts @@ -0,0 +1,87 @@ +import { Component, OnDestroy, OnInit } from '@angular/core'; +import { FormControl, FormGroup } from '@angular/forms'; +import { Subject } from 'rxjs'; +import { debounceTime, distinctUntilChanged, takeUntil } from 'rxjs/operators'; + +import { ChatService } from 'app/main/apps/chat/chat.service'; + +@Component({ + selector : 'chat-user-sidenav', + templateUrl: './user.component.html', + styleUrls : ['./user.component.scss'] +}) +export class ChatUserSidenavComponent implements OnInit, OnDestroy +{ + user: any; + userForm: FormGroup; + + // Private + private _unsubscribeAll: Subject; + + /** + * Constructor + * + * @param {ChatService} _chatService + */ + constructor( + private _chatService: ChatService + ) + { + // Set the private defaults + this._unsubscribeAll = new Subject(); + } + + // ----------------------------------------------------------------------------------------------------- + // @ Lifecycle hooks + // ----------------------------------------------------------------------------------------------------- + + /** + * On init + */ + ngOnInit(): void + { + this.user = this._chatService.user; + + this.userForm = new FormGroup({ + mood : new FormControl(this.user.mood), + status: new FormControl(this.user.status) + }); + + this.userForm.valueChanges + .pipe( + takeUntil(this._unsubscribeAll), + debounceTime(500), + distinctUntilChanged() + ) + .subscribe(data => { + this.user.mood = data.mood; + this.user.status = data.status; + this._chatService.updateUserData(this.user); + }); + } + + /** + * On destroy + */ + ngOnDestroy(): void + { + // Unsubscribe from all subscriptions + this._unsubscribeAll.next(); + this._unsubscribeAll.complete(); + } + + // ----------------------------------------------------------------------------------------------------- + // @ Public methods + // ----------------------------------------------------------------------------------------------------- + + /** + * Change left sidenav view + * + * @param view + */ + changeLeftSidenavView(view): void + { + this._chatService.onLeftSidenavViewChanged.next(view); + } + +} diff --git a/src/app/main/apps/chat/sidenavs/right/contact/contact.component.ts b/src/app/main/apps/chat/sidenavs/right/contact/contact.component.ts new file mode 100644 index 00000000..85f25438 --- /dev/null +++ b/src/app/main/apps/chat/sidenavs/right/contact/contact.component.ts @@ -0,0 +1,57 @@ +import { Component, OnDestroy, OnInit } from '@angular/core'; +import { Subject } from 'rxjs'; +import { takeUntil } from 'rxjs/operators'; + +import { ChatService } from 'app/main/apps/chat/chat.service'; + +@Component({ + selector : 'chat-contact-sidenav', + templateUrl: './contact.component.html', + styleUrls : ['./contact.component.scss'] +}) +export class ChatContactSidenavComponent implements OnInit, OnDestroy +{ + contact: any; + + // Private + private _unsubscribeAll: Subject; + + /** + * Constructor + * + * @param {ChatService} _chatService + */ + constructor( + private _chatService: ChatService + ) + { + // Set the private defaults + this._unsubscribeAll = new Subject(); + } + + // ----------------------------------------------------------------------------------------------------- + // @ Lifecycle hooks + // ----------------------------------------------------------------------------------------------------- + + /** + * On init + */ + ngOnInit(): void + { + this._chatService.onContactSelected + .pipe(takeUntil(this._unsubscribeAll)) + .subscribe(contact => { + this.contact = contact; + }); + } + + /** + * On destroy + */ + ngOnDestroy(): void + { + // Unsubscribe from all subscriptions + this._unsubscribeAll.next(); + this._unsubscribeAll.complete(); + } +} diff --git a/src/app/main/apps/chat/sidenavs/right/right.component.html b/src/app/main/apps/chat/sidenavs/right/right.component.html new file mode 100644 index 00000000..e6817050 --- /dev/null +++ b/src/app/main/apps/chat/sidenavs/right/right.component.html @@ -0,0 +1,9 @@ +
+ + + + +
diff --git a/src/app/main/apps/chat/sidenavs/right/right.component.ts b/src/app/main/apps/chat/sidenavs/right/right.component.ts new file mode 100644 index 00000000..cb08c0c6 --- /dev/null +++ b/src/app/main/apps/chat/sidenavs/right/right.component.ts @@ -0,0 +1,59 @@ +import { Component, OnDestroy, OnInit } from '@angular/core'; +import { Subject } from 'rxjs'; +import { takeUntil } from 'rxjs/operators'; + +import { fuseAnimations } from '@fuse/animations'; + +import { ChatService } from 'app/main/apps/chat/chat.service'; + +@Component({ + selector : 'chat-right-sidenav', + templateUrl: './right.component.html', + styleUrls : ['./right.component.scss'], + animations : fuseAnimations +}) +export class ChatRightSidenavComponent implements OnInit, OnDestroy +{ + view: string; + + // Private + private _unsubscribeAll: Subject; + + constructor( + private _chatService: ChatService + ) + { + // Set the defaults + this.view = 'contact'; + + // Set the private defaults + this._unsubscribeAll = new Subject(); + } + + // ----------------------------------------------------------------------------------------------------- + // @ Lifecycle hooks + // ----------------------------------------------------------------------------------------------------- + + /** + * On init + */ + ngOnInit(): void + { + this._chatService.onRightSidenavViewChanged + .pipe(takeUntil(this._unsubscribeAll)) + .subscribe(view => { + this.view = view; + }); + } + + /** + * On destroy + */ + ngOnDestroy(): void + { + // Unsubscribe from all subscriptions + this._unsubscribeAll.next(); + this._unsubscribeAll.complete(); + } + +} diff --git a/src/app/main/apps/contacts/contact-list/contact-list.component.ts b/src/app/main/apps/contacts/contact-list/contact-list.component.ts new file mode 100644 index 00000000..2443be7a --- /dev/null +++ b/src/app/main/apps/contacts/contact-list/contact-list.component.ts @@ -0,0 +1,242 @@ +import { Component, OnDestroy, OnInit, TemplateRef, ViewChild, ViewEncapsulation } from '@angular/core'; +import { FormGroup } from '@angular/forms'; +import { MatDialog, MatDialogRef } from '@angular/material'; +import { DataSource } from '@angular/cdk/collections'; +import { Observable, Subject } from 'rxjs'; +import { takeUntil } from 'rxjs/operators'; + +import { fuseAnimations } from '@fuse/animations'; +import { FuseConfirmDialogComponent } from '@fuse/components/confirm-dialog/confirm-dialog.component'; + +import { ContactsService } from 'app/main/apps/contacts/contacts.service'; +import { ContactsContactFormDialogComponent } from 'app/main/apps/contacts/contact-form/contact-form.component'; + +@Component({ + selector : 'contacts-contact-list', + templateUrl : './contact-list.component.html', + styleUrls : ['./contact-list.component.scss'], + encapsulation: ViewEncapsulation.None, + animations : fuseAnimations +}) +export class ContactsContactListComponent implements OnInit, OnDestroy +{ + @ViewChild('dialogContent') + dialogContent: TemplateRef; + + contacts: any; + user: any; + dataSource: FilesDataSource | null; + displayedColumns = ['checkbox', 'avatar', 'name', 'email', 'phone', 'jobTitle', 'buttons']; + selectedContacts: any[]; + checkboxes: {}; + dialogRef: any; + confirmDialogRef: MatDialogRef; + + // Private + private _unsubscribeAll: Subject; + + /** + * Constructor + * + * @param {ContactsService} _contactsService + * @param {MatDialog} _matDialog + */ + constructor( + private _contactsService: ContactsService, + public _matDialog: MatDialog + ) + { + // Set the private defaults + this._unsubscribeAll = new Subject(); + } + + // ----------------------------------------------------------------------------------------------------- + // @ Lifecycle hooks + // ----------------------------------------------------------------------------------------------------- + + /** + * On init + */ + ngOnInit(): void + { + this.dataSource = new FilesDataSource(this._contactsService); + + this._contactsService.onContactsChanged + .pipe(takeUntil(this._unsubscribeAll)) + .subscribe(contacts => { + this.contacts = contacts; + + this.checkboxes = {}; + contacts.map(contact => { + this.checkboxes[contact.id] = false; + }); + }); + + this._contactsService.onSelectedContactsChanged + .pipe(takeUntil(this._unsubscribeAll)) + .subscribe(selectedContacts => { + for ( const id in this.checkboxes ) + { + if ( !this.checkboxes.hasOwnProperty(id) ) + { + continue; + } + + this.checkboxes[id] = selectedContacts.includes(id); + } + this.selectedContacts = selectedContacts; + }); + + this._contactsService.onUserDataChanged + .pipe(takeUntil(this._unsubscribeAll)) + .subscribe(user => { + this.user = user; + }); + + this._contactsService.onFilterChanged + .pipe(takeUntil(this._unsubscribeAll)) + .subscribe(() => { + this._contactsService.deselectContacts(); + }); + } + + /** + * On destroy + */ + ngOnDestroy(): void + { + // Unsubscribe from all subscriptions + this._unsubscribeAll.next(); + this._unsubscribeAll.complete(); + } + + // ----------------------------------------------------------------------------------------------------- + // @ Public methods + // ----------------------------------------------------------------------------------------------------- + + /** + * Edit contact + * + * @param contact + */ + editContact(contact): void + { + this.dialogRef = this._matDialog.open(ContactsContactFormDialogComponent, { + panelClass: 'contact-form-dialog', + data : { + contact: contact, + action : 'edit' + } + }); + + this.dialogRef.afterClosed() + .subscribe(response => { + if ( !response ) + { + return; + } + const actionType: string = response[0]; + const formData: FormGroup = response[1]; + switch ( actionType ) + { + /** + * Save + */ + case 'save': + + this._contactsService.updateContact(formData.getRawValue()); + + break; + /** + * Delete + */ + case 'delete': + + this.deleteContact(contact); + + break; + } + }); + } + + /** + * Delete Contact + */ + deleteContact(contact): void + { + this.confirmDialogRef = this._matDialog.open(FuseConfirmDialogComponent, { + disableClose: false + }); + + this.confirmDialogRef.componentInstance.confirmMessage = 'Are you sure you want to delete?'; + + this.confirmDialogRef.afterClosed().subscribe(result => { + if ( result ) + { + this._contactsService.deleteContact(contact); + } + this.confirmDialogRef = null; + }); + + } + + /** + * On selected change + * + * @param contactId + */ + onSelectedChange(contactId): void + { + this._contactsService.toggleSelectedContact(contactId); + } + + /** + * Toggle star + * + * @param contactId + */ + toggleStar(contactId): void + { + if ( this.user.starred.includes(contactId) ) + { + this.user.starred.splice(this.user.starred.indexOf(contactId), 1); + } + else + { + this.user.starred.push(contactId); + } + + this._contactsService.updateUserData(this.user); + } +} + +export class FilesDataSource extends DataSource +{ + /** + * Constructor + * + * @param {ContactsService} _contactsService + */ + constructor( + private _contactsService: ContactsService + ) + { + super(); + } + + /** + * Connect function called by the table to retrieve one stream containing the data to render. + * @returns {Observable} + */ + connect(): Observable + { + return this._contactsService.onContactsChanged; + } + + /** + * Disconnect + */ + disconnect(): void + { + } +} diff --git a/src/app/main/apps/contacts/contacts.component.scss b/src/app/main/apps/contacts/contacts.component.scss new file mode 100644 index 00000000..cb752a8d --- /dev/null +++ b/src/app/main/apps/contacts/contacts.component.scss @@ -0,0 +1,13 @@ +#contacts { + + .content { + overflow: hidden; + + .sidebar { + + &:not(.locked-open) { + background: white; + } + } + } +} \ No newline at end of file diff --git a/src/app/main/apps/contacts/contacts.component.ts b/src/app/main/apps/contacts/contacts.component.ts new file mode 100644 index 00000000..9315110d --- /dev/null +++ b/src/app/main/apps/contacts/contacts.component.ts @@ -0,0 +1,121 @@ +import { Component, OnDestroy, OnInit, ViewEncapsulation } from '@angular/core'; +import { FormControl, FormGroup } from '@angular/forms'; +import { MatDialog } from '@angular/material'; +import { Subject } from 'rxjs'; +import { debounceTime, distinctUntilChanged, takeUntil } from 'rxjs/operators'; + +import { fuseAnimations } from '@fuse/animations'; +import { FuseSidebarService } from '@fuse/components/sidebar/sidebar.service'; + +import { ContactsService } from 'app/main/apps/contacts/contacts.service'; +import { ContactsContactFormDialogComponent } from 'app/main/apps/contacts/contact-form/contact-form.component'; + +@Component({ + selector : 'contacts', + templateUrl : './contacts.component.html', + styleUrls : ['./contacts.component.scss'], + encapsulation: ViewEncapsulation.None, + animations : fuseAnimations +}) +export class ContactsComponent implements OnInit, OnDestroy +{ + dialogRef: any; + hasSelectedContacts: boolean; + searchInput: FormControl; + + // Private + private _unsubscribeAll: Subject; + + /** + * Constructor + * + * @param {ContactsService} _contactsService + * @param {FuseSidebarService} _fuseSidebarService + * @param {MatDialog} _matDialog + */ + constructor( + private _contactsService: ContactsService, + private _fuseSidebarService: FuseSidebarService, + private _matDialog: MatDialog + ) + { + // Set the defaults + this.searchInput = new FormControl(''); + + // Set the private defaults + this._unsubscribeAll = new Subject(); + } + + // ----------------------------------------------------------------------------------------------------- + // @ Lifecycle hooks + // ----------------------------------------------------------------------------------------------------- + + /** + * On init + */ + ngOnInit(): void + { + this._contactsService.onSelectedContactsChanged + .pipe(takeUntil(this._unsubscribeAll)) + .subscribe(selectedContacts => { + this.hasSelectedContacts = selectedContacts.length > 0; + }); + + this.searchInput.valueChanges + .pipe( + takeUntil(this._unsubscribeAll), + debounceTime(300), + distinctUntilChanged() + ) + .subscribe(searchText => { + this._contactsService.onSearchTextChanged.next(searchText); + }); + } + + /** + * On destroy + */ + ngOnDestroy(): void + { + // Unsubscribe from all subscriptions + this._unsubscribeAll.next(); + this._unsubscribeAll.complete(); + } + + // ----------------------------------------------------------------------------------------------------- + // @ Public methods + // ----------------------------------------------------------------------------------------------------- + + /** + * New contact + */ + newContact(): void + { + this.dialogRef = this._matDialog.open(ContactsContactFormDialogComponent, { + panelClass: 'contact-form-dialog', + data : { + action: 'new' + } + }); + + this.dialogRef.afterClosed() + .subscribe((response: FormGroup) => { + if ( !response ) + { + return; + } + + this._contactsService.updateContact(response.getRawValue()); + }); + } + + /** + * Toggle the sidebar + * + * @param name + */ + toggleSidebar(name): void + { + this._fuseSidebarService.getSidebar(name).toggleOpen(); + } +} diff --git a/src/app/main/apps/contacts/contacts.module.ts b/src/app/main/apps/contacts/contacts.module.ts new file mode 100644 index 00000000..39a71560 --- /dev/null +++ b/src/app/main/apps/contacts/contacts.module.ts @@ -0,0 +1,63 @@ +import { NgModule } from '@angular/core'; +import { RouterModule, Routes } from '@angular/router'; +import { CdkTableModule } from '@angular/cdk/table'; + +import { MatButtonModule, MatCheckboxModule, MatDatepickerModule, MatFormFieldModule, MatIconModule, MatInputModule, MatMenuModule, MatRippleModule, MatTableModule, MatToolbarModule } from '@angular/material'; + +import { FuseSharedModule } from '@fuse/shared.module'; +import { FuseConfirmDialogModule, FuseSidebarModule } from '@fuse/components'; + +import { ContactsComponent } from 'app/main/apps/contacts/contacts.component'; +import { ContactsService } from 'app/main/apps/contacts/contacts.service'; +import { ContactsContactListComponent } from 'app/main/apps/contacts/contact-list/contact-list.component'; +import { ContactsSelectedBarComponent } from 'app/main/apps/contacts/selected-bar/selected-bar.component'; +import { ContactsMainSidebarComponent } from 'app/main/apps/contacts/sidebars/main/main.component'; +import { ContactsContactFormDialogComponent } from 'app/main/apps/contacts/contact-form/contact-form.component'; + +const routes: Routes = [ + { + path : '**', + component: ContactsComponent, + resolve : { + contacts: ContactsService + } + } +]; + +@NgModule({ + declarations : [ + ContactsComponent, + ContactsContactListComponent, + ContactsSelectedBarComponent, + ContactsMainSidebarComponent, + ContactsContactFormDialogComponent + ], + imports : [ + RouterModule.forChild(routes), + CdkTableModule, + + MatButtonModule, + MatCheckboxModule, + MatDatepickerModule, + MatFormFieldModule, + MatIconModule, + MatInputModule, + MatMenuModule, + MatRippleModule, + MatTableModule, + MatToolbarModule, + + FuseSharedModule, + FuseConfirmDialogModule, + FuseSidebarModule + ], + providers : [ + ContactsService + ], + entryComponents: [ + ContactsContactFormDialogComponent + ] +}) +export class ContactsModule +{ +} diff --git a/src/app/main/apps/contacts/selected-bar/selected-bar.component.ts b/src/app/main/apps/contacts/selected-bar/selected-bar.component.ts new file mode 100644 index 00000000..fa499a69 --- /dev/null +++ b/src/app/main/apps/contacts/selected-bar/selected-bar.component.ts @@ -0,0 +1,110 @@ +import { Component, OnDestroy, OnInit } from '@angular/core'; +import { MatDialog, MatDialogRef } from '@angular/material'; +import { Subject } from 'rxjs'; +import { takeUntil } from 'rxjs/operators'; + +import { FuseConfirmDialogComponent } from '@fuse/components/confirm-dialog/confirm-dialog.component'; + +import { ContactsService } from 'app/main/apps/contacts/contacts.service'; + +@Component({ + selector : 'selected-bar', + templateUrl: './selected-bar.component.html', + styleUrls : ['./selected-bar.component.scss'] +}) +export class ContactsSelectedBarComponent implements OnInit, OnDestroy +{ + confirmDialogRef: MatDialogRef; + hasSelectedContacts: boolean; + isIndeterminate: boolean; + selectedContacts: string[]; + + // Private + private _unsubscribeAll: Subject; + + /** + * Constructor + * + * @param {ContactsService} _contactsService + * @param {MatDialog} _matDialog + */ + constructor( + private _contactsService: ContactsService, + public _matDialog: MatDialog + ) + { + // Set the private defaults + this._unsubscribeAll = new Subject(); + } + + // ----------------------------------------------------------------------------------------------------- + // @ Lifecycle hooks + // ----------------------------------------------------------------------------------------------------- + + /** + * On init + */ + ngOnInit(): void + { + this._contactsService.onSelectedContactsChanged + .pipe(takeUntil(this._unsubscribeAll)) + .subscribe(selectedContacts => { + this.selectedContacts = selectedContacts; + setTimeout(() => { + this.hasSelectedContacts = selectedContacts.length > 0; + this.isIndeterminate = (selectedContacts.length !== this._contactsService.contacts.length && selectedContacts.length > 0); + }, 0); + }); + } + + /** + * On destroy + */ + ngOnDestroy(): void + { + // Unsubscribe from all subscriptions + this._unsubscribeAll.next(); + this._unsubscribeAll.complete(); + } + + // ----------------------------------------------------------------------------------------------------- + // @ Public methods + // ----------------------------------------------------------------------------------------------------- + + /** + * Select all + */ + selectAll(): void + { + this._contactsService.selectContacts(); + } + + /** + * Deselect all + */ + deselectAll(): void + { + this._contactsService.deselectContacts(); + } + + /** + * Delete selected contacts + */ + deleteSelectedContacts(): void + { + this.confirmDialogRef = this._matDialog.open(FuseConfirmDialogComponent, { + disableClose: false + }); + + this.confirmDialogRef.componentInstance.confirmMessage = 'Are you sure you want to delete all selected contacts?'; + + this.confirmDialogRef.afterClosed() + .subscribe(result => { + if ( result ) + { + this._contactsService.deleteSelectedContacts(); + } + this.confirmDialogRef = null; + }); + } +} diff --git a/src/app/main/apps/contacts/sidebars/main/main.component.ts b/src/app/main/apps/contacts/sidebars/main/main.component.ts new file mode 100644 index 00000000..d9b69540 --- /dev/null +++ b/src/app/main/apps/contacts/sidebars/main/main.component.ts @@ -0,0 +1,75 @@ +import { Component, OnDestroy, OnInit } from '@angular/core'; +import { Subject } from 'rxjs'; +import { takeUntil } from 'rxjs/operators'; + +import { ContactsService } from 'app/main/apps/contacts/contacts.service'; + +@Component({ + selector : 'contacts-main-sidebar', + templateUrl: './main.component.html', + styleUrls : ['./main.component.scss'] +}) +export class ContactsMainSidebarComponent implements OnInit, OnDestroy +{ + user: any; + filterBy: string; + + // Private + private _unsubscribeAll: Subject; + + /** + * Constructor + * + * @param {ContactsService} _contactsService + */ + constructor( + private _contactsService: ContactsService + ) + { + // Set the private defaults + this._unsubscribeAll = new Subject(); + } + + // ----------------------------------------------------------------------------------------------------- + // @ Lifecycle hooks + // ----------------------------------------------------------------------------------------------------- + + /** + * On init + */ + ngOnInit(): void + { + this.filterBy = this._contactsService.filterBy || 'all'; + + this._contactsService.onUserDataChanged + .pipe(takeUntil(this._unsubscribeAll)) + .subscribe(user => { + this.user = user; + }); + } + + /** + * On destroy + */ + ngOnDestroy() + { + // Unsubscribe from all subscriptions + this._unsubscribeAll.next(); + this._unsubscribeAll.complete(); + } + + // ----------------------------------------------------------------------------------------------------- + // @ Public methods + // ----------------------------------------------------------------------------------------------------- + + /** + * Change the filter + * + * @param filter + */ + changeFilter(filter): void + { + this.filterBy = filter; + this._contactsService.onFilterChanged.next(this.filterBy); + } +} diff --git a/src/app/main/apps/dashboards/project/project.component.html b/src/app/main/apps/dashboards/project/project.component.html new file mode 100644 index 00000000..17004ab3 --- /dev/null +++ b/src/app/main/apps/dashboards/project/project.component.html @@ -0,0 +1,903 @@ + diff --git a/src/app/main/apps/dashboards/project/project.component.scss b/src/app/main/apps/dashboards/project/project.component.scss new file mode 100644 index 00000000..f886160c --- /dev/null +++ b/src/app/main/apps/dashboards/project/project.component.scss @@ -0,0 +1,62 @@ +#dashboard-project { + + > .sidebar { + width: 280px; + min-width: 280px; + max-width: 280px; + } + + > .center { + + > .header { + height: 160px; + min-height: 160px; + max-height: 160px; + + .selected-project { + background: rgba(0, 0, 0, 0.12); + color: #FFFFFF; + padding: 8px 16px; + height: 40px; + line-height: 24px; + font-size: 16px; + } + + .project-selector { + margin-left: 1px; + border-radius: 0; + background: rgba(0, 0, 0, 0.12); + + mat-icon { + color: #FFFFFF; + } + } + } + + > .content { + flex: 1; + + mat-tab-group { + height: 100%; + + .mat-tab-body-wrapper { + flex-grow: 1; + } + } + + .mat-tab-label-container { + padding: 0 24px; + } + } + } + + .widget { + + &.widget5 { + + .gridline-path.gridline-path-horizontal { + display: none; + } + } + } +} \ No newline at end of file diff --git a/src/app/main/apps/e-commerce/order/order.component.ts b/src/app/main/apps/e-commerce/order/order.component.ts new file mode 100644 index 00000000..127598dc --- /dev/null +++ b/src/app/main/apps/e-commerce/order/order.component.ts @@ -0,0 +1,102 @@ +import { Component, OnDestroy, OnInit, ViewEncapsulation } from '@angular/core'; +import { FormBuilder, FormGroup } from '@angular/forms'; +import { Subject} from 'rxjs'; +import { takeUntil } from 'rxjs/operators'; + +import { fuseAnimations } from '@fuse/animations'; + +import { orderStatuses } from 'app/main/apps/e-commerce/order/order-statuses'; +import { Order } from 'app/main/apps/e-commerce/order/order.model'; +import { EcommerceOrderService } from 'app/main/apps/e-commerce/order/order.service'; + +@Component({ + selector : 'e-commerce-order', + templateUrl : './order.component.html', + styleUrls : ['./order.component.scss'], + encapsulation: ViewEncapsulation.None, + animations : fuseAnimations +}) +export class EcommerceOrderComponent implements OnInit, OnDestroy +{ + order: Order; + orderStatuses: any; + statusForm: FormGroup; + + // Private + private _unsubscribeAll: Subject; + + /** + * Constructor + * + * @param {EcommerceOrderService} _ecommerceOrderService + * @param {FormBuilder} _formBuilder + */ + constructor( + private _ecommerceOrderService: EcommerceOrderService, + private _formBuilder: FormBuilder + ) + { + // Set the defaults + this.order = new Order(); + this.orderStatuses = orderStatuses; + + // Set the private defaults + this._unsubscribeAll = new Subject(); + } + + // ----------------------------------------------------------------------------------------------------- + // @ Lifecycle hooks + // ----------------------------------------------------------------------------------------------------- + + /** + * On init + */ + ngOnInit(): void + { + // Subscribe to update order on changes + this._ecommerceOrderService.onOrderChanged + .pipe(takeUntil(this._unsubscribeAll)) + .subscribe(order => { + this.order = new Order(order); + }); + + this.statusForm = this._formBuilder.group({ + newStatus: [''] + }); + } + + /** + * On destroy + */ + ngOnDestroy(): void + { + // Unsubscribe from all subscriptions + this._unsubscribeAll.next(); + this._unsubscribeAll.complete(); + } + + // ----------------------------------------------------------------------------------------------------- + // @ Public methods + // ----------------------------------------------------------------------------------------------------- + + /** + * Update status + */ + updateStatus(): void + { + const newStatusId = Number.parseInt(this.statusForm.get('newStatus').value); + + if ( !newStatusId ) + { + return; + } + + const newStatus = this.orderStatuses.find((status) => { + return status.id === newStatusId; + }); + + newStatus['date'] = new Date().toString(); + + this.order.status.unshift(newStatus); + } +} diff --git a/src/app/main/apps/e-commerce/orders/orders.component.ts b/src/app/main/apps/e-commerce/orders/orders.component.ts new file mode 100644 index 00000000..5b1582ab --- /dev/null +++ b/src/app/main/apps/e-commerce/orders/orders.component.ts @@ -0,0 +1,242 @@ +import { Component, ElementRef, OnDestroy, OnInit, ViewChild } from '@angular/core'; +import { MatPaginator, MatSort } from '@angular/material'; +import { DataSource } from '@angular/cdk/collections'; +import { merge, Observable, BehaviorSubject, fromEvent, Subject } from 'rxjs'; +import { debounceTime, distinctUntilChanged, map } from 'rxjs/operators'; + +import { fuseAnimations } from '@fuse/animations'; +import { FuseUtils } from '@fuse/utils'; + +import { EcommerceOrdersService } from 'app/main/apps/e-commerce/orders/orders.service'; +import { takeUntil } from 'rxjs/internal/operators'; + +@Component({ + selector : 'e-commerce-orders', + templateUrl: './orders.component.html', + styleUrls : ['./orders.component.scss'], + animations : fuseAnimations +}) +export class EcommerceOrdersComponent implements OnInit, OnDestroy +{ + dataSource: FilesDataSource | null; + displayedColumns = ['id', 'reference', 'customer', 'total', 'payment', 'status', 'date']; + + @ViewChild(MatPaginator) + paginator: MatPaginator; + + @ViewChild('filter') + filter: ElementRef; + + @ViewChild(MatSort) + sort: MatSort; + + // Private + private _unsubscribeAll: Subject; + + /** + * Constructor + * + * @param {EcommerceOrdersService} _ecommerceOrdersService + */ + constructor( + private _ecommerceOrdersService: EcommerceOrdersService + ) + { + // Set the private defaults + this._unsubscribeAll = new Subject(); + } + + // ----------------------------------------------------------------------------------------------------- + // @ Lifecycle hooks + // ----------------------------------------------------------------------------------------------------- + + /** + * On init + */ + ngOnInit(): void + { + this.dataSource = new FilesDataSource(this._ecommerceOrdersService, this.paginator, this.sort); + + fromEvent(this.filter.nativeElement, 'keyup') + .pipe( + takeUntil(this._unsubscribeAll), + debounceTime(150), + distinctUntilChanged() + ) + .subscribe(() => { + if ( !this.dataSource ) + { + return; + } + this.dataSource.filter = this.filter.nativeElement.value; + }); + } + + /** + * On destroy + */ + ngOnDestroy(): void + { + // Unsubscribe from all subscriptions + this._unsubscribeAll.next(); + this._unsubscribeAll.complete(); + } +} + +export class FilesDataSource extends DataSource +{ + // Private + private _filterChange = new BehaviorSubject(''); + private _filteredDataChange = new BehaviorSubject(''); + + /** + * Constructor + * + * @param {EcommerceOrdersService} _ecommerceOrdersService + * @param {MatPaginator} _matPaginator + * @param {MatSort} _matSort + */ + constructor( + private _ecommerceOrdersService: EcommerceOrdersService, + private _matPaginator: MatPaginator, + private _matSort: MatSort + ) + { + super(); + + this.filteredData = this._ecommerceOrdersService.orders; + } + + // ----------------------------------------------------------------------------------------------------- + // @ Accessors + // ----------------------------------------------------------------------------------------------------- + + // Filtered data + get filteredData(): any + { + return this._filteredDataChange.value; + } + + set filteredData(value: any) + { + this._filteredDataChange.next(value); + } + + // Filter + get filter(): string + { + return this._filterChange.value; + } + + set filter(filter: string) + { + this._filterChange.next(filter); + } + + // ----------------------------------------------------------------------------------------------------- + // @ Public methods + // ----------------------------------------------------------------------------------------------------- + + /** + * Connect function called by the table to retrieve one stream containing the data to render. + * + * @returns {Observable} + */ + connect(): Observable + { + const displayDataChanges = [ + this._ecommerceOrdersService.onOrdersChanged, + this._matPaginator.page, + this._filterChange, + this._matSort.sortChange + ]; + + return merge(...displayDataChanges).pipe(map(() => { + + let data = this._ecommerceOrdersService.orders.slice(); + + data = this.filterData(data); + + this.filteredData = [...data]; + + data = this.sortData(data); + + // Grab the page's slice of data. + const startIndex = this._matPaginator.pageIndex * this._matPaginator.pageSize; + return data.splice(startIndex, this._matPaginator.pageSize); + }) + ); + + } + + /** + * Filter data + * + * @param data + * @returns {any} + */ + filterData(data): any + { + if ( !this.filter ) + { + return data; + } + return FuseUtils.filterArrayByString(data, this.filter); + } + + /** + * Sort data + * + * @param data + * @returns {any[]} + */ + sortData(data): any[] + { + if ( !this._matSort.active || this._matSort.direction === '' ) + { + return data; + } + + return data.sort((a, b) => { + let propertyA: number | string = ''; + let propertyB: number | string = ''; + + switch ( this._matSort.active ) + { + case 'id': + [propertyA, propertyB] = [a.id, b.id]; + break; + case 'reference': + [propertyA, propertyB] = [a.reference, b.reference]; + break; + case 'customer': + [propertyA, propertyB] = [a.customer.firstName, b.customer.firstName]; + break; + case 'total': + [propertyA, propertyB] = [a.total, b.total]; + break; + case 'payment': + [propertyA, propertyB] = [a.payment.method, b.payment.method]; + break; + case 'status': + [propertyA, propertyB] = [a.status[0].name, b.status[0].name]; + break; + case 'date': + [propertyA, propertyB] = [a.date, b.date]; + break; + } + + const valueA = isNaN(+propertyA) ? propertyA : +propertyA; + const valueB = isNaN(+propertyB) ? propertyB : +propertyB; + + return (valueA < valueB ? -1 : 1) * (this._matSort.direction === 'asc' ? 1 : -1); + }); + } + + /** + * Disconnect + */ + disconnect(): void + { + } +} diff --git a/src/app/main/apps/e-commerce/product/product.component.ts b/src/app/main/apps/e-commerce/product/product.component.ts new file mode 100644 index 00000000..01a9918a --- /dev/null +++ b/src/app/main/apps/e-commerce/product/product.component.ts @@ -0,0 +1,171 @@ +import { Component, OnDestroy, OnInit, ViewEncapsulation } from '@angular/core'; +import { FormBuilder, FormGroup } from '@angular/forms'; +import { Location } from '@angular/common'; +import { MatSnackBar } from '@angular/material'; +import { Subject } from 'rxjs'; +import { takeUntil } from 'rxjs/operators'; + +import { fuseAnimations } from '@fuse/animations'; +import { FuseUtils } from '@fuse/utils'; + +import { Product } from 'app/main/apps/e-commerce/product/product.model'; +import { EcommerceProductService } from 'app/main/apps/e-commerce/product/product.service'; + +@Component({ + selector : 'e-commerce-product', + templateUrl : './product.component.html', + styleUrls : ['./product.component.scss'], + encapsulation: ViewEncapsulation.None, + animations : fuseAnimations +}) +export class EcommerceProductComponent implements OnInit, OnDestroy +{ + product: Product; + pageType: string; + productForm: FormGroup; + + // Private + private _unsubscribeAll: Subject; + + /** + * Constructor + * + * @param {EcommerceProductService} _ecommerceProductService + * @param {FormBuilder} _formBuilder + * @param {Location} _location + * @param {MatSnackBar} _matSnackBar + */ + constructor( + private _ecommerceProductService: EcommerceProductService, + private _formBuilder: FormBuilder, + private _location: Location, + private _matSnackBar: MatSnackBar + ) + { + // Set the default + this.product = new Product(); + + // Set the private defaults + this._unsubscribeAll = new Subject(); + } + + // ----------------------------------------------------------------------------------------------------- + // @ Lifecycle hooks + // ----------------------------------------------------------------------------------------------------- + + /** + * On init + */ + ngOnInit(): void + { + // Subscribe to update product on changes + this._ecommerceProductService.onProductChanged + .pipe(takeUntil(this._unsubscribeAll)) + .subscribe(product => { + + if ( product ) + { + this.product = new Product(product); + this.pageType = 'edit'; + } + else + { + this.pageType = 'new'; + this.product = new Product(); + } + + this.productForm = this.createProductForm(); + }); + } + + /** + * On destroy + */ + ngOnDestroy(): void + { + // Unsubscribe from all subscriptions + this._unsubscribeAll.next(); + this._unsubscribeAll.complete(); + } + + // ----------------------------------------------------------------------------------------------------- + // @ Public methods + // ----------------------------------------------------------------------------------------------------- + + /** + * Create product form + * + * @returns {FormGroup} + */ + createProductForm(): FormGroup + { + return this._formBuilder.group({ + id : [this.product.id], + name : [this.product.name], + handle : [this.product.handle], + description : [this.product.description], + categories : [this.product.categories], + tags : [this.product.tags], + images : [this.product.images], + priceTaxExcl : [this.product.priceTaxExcl], + priceTaxIncl : [this.product.priceTaxIncl], + taxRate : [this.product.taxRate], + comparedPrice : [this.product.comparedPrice], + quantity : [this.product.quantity], + sku : [this.product.sku], + width : [this.product.width], + height : [this.product.height], + depth : [this.product.depth], + weight : [this.product.weight], + extraShippingFee: [this.product.extraShippingFee], + active : [this.product.active] + }); + } + + /** + * Save product + */ + saveProduct(): void + { + const data = this.productForm.getRawValue(); + data.handle = FuseUtils.handleize(data.name); + + this._ecommerceProductService.saveProduct(data) + .then(() => { + + // Trigger the subscription with new data + this._ecommerceProductService.onProductChanged.next(data); + + // Show the success message + this._matSnackBar.open('Product saved', 'OK', { + verticalPosition: 'top', + duration : 2000 + }); + }); + } + + /** + * Add product + */ + addProduct(): void + { + const data = this.productForm.getRawValue(); + data.handle = FuseUtils.handleize(data.name); + + this._ecommerceProductService.addProduct(data) + .then(() => { + + // Trigger the subscription with new data + this._ecommerceProductService.onProductChanged.next(data); + + // Show the success message + this._matSnackBar.open('Product added', 'OK', { + verticalPosition: 'top', + duration : 2000 + }); + + // Change the location with new one + this._location.go('apps/e-commerce/products/' + this.product.id + '/' + this.product.handle); + }); + } +} diff --git a/src/app/main/apps/e-commerce/products/products.component.ts b/src/app/main/apps/e-commerce/products/products.component.ts new file mode 100644 index 00000000..7a3df669 --- /dev/null +++ b/src/app/main/apps/e-commerce/products/products.component.ts @@ -0,0 +1,224 @@ +import { Component, ElementRef, OnInit, ViewChild } from '@angular/core'; +import { MatPaginator, MatSort } from '@angular/material'; +import { DataSource } from '@angular/cdk/collections'; +import { merge, Observable, BehaviorSubject, fromEvent, Subject } from 'rxjs'; +import { debounceTime, distinctUntilChanged, map } from 'rxjs/operators'; + +import { fuseAnimations } from '@fuse/animations'; +import { FuseUtils } from '@fuse/utils'; + +import { EcommerceProductsService } from 'app/main/apps/e-commerce/products/products.service'; +import { takeUntil } from 'rxjs/internal/operators'; + +@Component({ + selector : 'e-commerce-products', + templateUrl: './products.component.html', + styleUrls : ['./products.component.scss'], + animations : fuseAnimations +}) +export class EcommerceProductsComponent implements OnInit +{ + dataSource: FilesDataSource | null; + displayedColumns = ['id', 'image', 'name', 'category', 'price', 'quantity', 'active']; + + @ViewChild(MatPaginator) + paginator: MatPaginator; + + @ViewChild(MatSort) + sort: MatSort; + + @ViewChild('filter') + filter: ElementRef; + + // Private + private _unsubscribeAll: Subject; + + constructor( + private _ecommerceProductsService: EcommerceProductsService + ) + { + // Set the private defaults + this._unsubscribeAll = new Subject(); + } + + // ----------------------------------------------------------------------------------------------------- + // @ Lifecycle hooks + // ----------------------------------------------------------------------------------------------------- + + /** + * On init + */ + ngOnInit(): void + { + this.dataSource = new FilesDataSource(this._ecommerceProductsService, this.paginator, this.sort); + + fromEvent(this.filter.nativeElement, 'keyup') + .pipe( + takeUntil(this._unsubscribeAll), + debounceTime(150), + distinctUntilChanged() + ) + .subscribe(() => { + if ( !this.dataSource ) + { + return; + } + + this.dataSource.filter = this.filter.nativeElement.value; + }); + } +} + +export class FilesDataSource extends DataSource +{ + private _filterChange = new BehaviorSubject(''); + private _filteredDataChange = new BehaviorSubject(''); + + /** + * Constructor + * + * @param {EcommerceProductsService} _ecommerceProductsService + * @param {MatPaginator} _matPaginator + * @param {MatSort} _matSort + */ + constructor( + private _ecommerceProductsService: EcommerceProductsService, + private _matPaginator: MatPaginator, + private _matSort: MatSort + ) + { + super(); + + this.filteredData = this._ecommerceProductsService.products; + } + + /** + * Connect function called by the table to retrieve one stream containing the data to render. + * + * @returns {Observable} + */ + connect(): Observable + { + const displayDataChanges = [ + this._ecommerceProductsService.onProductsChanged, + this._matPaginator.page, + this._filterChange, + this._matSort.sortChange + ]; + + return merge(...displayDataChanges) + .pipe( + map(() => { + let data = this._ecommerceProductsService.products.slice(); + + data = this.filterData(data); + + this.filteredData = [...data]; + + data = this.sortData(data); + + // Grab the page's slice of data. + const startIndex = this._matPaginator.pageIndex * this._matPaginator.pageSize; + return data.splice(startIndex, this._matPaginator.pageSize); + } + )); + } + + // ----------------------------------------------------------------------------------------------------- + // @ Accessors + // ----------------------------------------------------------------------------------------------------- + + // Filtered data + get filteredData(): any + { + return this._filteredDataChange.value; + } + + set filteredData(value: any) + { + this._filteredDataChange.next(value); + } + + // Filter + get filter(): string + { + return this._filterChange.value; + } + + set filter(filter: string) + { + this._filterChange.next(filter); + } + + // ----------------------------------------------------------------------------------------------------- + // @ Public methods + // ----------------------------------------------------------------------------------------------------- + + /** + * Filter data + * + * @param data + * @returns {any} + */ + filterData(data): any + { + if ( !this.filter ) + { + return data; + } + return FuseUtils.filterArrayByString(data, this.filter); + } + + /** + * Sort data + * + * @param data + * @returns {any[]} + */ + sortData(data): any[] + { + if ( !this._matSort.active || this._matSort.direction === '' ) + { + return data; + } + + return data.sort((a, b) => { + let propertyA: number | string = ''; + let propertyB: number | string = ''; + + switch ( this._matSort.active ) + { + case 'id': + [propertyA, propertyB] = [a.id, b.id]; + break; + case 'name': + [propertyA, propertyB] = [a.name, b.name]; + break; + case 'categories': + [propertyA, propertyB] = [a.categories[0], b.categories[0]]; + break; + case 'price': + [propertyA, propertyB] = [a.priceTaxIncl, b.priceTaxIncl]; + break; + case 'quantity': + [propertyA, propertyB] = [a.quantity, b.quantity]; + break; + case 'active': + [propertyA, propertyB] = [a.active, b.active]; + break; + } + + const valueA = isNaN(+propertyA) ? propertyA : +propertyA; + const valueB = isNaN(+propertyB) ? propertyB : +propertyB; + + return (valueA < valueB ? -1 : 1) * (this._matSort.direction === 'asc' ? 1 : -1); + }); + } + + /** + * Disconnect + */ + disconnect(): void + { + } +} diff --git a/src/app/main/apps/file-manager/file-list/file-list.component.ts b/src/app/main/apps/file-manager/file-list/file-list.component.ts new file mode 100644 index 00000000..ca8b4d88 --- /dev/null +++ b/src/app/main/apps/file-manager/file-list/file-list.component.ts @@ -0,0 +1,131 @@ +import { Component, OnDestroy, OnInit } from '@angular/core'; +import { DataSource } from '@angular/cdk/collections'; +import { Observable, Subject } from 'rxjs'; +import { takeUntil } from 'rxjs/operators'; + +import { fuseAnimations } from '@fuse/animations'; +import { FuseSidebarService } from '@fuse/components/sidebar/sidebar.service'; + +import { FileManagerService } from 'app/main/apps/file-manager/file-manager.service'; + +@Component({ + selector : 'file-list', + templateUrl: './file-list.component.html', + styleUrls : ['./file-list.component.scss'], + animations : fuseAnimations +}) +export class FileManagerFileListComponent implements OnInit, OnDestroy +{ + files: any; + dataSource: FilesDataSource | null; + displayedColumns = ['icon', 'name', 'type', 'owner', 'size', 'modified', 'detail-button']; + selected: any; + + // Private + private _unsubscribeAll: Subject; + + /** + * Constructor + * + * @param {FileManagerService} _fileManagerService + * @param {FuseSidebarService} _fuseSidebarService + */ + constructor( + private _fileManagerService: FileManagerService, + private _fuseSidebarService: FuseSidebarService + ) + { + // Set the private defaults + this._unsubscribeAll = new Subject(); + } + + // ----------------------------------------------------------------------------------------------------- + // @ Lifecycle hooks + // ----------------------------------------------------------------------------------------------------- + + /** + * On init + */ + ngOnInit(): void + { + this.dataSource = new FilesDataSource(this._fileManagerService); + + this._fileManagerService.onFilesChanged + .pipe(takeUntil(this._unsubscribeAll)) + .subscribe(files => { + this.files = files; + }); + + this._fileManagerService.onFileSelected + .pipe(takeUntil(this._unsubscribeAll)) + .subscribe(selected => { + this.selected = selected; + }); + } + + /** + * On destroy + */ + ngOnDestroy(): void + { + // Unsubscribe from all subscriptions + this._unsubscribeAll.next(); + this._unsubscribeAll.complete(); + } + + // ----------------------------------------------------------------------------------------------------- + // @ Public methods + // ----------------------------------------------------------------------------------------------------- + + /** + * On select + * + * @param selected + */ + onSelect(selected): void + { + this._fileManagerService.onFileSelected.next(selected); + } + + /** + * Toggle the sidebar + * + * @param name + */ + toggleSidebar(name): void + { + this._fuseSidebarService.getSidebar(name).toggleOpen(); + } +} + +export class FilesDataSource extends DataSource +{ + /** + * Constructor + * + * @param {FileManagerService} _fileManagerService + */ + constructor( + private _fileManagerService: FileManagerService + ) + { + super(); + } + + /** + * Connect function called by the table to retrieve one stream containing the data to render. + * + * @returns {Observable} + */ + connect(): Observable + { + return this._fileManagerService.onFilesChanged; + } + + /** + * Disconnect + */ + disconnect(): void + { + } +} diff --git a/src/app/main/apps/file-manager/file-manager.component.html b/src/app/main/apps/file-manager/file-manager.component.html new file mode 100644 index 00000000..72b1b7f6 --- /dev/null +++ b/src/app/main/apps/file-manager/file-manager.component.html @@ -0,0 +1,75 @@ + diff --git a/src/app/main/apps/file-manager/file-manager.component.scss b/src/app/main/apps/file-manager/file-manager.component.scss new file mode 100644 index 00000000..0866d229 --- /dev/null +++ b/src/app/main/apps/file-manager/file-manager.component.scss @@ -0,0 +1,72 @@ +@import "src/@fuse/scss/fuse"; + +#file-manager { + + .sidebar { + width: 320px !important; + min-width: 320px !important; + max-width: 320px !important; + + &.main-sidebar { + } + + &.details-sidebar { + @include media-breakpoint('gt-md') { + z-index: 0; + } + } + } + + .center { + overflow: hidden; + + .header { + position: relative; + height: 160px; + min-height: 160px; + max-height: 160px; + + @include media-breakpoint-down('sm') { + height: 120px; + min-height: 120px; + max-height: 120px; + } + + .add-file-button { + position: absolute; + bottom: -28px; + left: 16px; + z-index: 999; + } + } + + .content { + flex: 1 1 auto; + overflow: auto; + } + } + + .type-icon { + + &.folder { + &:before { + content: 'folder'; + color: #FFB300; + } + } + + &.document { + &:before { + content: 'insert_drive_file'; + color: #1565C0; + } + } + + &.spreadsheet { + &:before { + content: 'insert_chart'; + color: #4CAF50; + } + } + } +} diff --git a/src/app/main/apps/file-manager/file-manager.component.ts b/src/app/main/apps/file-manager/file-manager.component.ts new file mode 100644 index 00000000..a5fee524 --- /dev/null +++ b/src/app/main/apps/file-manager/file-manager.component.ts @@ -0,0 +1,80 @@ +import { Component, OnDestroy, OnInit, ViewEncapsulation } from '@angular/core'; +import { Subject } from 'rxjs'; +import { takeUntil } from 'rxjs/operators'; + +import { fuseAnimations } from '@fuse/animations'; +import { FuseSidebarService } from '@fuse/components/sidebar/sidebar.service'; + +import { FileManagerService } from 'app/main/apps/file-manager/file-manager.service'; + +@Component({ + selector : 'file-manager', + templateUrl : './file-manager.component.html', + styleUrls : ['./file-manager.component.scss'], + encapsulation: ViewEncapsulation.None, + animations : fuseAnimations +}) +export class FileManagerComponent implements OnInit, OnDestroy +{ + selected: any; + pathArr: string[]; + + // Private + private _unsubscribeAll: Subject; + + /** + * Constructor + * + * @param {FileManagerService} _fileManagerService + * @param {FuseSidebarService} _fuseSidebarService + */ + constructor( + private _fileManagerService: FileManagerService, + private _fuseSidebarService: FuseSidebarService + ) + { + // Set the private defaults + this._unsubscribeAll = new Subject(); + } + + // ----------------------------------------------------------------------------------------------------- + // @ Lifecycle hooks + // ----------------------------------------------------------------------------------------------------- + + /** + * On init + */ + ngOnInit(): void + { + this._fileManagerService.onFileSelected + .pipe(takeUntil(this._unsubscribeAll)) + .subscribe(selected => { + this.selected = selected; + this.pathArr = selected.location.split('>'); + }); + } + + /** + * On destroy + */ + ngOnDestroy(): void + { + // Unsubscribe from all subscriptions + this._unsubscribeAll.next(); + this._unsubscribeAll.complete(); + } + + // ----------------------------------------------------------------------------------------------------- + // @ Public methods + // ----------------------------------------------------------------------------------------------------- + + /** + * Toggle the sidebar + * + * @param name + */ + toggleSidebar(name): void + { + this._fuseSidebarService.getSidebar(name).toggleOpen(); + } +} diff --git a/src/app/main/apps/file-manager/file-manager.module.ts b/src/app/main/apps/file-manager/file-manager.module.ts new file mode 100644 index 00000000..ba57d866 --- /dev/null +++ b/src/app/main/apps/file-manager/file-manager.module.ts @@ -0,0 +1,52 @@ +import { NgModule } from '@angular/core'; +import { RouterModule, Routes } from '@angular/router'; +import { CdkTableModule } from '@angular/cdk/table'; +import { MatButtonModule, MatIconModule, MatRippleModule, MatSlideToggleModule, MatTableModule } from '@angular/material'; + +import { FuseSharedModule } from '@fuse/shared.module'; +import { FuseSidebarModule } from '@fuse/components'; + +import { FileManagerService } from 'app/main/apps/file-manager/file-manager.service'; +import { FileManagerComponent } from 'app/main/apps/file-manager/file-manager.component'; +import { FileManagerDetailsSidebarComponent } from 'app/main/apps/file-manager/sidebars/details/details.component'; +import { FileManagerFileListComponent } from 'app/main/apps/file-manager/file-list/file-list.component'; +import { FileManagerMainSidebarComponent } from 'app/main/apps/file-manager/sidebars/main/main.component'; + +const routes: Routes = [ + { + path : '**', + component: FileManagerComponent, + children : [], + resolve : { + files: FileManagerService + } + } +]; + +@NgModule({ + declarations: [ + FileManagerComponent, + FileManagerFileListComponent, + FileManagerMainSidebarComponent, + FileManagerDetailsSidebarComponent + ], + imports : [ + RouterModule.forChild(routes), + + CdkTableModule, + MatButtonModule, + MatIconModule, + MatRippleModule, + MatSlideToggleModule, + MatTableModule, + + FuseSharedModule, + FuseSidebarModule + ], + providers : [ + FileManagerService + ] +}) +export class FileManagerModule +{ +} diff --git a/src/app/main/apps/file-manager/sidebars/details/details.component.ts b/src/app/main/apps/file-manager/sidebars/details/details.component.ts new file mode 100644 index 00000000..939e18df --- /dev/null +++ b/src/app/main/apps/file-manager/sidebars/details/details.component.ts @@ -0,0 +1,60 @@ +import { Component, OnDestroy, OnInit } from '@angular/core'; +import { Subject } from 'rxjs'; +import { takeUntil } from 'rxjs/operators'; + +import { fuseAnimations } from '@fuse/animations'; + +import { FileManagerService } from 'app/main/apps/file-manager/file-manager.service'; + +@Component({ + selector : 'file-manager-details-sidebar', + templateUrl: './details.component.html', + styleUrls : ['./details.component.scss'], + animations : fuseAnimations +}) +export class FileManagerDetailsSidebarComponent implements OnInit, OnDestroy +{ + selected: any; + + // Private + private _unsubscribeAll: Subject; + + /** + * Constructor + * + * @param {FileManagerService} _fileManagerService + */ + constructor( + private _fileManagerService: FileManagerService + ) + { + // Set the private defaults + this._unsubscribeAll = new Subject(); + } + + // ----------------------------------------------------------------------------------------------------- + // @ Lifecycle hooks + // ----------------------------------------------------------------------------------------------------- + + /** + * On init + */ + ngOnInit(): void + { + this._fileManagerService.onFileSelected + .pipe(takeUntil(this._unsubscribeAll)) + .subscribe(selected => { + this.selected = selected; + }); + } + + /** + * On destroy + */ + ngOnDestroy(): void + { + // Unsubscribe from all subscriptions + this._unsubscribeAll.next(); + this._unsubscribeAll.complete(); + } +} diff --git a/src/app/main/apps/mail-ngrx/dialogs/compose/compose.component.ts b/src/app/main/apps/mail-ngrx/dialogs/compose/compose.component.ts new file mode 100644 index 00000000..b4f6e742 --- /dev/null +++ b/src/app/main/apps/mail-ngrx/dialogs/compose/compose.component.ts @@ -0,0 +1,57 @@ +import { Component, Inject, ViewEncapsulation } from '@angular/core'; +import { FormBuilder, FormGroup } from '@angular/forms'; +import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material'; + +@Component({ + selector : 'mail-ngrx-compose', + templateUrl : './compose.component.html', + styleUrls : ['./compose.component.scss'], + encapsulation: ViewEncapsulation.None +}) +export class MailNgrxComposeDialogComponent +{ + composeForm: FormGroup; + + /** + * Constructor + * + * @param {MatDialogRef} matDialogRef + * @param _data + * @param {FormBuilder} _formBuilder + */ + constructor( + public matDialogRef: MatDialogRef, + @Inject(MAT_DIALOG_DATA) private _data: any, + private _formBuilder: FormBuilder + ) + { + // Set the defaults + this.composeForm = this.createComposeForm(); + } + + // ----------------------------------------------------------------------------------------------------- + // @ Public methods + // ----------------------------------------------------------------------------------------------------- + + /** + * Create compose form + * + * @returns {FormGroup} + */ + createComposeForm(): FormGroup + { + return this._formBuilder.group({ + from : { + value : ['johndoe@creapond.com'], + disabled: [true] + }, + to : [''], + cc : [''], + bcc : [''], + subject: [''], + message: [''] + }); + + } + +} diff --git a/src/app/main/apps/mail-ngrx/mail-details/mail-details.component.ts b/src/app/main/apps/mail-ngrx/mail-details/mail-details.component.ts new file mode 100644 index 00000000..746424cd --- /dev/null +++ b/src/app/main/apps/mail-ngrx/mail-details/mail-details.component.ts @@ -0,0 +1,111 @@ +import { ChangeDetectionStrategy, Component, Input, OnChanges } from '@angular/core'; +import { Store } from '@ngrx/store'; +import { Observable } from 'rxjs'; + +import { Mail } from 'app/main/apps/mail-ngrx/mail.model'; +import * as fromStore from 'app/main/apps/mail-ngrx/store'; +import { MailNgrxService } from 'app/main/apps/mail-ngrx/mail.service'; + +@Component({ + selector : 'mail-ngrx-details', + templateUrl : './mail-details.component.html', + styleUrls : ['./mail-details.component.scss'], + changeDetection: ChangeDetectionStrategy.OnPush +}) +export class MailNgrxDetailsComponent implements OnChanges +{ + @Input('mail') + mailInput: Mail; + + labels$: Observable; + mail: Mail; + showDetails: boolean; + + /** + * Constructor + * + * @param {MailNgrxService} _mailNgrxService + * @param {Store} _store + */ + constructor( + private _mailNgrxService: MailNgrxService, + private _store: Store + ) + { + // Set the defaults + this.labels$ = this._store.select(fromStore.getLabelsArr); + this.showDetails = false; + } + + // ----------------------------------------------------------------------------------------------------- + // @ Lifecycle hooks + // ----------------------------------------------------------------------------------------------------- + + /** + * On changes + */ + ngOnChanges(): void + { + this.updateModel(this.mailInput); + this.markAsRead(); + } + + // ----------------------------------------------------------------------------------------------------- + // @ Public methods + // ----------------------------------------------------------------------------------------------------- + + /** + * Mark as read + */ + markAsRead(): void + { + if ( this.mail && !this.mail.read ) + { + this.mail.markRead(); + this.updateMail(); + } + } + + /** + * Toggle star + * + * @param event + */ + toggleStar(event): void + { + event.stopPropagation(); + this.mail.toggleStar(); + this.updateMail(); + } + + /** + * Toggle important + * + * @param event + */ + toggleImportant(event): void + { + event.stopPropagation(); + this.mail.toggleImportant(); + this.updateMail(); + } + + /** + * Update model + * + * @param data + */ + updateModel(data): void + { + this.mail = !data ? null : new Mail({...data}); + } + + /** + * Update the mail + */ + updateMail(): void + { + this._store.dispatch(new fromStore.UpdateMail(this.mail)); + this.updateModel(this.mail); + } +} diff --git a/src/app/main/apps/mail-ngrx/mail-list/mail-list.component.ts b/src/app/main/apps/mail-ngrx/mail-list/mail-list.component.ts new file mode 100644 index 00000000..faaef965 --- /dev/null +++ b/src/app/main/apps/mail-ngrx/mail-list/mail-list.component.ts @@ -0,0 +1,64 @@ +import { ChangeDetectionStrategy, Component, Input } from '@angular/core'; +import { ActivatedRoute, Router } from '@angular/router'; + +import { Mail } from 'app/main/apps/mail-ngrx/mail.model'; +import { MailNgrxService } from 'app/main/apps/mail-ngrx/mail.service'; + +@Component({ + selector : 'mail-ngrx-list', + templateUrl : './mail-list.component.html', + styleUrls : ['./mail-list.component.scss'], + changeDetection: ChangeDetectionStrategy.OnPush +}) +export class MailNgrxListComponent +{ + @Input() + mails: Mail[]; + + @Input() + currentMail: Mail[]; + + /** + * Constructor + * + * @param {ActivatedRoute} _activatedRoute + * @param {MailNgrxService} _mailNgrxService + * @param {Router} _router + */ + constructor( + private _activatedRoute: ActivatedRoute, + private _mailNgrxService: MailNgrxService, + private _router: Router + ) + { + } + + // ----------------------------------------------------------------------------------------------------- + // @ Public methods + // ----------------------------------------------------------------------------------------------------- + + /** + * Read mail + * + * @param mailId + */ + readMail(mailId): void + { + const labelHandle = this._activatedRoute.snapshot.params.labelHandle, + filterHandle = this._activatedRoute.snapshot.params.filterHandle, + folderHandle = this._activatedRoute.snapshot.params.folderHandle; + + if ( labelHandle ) + { + this._router.navigate(['apps/mail-ngrx/label/' + labelHandle + '/' + mailId]); + } + else if ( filterHandle ) + { + this._router.navigate(['apps/mail-ngrx/filter/' + filterHandle + '/' + mailId]); + } + else + { + this._router.navigate(['apps/mail-ngrx/' + folderHandle + '/' + mailId]); + } + } +} diff --git a/src/app/main/apps/mail-ngrx/mail.component.html b/src/app/main/apps/mail-ngrx/mail.component.html new file mode 100644 index 00000000..6b1ce194 --- /dev/null +++ b/src/app/main/apps/mail-ngrx/mail.component.html @@ -0,0 +1,109 @@ + diff --git a/src/app/main/apps/mail-ngrx/mail.component.ts b/src/app/main/apps/mail-ngrx/mail.component.ts new file mode 100644 index 00000000..2b43c7e4 --- /dev/null +++ b/src/app/main/apps/mail-ngrx/mail.component.ts @@ -0,0 +1,206 @@ +import { ChangeDetectionStrategy, ChangeDetectorRef, Component, OnDestroy, OnInit } from '@angular/core'; +import { FormControl } from '@angular/forms'; +import { Store } from '@ngrx/store'; +import { Observable } from 'rxjs'; +import { debounceTime, distinctUntilChanged } from 'rxjs/operators'; + +import { FuseSidebarService } from '@fuse/components/sidebar/sidebar.service'; +import { FuseTranslationLoaderService } from '@fuse/services/translation-loader.service'; + +import { Mail } from 'app/main/apps/mail-ngrx/mail.model'; +import { MailNgrxService } from 'app/main/apps/mail-ngrx/mail.service'; +import * as fromStore from 'app/main/apps/mail-ngrx/store'; + +import { locale as english } from 'app/main/apps/mail-ngrx/i18n/en'; +import { locale as turkish } from 'app/main/apps/mail-ngrx/i18n/tr'; + +@Component({ + selector : 'mail-ngrx', + templateUrl : './mail.component.html', + styleUrls : ['./mail.component.scss'], + changeDetection: ChangeDetectionStrategy.OnPush +}) +export class MailNgrxComponent implements OnInit, OnDestroy +{ + hasSelectedMails: boolean; + isIndeterminate: boolean; + searchInput: FormControl; + mails$: Observable; + folders$: Observable; + labels$: Observable; + currentMail$: Observable; + selectedMailIds$: Observable; + searchText$: Observable; + mails: Mail[]; + selectedMailIds: string[]; + + /** + * Constructor + * + * @param {ChangeDetectorRef} _changeDetectorRef + * @param {FuseSidebarService} _fuseSidebarService + * @param {FuseTranslationLoaderService} _fuseTranslationLoaderService + * @param {MailNgrxService} _mailNgrxService + * @param {Store} _store + */ + constructor( + private _changeDetectorRef: ChangeDetectorRef, + private _fuseSidebarService: FuseSidebarService, + private _fuseTranslationLoaderService: FuseTranslationLoaderService, + private _mailNgrxService: MailNgrxService, + private _store: Store + ) + { + // Set the defaults + this.searchInput = new FormControl(''); + this._fuseTranslationLoaderService.loadTranslations(english, turkish); + this.currentMail$ = this._store.select(fromStore.getCurrentMail); + this.mails$ = this._store.select(fromStore.getMailsArr); + this.folders$ = this._store.select(fromStore.getFoldersArr); + this.labels$ = this._store.select(fromStore.getLabelsArr); + this.selectedMailIds$ = this._store.select(fromStore.getSelectedMailIds); + this.searchText$ = this._store.select(fromStore.getSearchText); + this.mails = []; + this.selectedMailIds = []; + } + + // ----------------------------------------------------------------------------------------------------- + // @ Lifecycle hooks + // ----------------------------------------------------------------------------------------------------- + + /** + * On init + */ + ngOnInit(): void + { + this.mails$.subscribe(mails => { + this.mails = mails; + }); + + this.selectedMailIds$ + .subscribe(selectedMailIds => { + this.selectedMailIds = selectedMailIds; + this.hasSelectedMails = selectedMailIds.length > 0; + this.isIndeterminate = (selectedMailIds.length !== this.mails.length && selectedMailIds.length > 0); + this.refresh(); + }); + + this.searchText$.subscribe(searchText => { + this.searchInput.setValue(searchText); + }); + + this.searchInput.valueChanges.pipe( + debounceTime(300), + distinctUntilChanged() + ).subscribe(searchText => { + this._store.dispatch(new fromStore.SetSearchText(searchText)); + }); + } + + /** + * On destroy + */ + ngOnDestroy(): void + { + this._changeDetectorRef.detach(); + } + + // ----------------------------------------------------------------------------------------------------- + // @ Public methods + // ----------------------------------------------------------------------------------------------------- + + /** + * Toggle select all + * + * @param ev + */ + toggleSelectAll(ev): void + { + ev.preventDefault(); + + if ( this.selectedMailIds.length && this.selectedMailIds.length > 0 ) + { + this.deselectAllMails(); + } + else + { + this.selectAllMails(); + } + } + + /** + * Select all mails + */ + selectAllMails(): void + { + this._store.dispatch(new fromStore.SelectAllMails()); + } + + /** + * Deselect all mails + */ + deselectAllMails(): void + { + this._store.dispatch(new fromStore.DeselectAllMails()); + } + + /** + * Select mails by parameter + * + * @param parameter + * @param value + */ + selectMailsByParameter(parameter, value): void + { + this._store.dispatch(new fromStore.SelectMailsByParameter({ + parameter, + value + })); + } + + /** + * Toggle label on selected mails + * + * @param labelId + */ + toggleLabelOnSelectedMails(labelId): void + { + this._store.dispatch(new fromStore.AddLabelOnSelectedMails(labelId)); + } + + /** + * Set folder on selected mails + * + * @param folderId + */ + setFolderOnSelectedMails(folderId): void + { + this._store.dispatch(new fromStore.SetFolderOnSelectedMails(folderId)); + } + + /** + * Deselect current mail + */ + deselectCurrentMail(): void + { + this._store.dispatch(new fromStore.SetCurrentMail('')); + } + + /** + * Refresh + */ + refresh(): void + { + this._changeDetectorRef.markForCheck(); + } + + /** + * Toggle the sidebar + * + * @param name + */ + toggleSidebar(name): void + { + this._fuseSidebarService.getSidebar(name).toggleOpen(); + } +} diff --git a/src/app/main/apps/mail-ngrx/mail.module.ts b/src/app/main/apps/mail-ngrx/mail.module.ts new file mode 100644 index 00000000..76474bbc --- /dev/null +++ b/src/app/main/apps/mail-ngrx/mail.module.ts @@ -0,0 +1,94 @@ +import { NgModule } from '@angular/core'; +import { RouterModule, Routes } from '@angular/router'; +import { MatButtonModule, MatCheckboxModule, MatDialogModule, MatFormFieldModule, MatIconModule, MatInputModule, MatMenuModule, MatRippleModule, MatSelectModule, MatToolbarModule } from '@angular/material'; +import { TranslateModule } from '@ngx-translate/core'; + +import { FuseSharedModule } from '@fuse/shared.module'; +import { FuseSidebarModule } from '@fuse/components'; + +import * as fromGuards from 'app/main/apps/mail-ngrx/store/guards/index'; +import { MailNgrxStoreModule } from 'app/main/apps/mail-ngrx/store/store.module'; +import { MailNgrxComponent } from 'app/main/apps/mail-ngrx/mail.component'; +import { MailNgrxListComponent } from 'app/main/apps/mail-ngrx/mail-list/mail-list.component'; +import { MailNgrxListItemComponent } from 'app/main/apps/mail-ngrx/mail-list/mail-list-item/mail-list-item.component'; +import { MailNgrxDetailsComponent } from 'app/main/apps/mail-ngrx/mail-details/mail-details.component'; +import { MailNgrxMainSidebarComponent } from 'app/main/apps/mail-ngrx/sidebars/main/main-sidebar.component'; +import { MailNgrxComposeDialogComponent } from 'app/main/apps/mail-ngrx/dialogs/compose/compose.component'; +import { MailNgrxService } from 'app/main/apps/mail-ngrx/mail.service'; + +const routes: Routes = [ + { + path : 'label/:labelHandle', + component : MailNgrxComponent, + canActivate: [fromGuards.ResolveGuard] + }, + { + path : 'label/:labelHandle/:mailId', + component : MailNgrxComponent, + canActivate: [fromGuards.ResolveGuard] + }, + { + path : 'filter/:filterHandle', + component : MailNgrxComponent, + canActivate: [fromGuards.ResolveGuard] + }, + { + path : 'filter/:filterHandle/:mailId', + component : MailNgrxComponent, + canActivate: [fromGuards.ResolveGuard] + }, + { + path : ':folderHandle', + component : MailNgrxComponent, + canActivate: [fromGuards.ResolveGuard] + }, + { + path : ':folderHandle/:mailId', + component : MailNgrxComponent, + canActivate: [fromGuards.ResolveGuard] + }, + { + path : '**', + redirectTo: 'inbox' + } +]; + +@NgModule({ + declarations : [ + MailNgrxComponent, + MailNgrxListComponent, + MailNgrxListItemComponent, + MailNgrxDetailsComponent, + MailNgrxMainSidebarComponent, + MailNgrxComposeDialogComponent + ], + imports : [ + RouterModule.forChild(routes), + + MatButtonModule, + MatCheckboxModule, + MatDialogModule, + MatFormFieldModule, + MatIconModule, + MatInputModule, + MatMenuModule, + MatRippleModule, + MatSelectModule, + MatToolbarModule, + + TranslateModule, + + FuseSharedModule, + FuseSidebarModule, + + MailNgrxStoreModule + ], + providers : [ + MailNgrxService, + fromGuards.ResolveGuard + ], + entryComponents: [MailNgrxComposeDialogComponent] +}) +export class MailNgrxModule +{ +} diff --git a/src/app/main/apps/mail-ngrx/mail.service.ts b/src/app/main/apps/mail-ngrx/mail.service.ts new file mode 100644 index 00000000..ec1a6aad --- /dev/null +++ b/src/app/main/apps/mail-ngrx/mail.service.ts @@ -0,0 +1,123 @@ +import { Injectable } from '@angular/core'; +import { HttpClient } from '@angular/common/http'; +import { Store } from '@ngrx/store'; +import { Observable } from 'rxjs'; + +import { Mail } from 'app/main/apps/mail-ngrx/mail.model'; +import { MailAppState } from 'app/main/apps/mail-ngrx/store/reducers'; +import { getFiltersArr, getFoldersArr, getLabelsArr, getMailsArr } from 'app/main/apps/mail-ngrx/store/selectors'; + +@Injectable() +export class MailNgrxService +{ + foldersArr: any; + filtersArr: any; + labelsArr: any; + selectedMails: Mail[]; + mails: Mail[]; + + /** + * Constructor + * + * @param {HttpClient} _httpClient + * @param {Store} _store + */ + constructor( + private _httpClient: HttpClient, + private _store: Store + ) + { + this._store.select(getFoldersArr).subscribe(folders => { + this.foldersArr = folders; + }); + + this._store.select(getFiltersArr).subscribe(filters => { + this.filtersArr = filters; + }); + + this._store.select(getLabelsArr).subscribe(labels => { + this.labelsArr = labels; + }); + + this._store.select(getMailsArr).subscribe(mails => { + this.mails = mails; + }); + + this.selectedMails = []; + } + + /** + * Get all mails + * + * @returns {Observable} + */ + getAllMails(): Observable + { + return this._httpClient.get('api/mail-mails'); + } + + /** + * Get folders + * + * @returns {Observable} + */ + getFolders(): Observable + { + return this._httpClient.get('api/mail-folders'); + } + + /** + * Get filters + * + * @returns {Observable} + */ + getFilters(): Observable + { + return this._httpClient.get('api/mail-filters'); + } + + /** + * Get labels + * + * @returns {Observable} + */ + getLabels(): Observable + { + return this._httpClient.get('api/mail-labels'); + } + + /** + * Get mails + * + * @param handle + * @returns {Observable} + */ + getMails(handle): Observable + { + if ( handle.id === 'labelHandle' ) + { + const labelId = this.labelsArr.find(label => label.handle === handle.value).id; + return this._httpClient.get('api/mail-mails?labels=' + labelId); + } + else if ( handle.id === 'filterHandle' ) + { + return this._httpClient.get('api/mail-mails?' + handle.value + '=true'); + } + else // folderHandle + { + const folderId = this.foldersArr.find(folder => folder.handle === handle.value).id; + return this._httpClient.get('api/mail-mails?folder=' + folderId); + } + } + + /** + * Update the mail + * + * @param mail + * @returns {Promise} + */ + updateMail(mail): any + { + return this._httpClient.post('api/mail-mails/' + mail.id, {...mail}); + } +} diff --git a/src/app/main/apps/mail-ngrx/sidebars/main/main-sidebar.component.ts b/src/app/main/apps/mail-ngrx/sidebars/main/main-sidebar.component.ts new file mode 100644 index 00000000..7231340b --- /dev/null +++ b/src/app/main/apps/mail-ngrx/sidebars/main/main-sidebar.component.ts @@ -0,0 +1,90 @@ +import { ChangeDetectionStrategy, Component } from '@angular/core'; +import { MatDialog } from '@angular/material'; +import { FormGroup } from '@angular/forms'; +import { Store } from '@ngrx/store'; +import { Observable } from 'rxjs'; + +import { MailNgrxService } from 'app/main/apps/mail-ngrx/mail.service'; +import * as fromStore from 'app/main/apps/mail-ngrx/store'; +import { MailNgrxComposeDialogComponent } from 'app/main/apps/mail-ngrx/dialogs/compose/compose.component'; + +@Component({ + selector : 'mail-ngrx-main-sidebar', + templateUrl : './main-sidebar.component.html', + styleUrls : ['./main-sidebar.component.scss'], + changeDetection: ChangeDetectionStrategy.OnPush +}) +export class MailNgrxMainSidebarComponent +{ + labels: any[]; + accounts: object; + selectedAccount: string; + dialogRef: any; + + folders$: Observable; + filters$: Observable; + labels$: Observable; + + /** + * Constructor + * + * @param {MailNgrxService} _mailNgrxService + * @param {MatDialog} _matDialog + * @param {Store} _store + */ + constructor( + private _mailNgrxService: MailNgrxService, + private _matDialog: MatDialog, + private _store: Store + ) + { + // Set the defaults + this.accounts = { + 'creapond' : 'johndoe@creapond.com', + 'withinpixels': 'johndoe@withinpixels.com' + }; + this.selectedAccount = 'creapond'; + this.folders$ = this._store.select(fromStore.getFoldersArr); + this.filters$ = this._store.select(fromStore.getFiltersArr); + this.labels$ = this._store.select(fromStore.getLabelsArr); + } + + // ----------------------------------------------------------------------------------------------------- + // @ Public methods + // ----------------------------------------------------------------------------------------------------- + + /** + * Compose dialog + */ + composeDialog(): void + { + this.dialogRef = this._matDialog.open(MailNgrxComposeDialogComponent, { + panelClass: 'mail-ngrx-compose-dialog' + }); + + this.dialogRef.afterClosed() + .subscribe(response => { + if ( !response ) + { + return; + } + const actionType: string = response[0]; + const formData: FormGroup = response[1]; + switch ( actionType ) + { + /** + * Send + */ + case 'send': + console.log('new Mail', formData.getRawValue()); + break; + /** + * Delete + */ + case 'delete': + console.log('delete Mail'); + break; + } + }); + } +} diff --git a/src/app/main/apps/mail/mail-details/mail-details.component.ts b/src/app/main/apps/mail/mail-details/mail-details.component.ts new file mode 100644 index 00000000..a6be0823 --- /dev/null +++ b/src/app/main/apps/mail/mail-details/mail-details.component.ts @@ -0,0 +1,106 @@ +import { Component, OnDestroy, OnInit } from '@angular/core'; +import { Subject } from 'rxjs'; +import { takeUntil } from 'rxjs/operators'; + +import { fuseAnimations } from '@fuse/animations'; + +import { Mail } from 'app/main/apps/mail/mail.model'; +import { MailService } from 'app/main/apps/mail/mail.service'; + +@Component({ + selector : 'mail-details', + templateUrl: './mail-details.component.html', + styleUrls : ['./mail-details.component.scss'], + animations : fuseAnimations +}) +export class MailDetailsComponent implements OnInit, OnDestroy +{ + mail: Mail; + labels: any[]; + showDetails: boolean; + + // Private + private _unsubscribeAll: Subject; + + /** + * Constructor + * + * @param {MailService} _mailService + */ + constructor( + private _mailService: MailService + ) + { + // Set the defaults + this.showDetails = false; + + // Set the private defaults + this._unsubscribeAll = new Subject(); + } + + // ----------------------------------------------------------------------------------------------------- + // @ Lifecycle hooks + // ----------------------------------------------------------------------------------------------------- + + /** + * On init + */ + ngOnInit(): void + { + // Subscribe to update the current mail + this._mailService.onCurrentMailChanged + .pipe(takeUntil(this._unsubscribeAll)) + .subscribe(currentMail => { + this.mail = currentMail; + }); + + // Subscribe to update on label change + this._mailService.onLabelsChanged + .pipe(takeUntil(this._unsubscribeAll)) + .subscribe(labels => { + this.labels = labels; + }); + } + + /** + * On destroy + */ + ngOnDestroy(): void + { + // Unsubscribe from all subscriptions + this._unsubscribeAll.next(); + this._unsubscribeAll.complete(); + } + + // ----------------------------------------------------------------------------------------------------- + // @ Public methods + // ----------------------------------------------------------------------------------------------------- + + /** + * Toggle star + * + * @param event + */ + toggleStar(event): void + { + event.stopPropagation(); + + this.mail.toggleStar(); + + this._mailService.updateMail(this.mail); + } + + /** + * Toggle important + * + * @param event + */ + toggleImportant(event): void + { + event.stopPropagation(); + + this.mail.toggleImportant(); + + this._mailService.updateMail(this.mail); + } +} diff --git a/src/app/main/apps/mail/mail-list/mail-list-item/mail-list-item.component.ts b/src/app/main/apps/mail/mail-list/mail-list-item/mail-list-item.component.ts new file mode 100644 index 00000000..81bee3b0 --- /dev/null +++ b/src/app/main/apps/mail/mail-list/mail-list-item/mail-list-item.component.ts @@ -0,0 +1,125 @@ +import { Component, HostBinding, Input, OnDestroy, OnInit } from '@angular/core'; +import { Subject } from 'rxjs'; +import { takeUntil } from 'rxjs/operators'; + +import { Mail } from 'app/main/apps/mail/mail.model'; +import { MailService } from 'app/main/apps/mail/mail.service'; + +@Component({ + selector : 'mail-list-item', + templateUrl: './mail-list-item.component.html', + styleUrls : ['./mail-list-item.component.scss'] +}) +export class MailListItemComponent implements OnInit, OnDestroy +{ + @Input() mail: Mail; + labels: any[]; + + @HostBinding('class.selected') + selected: boolean; + + // Private + private _unsubscribeAll: Subject; + + /** + * Constructor + * + * @param {MailService} _mailService + */ + constructor( + private _mailService: MailService + ) + { + // Set the private defaults + this._unsubscribeAll = new Subject(); + } + + // ----------------------------------------------------------------------------------------------------- + // @ Lifecycle hooks + // ----------------------------------------------------------------------------------------------------- + + /** + * On init + */ + ngOnInit(): void + { + // Set the initial values + this.mail = new Mail(this.mail); + + // Subscribe to update on selected mail change + this._mailService.onSelectedMailsChanged + .pipe(takeUntil(this._unsubscribeAll)) + .subscribe(selectedMails => { + this.selected = false; + + if ( selectedMails.length > 0 ) + { + for ( const mail of selectedMails ) + { + if ( mail.id === this.mail.id ) + { + this.selected = true; + break; + } + } + } + }); + + // Subscribe to update on label change + this._mailService.onLabelsChanged + .pipe(takeUntil(this._unsubscribeAll)) + .subscribe(labels => { + this.labels = labels; + }); + } + + /** + * On destroy + */ + ngOnDestroy(): void + { + // Unsubscribe from all subscriptions + this._unsubscribeAll.next(); + this._unsubscribeAll.complete(); + } + + // ----------------------------------------------------------------------------------------------------- + // @ Public methods + // ----------------------------------------------------------------------------------------------------- + + /** + * On selected change + */ + onSelectedChange(): void + { + this._mailService.toggleSelectedMail(this.mail.id); + } + + /** + * Toggle star + * + * @param event + */ + toggleStar(event): void + { + event.stopPropagation(); + + this.mail.toggleStar(); + + this._mailService.updateMail(this.mail); + } + + /** + * Toggle Important + * + * @param event + */ + toggleImportant(event): void + { + event.stopPropagation(); + + this.mail.toggleImportant(); + + this._mailService.updateMail(this.mail); + } +} diff --git a/src/app/main/apps/mail/mail-list/mail-list.component.html b/src/app/main/apps/mail/mail-list/mail-list.component.html new file mode 100644 index 00000000..7090440b --- /dev/null +++ b/src/app/main/apps/mail/mail-list/mail-list.component.html @@ -0,0 +1,10 @@ +
+ {{ 'MAIL.NO_MESSAGES' | translate }} +
+ +
+ + +
diff --git a/src/app/main/apps/mail/mail-list/mail-list.component.ts b/src/app/main/apps/mail/mail-list/mail-list.component.ts new file mode 100644 index 00000000..b59ec11e --- /dev/null +++ b/src/app/main/apps/mail/mail-list/mail-list.component.ts @@ -0,0 +1,134 @@ +import { Component, OnDestroy, OnInit } from '@angular/core'; +import { Location } from '@angular/common'; +import { ActivatedRoute } from '@angular/router'; +import { Subject } from 'rxjs'; +import { takeUntil } from 'rxjs/operators'; + +import { fuseAnimations } from '@fuse/animations'; + +import { Mail } from 'app/main/apps/mail/mail.model'; +import { MailService } from 'app/main/apps/mail/mail.service'; + +@Component({ + selector : 'mail-list', + templateUrl: './mail-list.component.html', + styleUrls : ['./mail-list.component.scss'], + animations : fuseAnimations +}) +export class MailListComponent implements OnInit, OnDestroy +{ + mails: Mail[]; + currentMail: Mail; + + // Private + private _unsubscribeAll: Subject; + + /** + * Constructor + * + * @param {ActivatedRoute} _activatedRoute + * @param {MailService} _mailService + * @param {Location} _location + */ + constructor( + private _activatedRoute: ActivatedRoute, + private _mailService: MailService, + private _location: Location + ) + { + // Set the private defaults + this._unsubscribeAll = new Subject(); + } + + // ----------------------------------------------------------------------------------------------------- + // @ Lifecycle hooks + // ----------------------------------------------------------------------------------------------------- + + /** + * On init + */ + ngOnInit(): void + { + // Subscribe to update mails on changes + this._mailService.onMailsChanged + .pipe(takeUntil(this._unsubscribeAll)) + .subscribe(mails => { + this.mails = mails; + }); + + // Subscribe to update current mail on changes + this._mailService.onCurrentMailChanged + .pipe(takeUntil(this._unsubscribeAll)) + .subscribe(currentMail => { + if ( !currentMail ) + { + // Set the current mail id to null to deselect the current mail + this.currentMail = null; + + // Handle the location changes + const labelHandle = this._activatedRoute.snapshot.params.labelHandle, + filterHandle = this._activatedRoute.snapshot.params.filterHandle, + folderHandle = this._activatedRoute.snapshot.params.folderHandle; + + if ( labelHandle ) + { + this._location.go('apps/mail/label/' + labelHandle); + } + else if ( filterHandle ) + { + this._location.go('apps/mail/filter/' + filterHandle); + } + else + { + this._location.go('apps/mail/' + folderHandle); + } + } + else + { + this.currentMail = currentMail; + } + }); + } + + /** + * On destroy + */ + ngOnDestroy(): void + { + // Unsubscribe from all subscriptions + this._unsubscribeAll.next(); + this._unsubscribeAll.complete(); + } + + // ----------------------------------------------------------------------------------------------------- + // @ Public methods + // ----------------------------------------------------------------------------------------------------- + + /** + * Read mail + * + * @param mailId + */ + readMail(mailId): void + { + const labelHandle = this._activatedRoute.snapshot.params.labelHandle, + filterHandle = this._activatedRoute.snapshot.params.filterHandle, + folderHandle = this._activatedRoute.snapshot.params.folderHandle; + + if ( labelHandle ) + { + this._location.go('apps/mail/label/' + labelHandle + '/' + mailId); + } + else if ( filterHandle ) + { + this._location.go('apps/mail/filter/' + filterHandle + '/' + mailId); + } + else + { + this._location.go('apps/mail/' + folderHandle + '/' + mailId); + } + + // Set current mail + this._mailService.setCurrentMail(mailId); + } +} diff --git a/src/app/main/apps/mail/mail.component.html b/src/app/main/apps/mail/mail.component.html new file mode 100644 index 00000000..0a28b1d4 --- /dev/null +++ b/src/app/main/apps/mail/mail.component.html @@ -0,0 +1,107 @@ + diff --git a/src/app/main/apps/mail/mail.component.ts b/src/app/main/apps/mail/mail.component.ts new file mode 100644 index 00000000..27ee6841 --- /dev/null +++ b/src/app/main/apps/mail/mail.component.ts @@ -0,0 +1,193 @@ +import { Component, OnDestroy, OnInit } from '@angular/core'; +import { FormControl } from '@angular/forms'; +import { Subject } from 'rxjs'; +import { debounceTime, distinctUntilChanged, takeUntil } from 'rxjs/operators'; + +import { FuseSidebarService } from '@fuse/components/sidebar/sidebar.service'; +import { FuseTranslationLoaderService } from '@fuse/services/translation-loader.service'; + +import { Mail } from 'app/main/apps/mail/mail.model'; +import { MailService } from 'app/main/apps/mail/mail.service'; + +import { locale as english } from 'app/main/apps/mail//i18n/en'; +import { locale as turkish } from 'app/main/apps/mail//i18n/tr'; + +@Component({ + selector : 'mail', + templateUrl: './mail.component.html', + styleUrls : ['./mail.component.scss'] +}) +export class MailComponent implements OnInit, OnDestroy +{ + hasSelectedMails: boolean; + isIndeterminate: boolean; + folders: any[]; + filters: any[]; + labels: any[]; + searchInput: FormControl; + currentMail: Mail; + + // Private + private _unsubscribeAll: Subject; + + /** + * Constructor + * + * @param {MailService} _mailService + * @param {FuseSidebarService} _fuseSidebarService + * @param {FuseTranslationLoaderService} _fuseTranslationLoaderService + */ + constructor( + private _mailService: MailService, + private _fuseSidebarService: FuseSidebarService, + private _fuseTranslationLoaderService: FuseTranslationLoaderService + ) + { + // Load the translations + this._fuseTranslationLoaderService.loadTranslations(english, turkish); + + // Set the defaults + this.searchInput = new FormControl(''); + + // Set the private defaults + this._unsubscribeAll = new Subject(); + } + + // ----------------------------------------------------------------------------------------------------- + // @ Lifecycle hooks + // ----------------------------------------------------------------------------------------------------- + + /** + * On init + */ + ngOnInit(): void + { + this._mailService.onSelectedMailsChanged + .pipe(takeUntil(this._unsubscribeAll)) + .subscribe(selectedMails => { + setTimeout(() => { + this.hasSelectedMails = selectedMails.length > 0; + this.isIndeterminate = (selectedMails.length !== this._mailService.mails.length && selectedMails.length > 0); + }, 0); + }); + + this._mailService.onFoldersChanged + .pipe(takeUntil(this._unsubscribeAll)) + .subscribe(folders => { + this.folders = this._mailService.folders; + }); + + this._mailService.onFiltersChanged + .pipe(takeUntil(this._unsubscribeAll)) + .subscribe(folders => { + this.filters = this._mailService.filters; + }); + + this._mailService.onLabelsChanged + .pipe(takeUntil(this._unsubscribeAll)) + .subscribe(labels => { + this.labels = this._mailService.labels; + }); + + this._mailService.onCurrentMailChanged + .pipe(takeUntil(this._unsubscribeAll)) + .subscribe(currentMail => { + if ( !currentMail ) + { + this.currentMail = null; + } + else + { + this.currentMail = currentMail; + } + }); + + this.searchInput.valueChanges.pipe( + takeUntil(this._unsubscribeAll), + debounceTime(300), + distinctUntilChanged() + ) + .subscribe(searchText => { + this._mailService.onSearchTextChanged.next(searchText); + }); + } + + /** + * On destroy + */ + ngOnDestroy(): void + { + // Unsubscribe from all subscriptions + this._unsubscribeAll.next(); + this._unsubscribeAll.complete(); + } + + // ----------------------------------------------------------------------------------------------------- + // @ Public methods + // ----------------------------------------------------------------------------------------------------- + + /** + * Toggle select all + */ + toggleSelectAll(): void + { + this._mailService.toggleSelectAll(); + } + + /** + * Select mails + * + * @param filterParameter + * @param filterValue + */ + selectMails(filterParameter?, filterValue?): void + { + this._mailService.selectMails(filterParameter, filterValue); + } + + /** + * Deselect mails + */ + deselectMails(): void + { + this._mailService.deselectMails(); + } + + /** + * Deselect current mail + */ + deselectCurrentMail(): void + { + this._mailService.onCurrentMailChanged.next(null); + } + + /** + * Toggle label on selected mails + * + * @param labelId + */ + toggleLabelOnSelectedMails(labelId): void + { + this._mailService.toggleLabelOnSelectedMails(labelId); + } + + /** + * Set folder on selected mails + * + * @param folderId + */ + setFolderOnSelectedMails(folderId): void + { + this._mailService.setFolderOnSelectedMails(folderId); + } + + /** + * Toggle the sidebar + * + * @param name + */ + toggleSidebar(name): void + { + this._fuseSidebarService.getSidebar(name).toggleOpen(); + } +} diff --git a/src/app/main/apps/mail/sidebars/main/main-sidebar.component.ts b/src/app/main/apps/mail/sidebars/main/main-sidebar.component.ts new file mode 100644 index 00000000..e2d0ae95 --- /dev/null +++ b/src/app/main/apps/mail/sidebars/main/main-sidebar.component.ts @@ -0,0 +1,127 @@ +import { Component, OnDestroy, OnInit } from '@angular/core'; +import { FormGroup } from '@angular/forms'; +import { MatDialog } from '@angular/material'; +import { Subject } from 'rxjs'; +import { takeUntil } from 'rxjs/operators'; + +import { fuseAnimations } from '@fuse/animations'; + +import { MailService } from 'app/main/apps/mail/mail.service'; +import { MailComposeDialogComponent } from 'app/main/apps/mail/dialogs/compose/compose.component'; + +@Component({ + selector : 'mail-main-sidebar', + templateUrl: './main-sidebar.component.html', + styleUrls : ['./main-sidebar.component.scss'], + animations : fuseAnimations +}) +export class MailMainSidebarComponent implements OnInit, OnDestroy +{ + folders: any[]; + filters: any[]; + labels: any[]; + accounts: object; + selectedAccount: string; + dialogRef: any; + + // Private + private _unsubscribeAll: Subject; + + /** + * Constructor + * + * @param {MailService} _mailService + * @param {MatDialog} _matDialog + */ + constructor( + private _mailService: MailService, + public _matDialog: MatDialog + ) + { + // Set the defaults + this.accounts = { + 'creapond' : 'johndoe@creapond.com', + 'withinpixels': 'johndoe@withinpixels.com' + }; + this.selectedAccount = 'creapond'; + + // Set the private defaults + this._unsubscribeAll = new Subject(); + } + + // ----------------------------------------------------------------------------------------------------- + // @ Lifecycle hooks + // ----------------------------------------------------------------------------------------------------- + + /** + * On init + */ + ngOnInit(): void + { + this._mailService.onFoldersChanged + .pipe(takeUntil(this._unsubscribeAll)) + .subscribe(folders => { + this.folders = folders; + }); + + this._mailService.onFiltersChanged + .pipe(takeUntil(this._unsubscribeAll)) + .subscribe(filters => { + this.filters = filters; + }); + + this._mailService.onLabelsChanged + .pipe(takeUntil(this._unsubscribeAll)) + .subscribe(labels => { + this.labels = labels; + }); + } + + /** + * On destroy + */ + ngOnDestroy(): void + { + // Unsubscribe from all subscriptions + this._unsubscribeAll.next(); + this._unsubscribeAll.complete(); + } + + // ----------------------------------------------------------------------------------------------------- + // @ Public methods + // ----------------------------------------------------------------------------------------------------- + + /** + * Compose dialog + */ + composeDialog(): void + { + this.dialogRef = this._matDialog.open(MailComposeDialogComponent, { + panelClass: 'mail-compose-dialog' + }); + this.dialogRef.afterClosed() + .subscribe(response => { + if ( !response ) + { + return; + } + const actionType: string = response[0]; + const formData: FormGroup = response[1]; + switch ( actionType ) + { + /** + * Send + */ + case 'send': + console.log('new Mail', formData.getRawValue()); + break; + /** + * Delete + */ + case 'delete': + console.log('delete Mail'); + break; + } + }); + } +} diff --git a/src/app/main/apps/scrumboard/board/add-list/add-list.component.ts b/src/app/main/apps/scrumboard/board/add-list/add-list.component.ts new file mode 100644 index 00000000..bf74e6b1 --- /dev/null +++ b/src/app/main/apps/scrumboard/board/add-list/add-list.component.ts @@ -0,0 +1,80 @@ +import { Component, EventEmitter, Output, ViewChild } from '@angular/core'; +import { FormBuilder, FormGroup } from '@angular/forms'; + +@Component({ + selector : 'scrumboard-board-add-list', + templateUrl: './add-list.component.html', + styleUrls : ['./add-list.component.scss'] +}) +export class ScrumboardBoardAddListComponent +{ + formActive: boolean; + form: FormGroup; + + @Output() + onListAdd: EventEmitter; + + @ViewChild('nameInput') + nameInputField; + + /** + * Constructor + * + * @param {FormBuilder} _formBuilder + */ + constructor( + private _formBuilder: FormBuilder + ) + { + // Set the defaults + this.formActive = false; + this.onListAdd = new EventEmitter(); + } + + // ----------------------------------------------------------------------------------------------------- + // @ Public methods + // ----------------------------------------------------------------------------------------------------- + + /** + * Open form + */ + openForm(): void + { + this.form = this._formBuilder.group({ + name: [''] + }); + this.formActive = true; + this.focusNameField(); + } + + /** + * Close form + */ + closeForm(): void + { + this.formActive = false; + } + + /** + * Focus to the name field + */ + focusNameField(): void + { + setTimeout(() => { + this.nameInputField.nativeElement.focus(); + }); + } + + /** + * On form submit + */ + onFormSubmit(): void + { + if ( this.form.valid ) + { + this.onListAdd.next(this.form.getRawValue().name); + this.formActive = false; + } + } + +} diff --git a/src/app/main/apps/scrumboard/board/board.component.ts b/src/app/main/apps/scrumboard/board/board.component.ts new file mode 100644 index 00000000..d225089c --- /dev/null +++ b/src/app/main/apps/scrumboard/board/board.component.ts @@ -0,0 +1,100 @@ +import { Component, OnDestroy, OnInit } from '@angular/core'; +import { Location } from '@angular/common'; +import { ActivatedRoute } from '@angular/router'; +import { Subject } from 'rxjs'; +import { takeUntil } from 'rxjs/operators'; + +import { fuseAnimations } from '@fuse/animations'; + +import { ScrumboardService } from 'app/main/apps/scrumboard/scrumboard.service'; +import { List } from 'app/main/apps/scrumboard/list.model'; + +@Component({ + selector : 'scrumboard-board', + templateUrl: './board.component.html', + styleUrls : ['./board.component.scss'], + animations : fuseAnimations +}) +export class ScrumboardBoardComponent implements OnInit, OnDestroy +{ + board: any; + + // Private + private _unsubscribeAll: Subject; + + constructor( + private _activatedRoute: ActivatedRoute, + private _location: Location, + private _scrumboardService: ScrumboardService + ) + { + // Set the private defaults + this._unsubscribeAll = new Subject(); + } + + // ----------------------------------------------------------------------------------------------------- + // @ Lifecycle hooks + // ----------------------------------------------------------------------------------------------------- + + /** + * On init + */ + ngOnInit(): void + { + this._scrumboardService.onBoardChanged + .pipe(takeUntil(this._unsubscribeAll)) + .subscribe(board => { + this.board = board; + }); + } + + /** + * On destroy + */ + ngOnDestroy(): void + { + // Unsubscribe from all subscriptions + this._unsubscribeAll.next(); + this._unsubscribeAll.complete(); + } + + // ----------------------------------------------------------------------------------------------------- + // @ Public methods + // ----------------------------------------------------------------------------------------------------- + + /** + * On list add + * + * @param newListName + */ + onListAdd(newListName): void + { + if ( newListName === '' ) + { + return; + } + + this._scrumboardService.addList(new List({name: newListName})); + } + + /** + * On board name changed + * + * @param newName + */ + onBoardNameChanged(newName): void + { + this._scrumboardService.updateBoard(); + this._location.go('/apps/scrumboard/boards/' + this.board.id + '/' + this.board.uri); + } + + /** + * On drop + * + * @param ev + */ + onDrop(ev): void + { + this._scrumboardService.updateBoard(); + } +} diff --git a/src/app/main/apps/scrumboard/board/dialogs/card/label-selector/label-selector.component.ts b/src/app/main/apps/scrumboard/board/dialogs/card/label-selector/label-selector.component.ts new file mode 100644 index 00000000..46cb3bca --- /dev/null +++ b/src/app/main/apps/scrumboard/board/dialogs/card/label-selector/label-selector.component.ts @@ -0,0 +1,114 @@ +import { Component, EventEmitter, Input, OnDestroy, OnInit, Output, ViewEncapsulation } from '@angular/core'; +import { Subject } from 'rxjs'; +import { takeUntil } from 'rxjs/operators'; + +import { fuseAnimations } from '@fuse/animations'; +import { FuseUtils } from '@fuse/utils'; + +import { ScrumboardService } from 'app/main/apps/scrumboard/scrumboard.service'; + +@Component({ + selector : 'scrumboard-label-selector', + templateUrl : './label-selector.component.html', + styleUrls : ['./label-selector.component.scss'], + encapsulation: ViewEncapsulation.None, + animations : fuseAnimations +}) + +export class ScrumboardLabelSelectorComponent implements OnInit, OnDestroy +{ + @Input('card') + card: any; + + @Output() + onCardLabelsChange: EventEmitter; + + board: any; + labelsMenuView: string; + selectedLabel: any; + newLabel: any; + toggleInArray: any; + + // Private + private _unsubscribeAll: Subject; + + /** + * Constructor + * + * @param {ScrumboardService} _scrumboardService + */ + constructor( + private _scrumboardService: ScrumboardService + ) + { + // Set the defaults + this.onCardLabelsChange = new EventEmitter(); + this.labelsMenuView = 'labels'; + this.newLabel = { + 'id' : '', + 'name' : '', + 'color': 'mat-blue-400-bg' + }; + this.toggleInArray = FuseUtils.toggleInArray; + + // Set the private defaults + this._unsubscribeAll = new Subject(); + } + + // ----------------------------------------------------------------------------------------------------- + // @ Lifecycle hooks + // ----------------------------------------------------------------------------------------------------- + + /** + * On init + */ + ngOnInit(): void + { + this._scrumboardService.onBoardChanged + .pipe(takeUntil(this._unsubscribeAll)) + .subscribe(board => { + this.board = board; + }); + } + + /** + * On destroy + */ + ngOnDestroy(): void + { + // Unsubscribe from all subscriptions + this._unsubscribeAll.next(); + this._unsubscribeAll.complete(); + } + + // ----------------------------------------------------------------------------------------------------- + // @ Public methods + // ----------------------------------------------------------------------------------------------------- + + /** + * Card labels changed + */ + cardLabelsChanged(): void + { + this.onCardLabelsChange.next(); + } + + /** + * On label change + */ + onLabelChange(): void + { + this._scrumboardService.updateBoard(); + } + + /** + * Add new label + */ + addNewLabel(): void + { + this.newLabel.id = FuseUtils.generateGUID(); + this.board.labels.push(Object.assign({}, this.newLabel)); + this.newLabel.name = ''; + this.labelsMenuView = 'labels'; + } +} diff --git a/src/app/main/apps/scrumboard/board/list/add-card/add-card.component.ts b/src/app/main/apps/scrumboard/board/list/add-card/add-card.component.ts new file mode 100644 index 00000000..4a2268d3 --- /dev/null +++ b/src/app/main/apps/scrumboard/board/list/add-card/add-card.component.ts @@ -0,0 +1,81 @@ +import { Component, EventEmitter, Output, ViewChild } from '@angular/core'; +import { FormBuilder, FormGroup } from '@angular/forms'; + +@Component({ + selector : 'scrumboard-board-add-card', + templateUrl: './add-card.component.html', + styleUrls : ['./add-card.component.scss'] +}) +export class ScrumboardBoardAddCardComponent +{ + formActive: boolean; + form: FormGroup; + + @Output() + onCardAdd: EventEmitter; + + @ViewChild('nameInput') + nameInputField; + + /** + * Constructor + * + * @param {FormBuilder} _formBuilder + */ + constructor( + private _formBuilder: FormBuilder + ) + { + // Set the defaults + this.formActive = false; + this.onCardAdd = new EventEmitter(); + } + + // ----------------------------------------------------------------------------------------------------- + // @ Public methods + // ----------------------------------------------------------------------------------------------------- + + /** + * Open the form + */ + openForm(): void + { + this.form = this._formBuilder.group({ + name: '' + }); + this.formActive = true; + this.focusNameField(); + } + + /** + * Close the form + */ + closeForm(): void + { + this.formActive = false; + } + + /** + * Focus to the name field + */ + focusNameField(): void + { + setTimeout(() => { + this.nameInputField.nativeElement.focus(); + }); + } + + /** + * On form submit + */ + onFormSubmit(): void + { + if ( this.form.valid ) + { + const cardName = this.form.getRawValue().name; + this.onCardAdd.next(cardName); + this.formActive = false; + } + } +} + diff --git a/src/app/main/apps/scrumboard/board/list/card/card.component.ts b/src/app/main/apps/scrumboard/board/list/card/card.component.ts new file mode 100644 index 00000000..0c47bf23 --- /dev/null +++ b/src/app/main/apps/scrumboard/board/list/card/card.component.ts @@ -0,0 +1,59 @@ +import { Component, Input, OnInit, ViewEncapsulation } from '@angular/core'; +import { ActivatedRoute } from '@angular/router'; +import * as moment from 'moment'; + +@Component({ + selector : 'scrumboard-board-card', + templateUrl : './card.component.html', + styleUrls : ['./card.component.scss'], + encapsulation: ViewEncapsulation.None +}) +export class ScrumboardBoardCardComponent implements OnInit +{ + @Input() + cardId; + + card: any; + board: any; + + /** + * Constructor + * + * @param {ActivatedRoute} _activatedRoute + */ + constructor( + private _activatedRoute: ActivatedRoute + ) + { + } + + // ----------------------------------------------------------------------------------------------------- + // @ Lifecycle hooks + // ----------------------------------------------------------------------------------------------------- + + /** + * On init + */ + ngOnInit(): void + { + this.board = this._activatedRoute.snapshot.data.board; + this.card = this.board.cards.filter((card) => { + return this.cardId === card.id; + })[0]; + } + + // ----------------------------------------------------------------------------------------------------- + // @ Public methods + // ----------------------------------------------------------------------------------------------------- + + /** + * Is the card overdue? + * + * @param cardDate + * @returns {boolean} + */ + isOverdue(cardDate): boolean + { + return moment() > moment(new Date(cardDate)); + } +} diff --git a/src/app/main/apps/scrumboard/board/list/edit-list-name/edit-list-name.component.ts b/src/app/main/apps/scrumboard/board/list/edit-list-name/edit-list-name.component.ts new file mode 100644 index 00000000..55cf831d --- /dev/null +++ b/src/app/main/apps/scrumboard/board/list/edit-list-name/edit-list-name.component.ts @@ -0,0 +1,83 @@ +import { Component, EventEmitter, Input, Output, ViewChild } from '@angular/core'; +import { FormBuilder, FormGroup } from '@angular/forms'; + +@Component({ + selector : 'scrumboard-board-edit-list-name', + templateUrl: './edit-list-name.component.html', + styleUrls : ['./edit-list-name.component.scss'] +}) +export class ScrumboardBoardEditListNameComponent +{ + formActive: boolean; + form: FormGroup; + + @Input() + list; + + @Output() + onNameChanged: EventEmitter; + + @ViewChild('nameInput') + nameInputField; + + /** + * Constructor + * + * @param {FormBuilder} _formBuilder + */ + constructor( + private _formBuilder: FormBuilder + ) + { + // Set the defaults + this.formActive = false; + this.onNameChanged = new EventEmitter(); + } + + // ----------------------------------------------------------------------------------------------------- + // @ Public methods + // ----------------------------------------------------------------------------------------------------- + + /** + * Open the form + */ + openForm(): void + { + this.form = this._formBuilder.group({ + name: [this.list.name] + }); + this.formActive = true; + this.focusNameField(); + } + + /** + * Close the form + */ + closeForm(): void + { + this.formActive = false; + } + + /** + * Focus to the name field + */ + focusNameField(): void + { + setTimeout(() => { + this.nameInputField.nativeElement.focus(); + }); + } + + /** + * On form submit + */ + onFormSubmit(): void + { + if ( this.form.valid ) + { + this.list.name = this.form.getRawValue().name; + this.onNameChanged.next(this.list.name); + this.formActive = false; + } + } +} diff --git a/src/app/main/apps/scrumboard/board/list/list.component.ts b/src/app/main/apps/scrumboard/board/list/list.component.ts new file mode 100644 index 00000000..15093f75 --- /dev/null +++ b/src/app/main/apps/scrumboard/board/list/list.component.ts @@ -0,0 +1,162 @@ +import { Component, Input, OnDestroy, OnInit, ViewChild, ViewEncapsulation } from '@angular/core'; +import { ActivatedRoute } from '@angular/router'; +import { MatDialog, MatDialogRef } from '@angular/material'; +import { Subject } from 'rxjs'; +import { takeUntil } from 'rxjs/operators'; + +import { FuseConfirmDialogComponent } from '@fuse/components/confirm-dialog/confirm-dialog.component'; +import { FusePerfectScrollbarDirective } from '@fuse/directives/fuse-perfect-scrollbar/fuse-perfect-scrollbar.directive'; + +import { ScrumboardService } from 'app/main/apps/scrumboard/scrumboard.service'; +import { Card } from 'app/main/apps/scrumboard/card.model'; +import { ScrumboardCardDialogComponent } from 'app/main/apps/scrumboard/board/dialogs/card/card.component'; + +@Component({ + selector : 'scrumboard-board-list', + templateUrl : './list.component.html', + styleUrls : ['./list.component.scss'], + encapsulation: ViewEncapsulation.None +}) +export class ScrumboardBoardListComponent implements OnInit, OnDestroy +{ + board: any; + dialogRef: any; + + @Input() + list; + + @ViewChild(FusePerfectScrollbarDirective) + listScroll: FusePerfectScrollbarDirective; + + confirmDialogRef: MatDialogRef; + + // Private + private _unsubscribeAll: Subject; + + /** + * Constructor + * + * @param {ActivatedRoute} _activatedRoute + * @param {ScrumboardService} _scrumboardService + * @param {MatDialog} _matDialog + */ + constructor( + private _activatedRoute: ActivatedRoute, + private _scrumboardService: ScrumboardService, + private _matDialog: MatDialog + ) + { + // Set the private defaults + this._unsubscribeAll = new Subject(); + } + + // ----------------------------------------------------------------------------------------------------- + // @ Lifecycle hooks + // ----------------------------------------------------------------------------------------------------- + + /** + * On init + */ + ngOnInit(): void + { + this._scrumboardService.onBoardChanged + .pipe(takeUntil(this._unsubscribeAll)) + .subscribe(board => { + this.board = board; + }); + } + + /** + * On destroy + */ + ngOnDestroy(): void + { + // Unsubscribe from all subscriptions + this._unsubscribeAll.next(); + this._unsubscribeAll.complete(); + } + + // ----------------------------------------------------------------------------------------------------- + // @ Public methods + // ----------------------------------------------------------------------------------------------------- + + /** + * On list name changed + * + * @param newListName + */ + onListNameChanged(newListName): void + { + this.list.name = newListName; + } + + /** + * On card added + * + * @param newCardName + */ + onCardAdd(newCardName): void + { + if ( newCardName === '' ) + { + return; + } + + this._scrumboardService.addCard(this.list.id, new Card({name: newCardName})); + + setTimeout(() => { + this.listScroll.scrollToBottom(0, 400); + }); + } + + /** + * Remove list + * + * @param listId + */ + removeList(listId): void + { + this.confirmDialogRef = this._matDialog.open(FuseConfirmDialogComponent, { + disableClose: false + }); + + this.confirmDialogRef.componentInstance.confirmMessage = 'Are you sure you want to delete the list and it\'s all cards?'; + + this.confirmDialogRef.afterClosed().subscribe(result => { + if ( result ) + { + this._scrumboardService.removeList(listId); + } + }); + } + + /** + * Open card dialog + * + * @param cardId + */ + openCardDialog(cardId): void + { + this.dialogRef = this._matDialog.open(ScrumboardCardDialogComponent, { + panelClass: 'scrumboard-card-dialog', + data : { + cardId: cardId, + listId: this.list.id + } + }); + this.dialogRef.afterClosed() + .subscribe(response => { + + }); + } + + /** + * On drop + * + * @param ev + */ + onDrop(ev): void + { + this._scrumboardService.updateBoard(); + } +} diff --git a/src/app/main/apps/scrumboard/board/sidenavs/settings/board-color-selector/board-color-selector.component.ts b/src/app/main/apps/scrumboard/board/sidenavs/settings/board-color-selector/board-color-selector.component.ts new file mode 100644 index 00000000..239ee075 --- /dev/null +++ b/src/app/main/apps/scrumboard/board/sidenavs/settings/board-color-selector/board-color-selector.component.ts @@ -0,0 +1,78 @@ +import { Component, OnDestroy, OnInit } from '@angular/core'; +import { Subject } from 'rxjs'; +import { takeUntil } from 'rxjs/operators'; + +import { MatColors } from '@fuse/mat-colors'; + +import { ScrumboardService } from 'app/main/apps/scrumboard/scrumboard.service'; + +@Component({ + selector : 'scrumboard-board-color-selector', + templateUrl: './board-color-selector.component.html', + styleUrls : ['./board-color-selector.component.scss'] +}) +export class ScrumboardBoardColorSelectorComponent implements OnInit, OnDestroy +{ + colors: any; + board: any; + + // Private + private _unsubscribeAll: Subject; + + /** + * Constructor + * + * @param {ScrumboardService} _scrumboardService + */ + constructor( + private _scrumboardService: ScrumboardService + ) + { + // Set the defaults + this.colors = MatColors.all; + + // Set the private defaults + this._unsubscribeAll = new Subject(); + } + + // ----------------------------------------------------------------------------------------------------- + // @ Lifecycle hooks + // ----------------------------------------------------------------------------------------------------- + + /** + * On init + */ + ngOnInit(): void + { + this._scrumboardService.onBoardChanged + .pipe(takeUntil(this._unsubscribeAll)) + .subscribe(board => { + this.board = board; + }); + } + + /** + * On destroy + */ + ngOnDestroy(): void + { + // Unsubscribe from all subscriptions + this._unsubscribeAll.next(); + this._unsubscribeAll.complete(); + } + + // ----------------------------------------------------------------------------------------------------- + // @ Public methods + // ----------------------------------------------------------------------------------------------------- + + /** + * Set the color + * + * @param color + */ + setColor(color): void + { + this.board.settings.color = color; + this._scrumboardService.updateBoard(); + } +} diff --git a/src/app/main/apps/scrumboard/board/sidenavs/settings/settings.component.ts b/src/app/main/apps/scrumboard/board/sidenavs/settings/settings.component.ts new file mode 100644 index 00000000..95d3b273 --- /dev/null +++ b/src/app/main/apps/scrumboard/board/sidenavs/settings/settings.component.ts @@ -0,0 +1,80 @@ +import { Component, OnDestroy, OnInit } from '@angular/core'; + +import { fuseAnimations } from '@fuse/animations'; +import { ScrumboardService } from 'app/main/apps/scrumboard/scrumboard.service'; +import { Subject } from 'rxjs'; +import { takeUntil } from 'rxjs/operators'; + +@Component({ + selector : 'scrumboard-board-settings', + templateUrl: './settings.component.html', + styleUrls : ['./settings.component.scss'], + animations : fuseAnimations +}) +export class ScrumboardBoardSettingsSidenavComponent implements OnInit, OnDestroy +{ + board: any; + view: string; + + // Private + private _unsubscribeAll: Subject; + + constructor( + private scrumboardService: ScrumboardService + ) + { + // Set the defaults + this.view = 'main'; + + // Set the private defaults + this._unsubscribeAll = new Subject(); + } + + // ----------------------------------------------------------------------------------------------------- + // @ Lifecycle hooks + // ----------------------------------------------------------------------------------------------------- + + /** + * On init + */ + ngOnInit(): void + { + this.scrumboardService.onBoardChanged + .pipe(takeUntil(this._unsubscribeAll)) + .subscribe(board => { + this.board = board; + }); + } + + /** + * On destroy + */ + ngOnDestroy(): void + { + // Unsubscribe from all subscriptions + this._unsubscribeAll.next(); + this._unsubscribeAll.complete(); + } + + // ----------------------------------------------------------------------------------------------------- + // @ Public methods + // ----------------------------------------------------------------------------------------------------- + + /** + * Toggle card cover + */ + toggleCardCover(): void + { + this.board.settings.cardCoverImages = !this.board.settings.cardCoverImages; + this.scrumboardService.updateBoard(); + } + + /** + * Toggle subscription + */ + toggleSubscription(): void + { + this.board.settings.subscribed = !this.board.settings.subscribed; + this.scrumboardService.updateBoard(); + } +} diff --git a/src/app/main/apps/scrumboard/scrumboard.component.ts b/src/app/main/apps/scrumboard/scrumboard.component.ts new file mode 100644 index 00000000..b35fc570 --- /dev/null +++ b/src/app/main/apps/scrumboard/scrumboard.component.ts @@ -0,0 +1,79 @@ +import { Component, OnDestroy, OnInit } from '@angular/core'; +import { Router } from '@angular/router'; +import { Subject } from 'rxjs'; +import { takeUntil } from 'rxjs/operators'; + +import { fuseAnimations } from '@fuse/animations'; + +import { ScrumboardService } from 'app/main/apps/scrumboard/scrumboard.service'; +import { Board } from 'app/main/apps/scrumboard/board.model'; + +@Component({ + selector : 'scrumboard', + templateUrl: './scrumboard.component.html', + styleUrls : ['./scrumboard.component.scss'], + animations : fuseAnimations +}) +export class ScrumboardComponent implements OnInit, OnDestroy +{ + boards: any[]; + + // Private + private _unsubscribeAll: Subject; + + /** + * Constructor + * + * @param {Router} _router + * @param {ScrumboardService} _scrumboardService + */ + constructor( + private _router: Router, + private _scrumboardService: ScrumboardService + ) + { + // Set the private defaults + this._unsubscribeAll = new Subject(); + } + + // ----------------------------------------------------------------------------------------------------- + // @ Lifecycle hooks + // ----------------------------------------------------------------------------------------------------- + + /** + * On init + */ + ngOnInit(): void + { + this._scrumboardService.onBoardsChanged + .pipe(takeUntil(this._unsubscribeAll)) + .subscribe(boards => { + this.boards = boards; + }); + } + + /** + * On destroy + */ + ngOnDestroy(): void + { + // Unsubscribe from all subscriptions + this._unsubscribeAll.next(); + this._unsubscribeAll.complete(); + } + + // ----------------------------------------------------------------------------------------------------- + // @ Public methods + // ----------------------------------------------------------------------------------------------------- + + /** + * New board + */ + newBoard(): void + { + const newBoard = new Board({}); + this._scrumboardService.createNewBoard(newBoard).then(() => { + this._router.navigate(['/apps/scrumboard/boards/' + newBoard.id + '/' + newBoard.uri]); + }); + } +} diff --git a/src/app/main/apps/scrumboard/scrumboard.module.ts b/src/app/main/apps/scrumboard/scrumboard.module.ts new file mode 100644 index 00000000..eba8e392 --- /dev/null +++ b/src/app/main/apps/scrumboard/scrumboard.module.ts @@ -0,0 +1,92 @@ +import { NgModule } from '@angular/core'; +import { RouterModule, Routes } from '@angular/router'; +import { MatButtonModule, MatCheckboxModule, MatChipsModule, MatDatepickerModule, MatDialogModule, MatFormFieldModule, MatIconModule, MatInputModule, MatListModule, MatMenuModule, MatProgressBarModule, MatRippleModule, MatSidenavModule, MatToolbarModule, MatTooltipModule } from '@angular/material'; +import { NgxDnDModule } from '@swimlane/ngx-dnd'; + +import { FuseSharedModule } from '@fuse/shared.module'; +import { FuseConfirmDialogModule, FuseMaterialColorPickerModule } from '@fuse/components'; + +import { BoardResolve, ScrumboardService } from 'app/main/apps/scrumboard/scrumboard.service'; +import { ScrumboardComponent } from 'app/main/apps/scrumboard/scrumboard.component'; +import { ScrumboardBoardComponent } from 'app/main/apps/scrumboard/board/board.component'; +import { ScrumboardBoardListComponent } from 'app/main/apps/scrumboard/board/list/list.component'; +import { ScrumboardBoardCardComponent } from 'app/main/apps/scrumboard/board/list/card/card.component'; +import { ScrumboardBoardEditListNameComponent } from 'app/main/apps/scrumboard/board/list/edit-list-name/edit-list-name.component'; +import { ScrumboardBoardAddCardComponent } from 'app/main/apps/scrumboard/board/list/add-card/add-card.component'; +import { ScrumboardBoardAddListComponent } from 'app/main/apps/scrumboard/board/add-list/add-list.component'; +import { ScrumboardCardDialogComponent } from 'app/main/apps/scrumboard/board/dialogs/card/card.component'; +import { ScrumboardLabelSelectorComponent } from 'app/main/apps/scrumboard/board/dialogs/card/label-selector/label-selector.component'; +import { ScrumboardEditBoardNameComponent } from 'app/main/apps/scrumboard/board/edit-board-name/edit-board-name.component'; +import { ScrumboardBoardSettingsSidenavComponent } from 'app/main/apps/scrumboard/board/sidenavs/settings/settings.component'; +import { ScrumboardBoardColorSelectorComponent } from 'app/main/apps/scrumboard/board/sidenavs/settings/board-color-selector/board-color-selector.component'; + +const routes: Routes = [ + { + path : 'boards', + component: ScrumboardComponent, + resolve : { + scrumboard: ScrumboardService + } + }, + { + path : 'boards/:boardId/:boardUri', + component: ScrumboardBoardComponent, + resolve : { + board: BoardResolve + } + }, + { + path : '**', + redirectTo: 'boards' + } +]; + +@NgModule({ + declarations : [ + ScrumboardComponent, + ScrumboardBoardComponent, + ScrumboardBoardListComponent, + ScrumboardBoardCardComponent, + ScrumboardBoardEditListNameComponent, + ScrumboardBoardAddCardComponent, + ScrumboardBoardAddListComponent, + ScrumboardCardDialogComponent, + ScrumboardLabelSelectorComponent, + ScrumboardEditBoardNameComponent, + ScrumboardBoardSettingsSidenavComponent, + ScrumboardBoardColorSelectorComponent + ], + imports : [ + RouterModule.forChild(routes), + + MatButtonModule, + MatCheckboxModule, + MatChipsModule, + MatDatepickerModule, + MatDialogModule, + MatFormFieldModule, + MatIconModule, + MatInputModule, + MatListModule, + MatMenuModule, + MatProgressBarModule, + MatRippleModule, + MatSidenavModule, + MatToolbarModule, + MatTooltipModule, + + NgxDnDModule, + + FuseSharedModule, + FuseConfirmDialogModule, + FuseMaterialColorPickerModule + ], + providers : [ + ScrumboardService, + BoardResolve + ], + entryComponents: [ScrumboardCardDialogComponent] +}) +export class ScrumboardModule +{ +} diff --git a/src/app/main/apps/todo/sidebars/main/main-sidebar.component.ts b/src/app/main/apps/todo/sidebars/main/main-sidebar.component.ts new file mode 100644 index 00000000..bf636191 --- /dev/null +++ b/src/app/main/apps/todo/sidebars/main/main-sidebar.component.ts @@ -0,0 +1,96 @@ +import { Component, OnDestroy, OnInit } from '@angular/core'; +import { Router } from '@angular/router'; +import { Subject } from 'rxjs'; +import { takeUntil } from 'rxjs/operators'; + +import { fuseAnimations } from '@fuse/animations'; + +import { TodoService } from 'app/main/apps/todo/todo.service'; + +@Component({ + selector : 'todo-main-sidebar', + templateUrl: './main-sidebar.component.html', + styleUrls : ['./main-sidebar.component.scss'], + animations : fuseAnimations +}) +export class TodoMainSidebarComponent implements OnInit, OnDestroy +{ + folders: any[]; + filters: any[]; + tags: any[]; + accounts: object; + selectedAccount: string; + + // Private + private _unsubscribeAll: Subject; + + /** + * Constructor + * + * @param {TodoService} _todoService + * @param {Router} _router + */ + constructor( + private _todoService: TodoService, + private _router: Router + ) + { + // Set the defaults + this.accounts = { + 'creapond' : 'johndoe@creapond.com', + 'withinpixels': 'johndoe@withinpixels.com' + }; + this.selectedAccount = 'creapond'; + + // Set the private defaults + this._unsubscribeAll = new Subject(); + } + + // ----------------------------------------------------------------------------------------------------- + // @ Lifecycle hooks + // ----------------------------------------------------------------------------------------------------- + + /** + * On init + */ + ngOnInit(): void + { + this._todoService.onFiltersChanged + .pipe(takeUntil(this._unsubscribeAll)) + .subscribe(filters => { + this.filters = filters; + }); + + this._todoService.onTagsChanged + .pipe(takeUntil(this._unsubscribeAll)) + .subscribe(tags => { + this.tags = tags; + }); + } + + /** + * On destroy + */ + ngOnDestroy(): void + { + // Unsubscribe from all subscriptions + this._unsubscribeAll.next(); + this._unsubscribeAll.complete(); + } + + // ----------------------------------------------------------------------------------------------------- + // @ Public methods + // ----------------------------------------------------------------------------------------------------- + + /** + * New todo + */ + newTodo(): void + { + this._router.navigate(['/apps/todo/all']).then(() => { + setTimeout(() => { + this._todoService.onNewTodoClicked.next(''); + }); + }); + } +} diff --git a/src/app/main/apps/todo/todo-details/todo-details.component.ts b/src/app/main/apps/todo/todo-details/todo-details.component.ts new file mode 100644 index 00000000..07f6b6fc --- /dev/null +++ b/src/app/main/apps/todo/todo-details/todo-details.component.ts @@ -0,0 +1,219 @@ +import { Component, OnDestroy, OnInit, ViewChild } from '@angular/core'; +import { FormBuilder, FormGroup } from '@angular/forms'; +import { Subject } from 'rxjs'; +import { debounceTime, distinctUntilChanged, takeUntil } from 'rxjs/operators'; + +import { FuseUtils } from '@fuse/utils'; +import { fuseAnimations } from '@fuse/animations'; + +import { Todo } from 'app/main/apps/todo/todo.model'; +import { TodoService } from 'app/main/apps/todo/todo.service'; + +@Component({ + selector : 'todo-details', + templateUrl: './todo-details.component.html', + styleUrls : ['./todo-details.component.scss'], + animations : fuseAnimations +}) +export class TodoDetailsComponent implements OnInit, OnDestroy +{ + todo: Todo; + tags: any[]; + formType: string; + todoForm: FormGroup; + + @ViewChild('titleInput') + titleInputField; + + // Private + private _unsubscribeAll: Subject; + + /** + * Constructor + * + * @param {TodoService} _todoService + * @param {FormBuilder} _formBuilder + */ + constructor( + private _todoService: TodoService, + private _formBuilder: FormBuilder + ) + { + // Set the private defaults + this._unsubscribeAll = new Subject(); + } + + // ----------------------------------------------------------------------------------------------------- + // @ Lifecycle hooks + // ----------------------------------------------------------------------------------------------------- + + /** + * On init + */ + ngOnInit(): void + { + // Subscribe to update the current todo + this._todoService.onCurrentTodoChanged + .pipe(takeUntil(this._unsubscribeAll)) + .subscribe(([todo, formType]) => { + + if ( todo && formType === 'edit' ) + { + this.formType = 'edit'; + this.todo = todo; + this.todoForm = this.createTodoForm(); + + this.todoForm.valueChanges + .pipe( + takeUntil(this._unsubscribeAll), + debounceTime(500), + distinctUntilChanged() + ) + .subscribe(data => { + this._todoService.updateTodo(data); + }); + } + }); + + // Subscribe to update on tag change + this._todoService.onTagsChanged + .pipe(takeUntil(this._unsubscribeAll)) + .subscribe(labels => { + this.tags = labels; + }); + + // Subscribe to update on tag change + this._todoService.onNewTodoClicked + .pipe(takeUntil(this._unsubscribeAll)) + .subscribe(() => { + this.todo = new Todo({}); + this.todo.id = FuseUtils.generateGUID(); + this.formType = 'new'; + this.todoForm = this.createTodoForm(); + this.focusTitleField(); + this._todoService.onCurrentTodoChanged.next([this.todo, 'new']); + }); + } + + /** + * On destroy + */ + ngOnDestroy(): void + { + // Unsubscribe from all subscriptions + this._unsubscribeAll.next(); + this._unsubscribeAll.complete(); + } + + // ----------------------------------------------------------------------------------------------------- + // @ Public methods + // ----------------------------------------------------------------------------------------------------- + + /** + * Focus title field + */ + focusTitleField(): void + { + setTimeout(() => { + this.titleInputField.nativeElement.focus(); + }); + } + + /** + * Create todo form + * + * @returns {FormGroup} + */ + createTodoForm(): FormGroup + { + return this._formBuilder.group({ + 'id' : [this.todo.id], + 'title' : [this.todo.title], + 'notes' : [this.todo.notes], + 'startDate': [this.todo.startDate], + 'dueDate' : [this.todo.dueDate], + 'completed': [this.todo.completed], + 'starred' : [this.todo.starred], + 'important': [this.todo.important], + 'deleted' : [this.todo.deleted], + 'tags' : [this.todo.tags] + }); + } + + /** + * Toggle star + * + * @param event + */ + toggleStar(event): void + { + event.stopPropagation(); + this.todo.toggleStar(); + this._todoService.updateTodo(this.todo); + } + + /** + * Toggle important + * + * @param event + */ + toggleImportant(event): void + { + event.stopPropagation(); + this.todo.toggleImportant(); + this._todoService.updateTodo(this.todo); + } + + /** + * Toggle Completed + * + * @param event + */ + toggleCompleted(event): void + { + event.stopPropagation(); + this.todo.toggleCompleted(); + this._todoService.updateTodo(this.todo); + } + + /** + * Toggle Deleted + * + * @param event + */ + toggleDeleted(event): void + { + event.stopPropagation(); + this.todo.toggleDeleted(); + this._todoService.updateTodo(this.todo); + } + + /** + * Toggle tag on todo + * + * @param tagId + */ + toggleTagOnTodo(tagId): void + { + this._todoService.toggleTagOnTodo(tagId, this.todo); + } + + /** + * Has tag? + * + * @param tagId + * @returns {any} + */ + hasTag(tagId): any + { + return this._todoService.hasTag(tagId, this.todo); + } + + /** + * Add todo + */ + addTodo(): void + { + this._todoService.updateTodo(this.todoForm.getRawValue()); + } +} diff --git a/src/app/main/apps/todo/todo-list/todo-list-item/todo-list-item.component.ts b/src/app/main/apps/todo/todo-list/todo-list-item/todo-list-item.component.ts new file mode 100644 index 00000000..75d9a1ef --- /dev/null +++ b/src/app/main/apps/todo/todo-list/todo-list-item/todo-list-item.component.ts @@ -0,0 +1,148 @@ +import { Component, HostBinding, Input, OnDestroy, OnInit, ViewEncapsulation } from '@angular/core'; +import { ActivatedRoute } from '@angular/router'; +import { Subject, Subscription } from 'rxjs'; +import { Todo } from 'app/main/apps/todo/todo.model'; +import { TodoService } from 'app/main/apps/todo/todo.service'; +import { takeUntil } from 'rxjs/operators'; + +@Component({ + selector : 'todo-list-item', + templateUrl : './todo-list-item.component.html', + styleUrls : ['./todo-list-item.component.scss'], + encapsulation: ViewEncapsulation.None +}) +export class TodoListItemComponent implements OnInit, OnDestroy +{ + tags: any[]; + + @Input() + todo: Todo; + + @HostBinding('class.selected') + selected: boolean; + + @HostBinding('class.completed') + completed: boolean; + + @HostBinding('class.move-disabled') + moveDisabled: boolean; + + // Private + private _unsubscribeAll: Subject; + + /** + * Constructor + * + * @param {TodoService} _todoService + * @param {ActivatedRoute} _activatedRoute + */ + constructor( + private _todoService: TodoService, + private _activatedRoute: ActivatedRoute + ) + { + // Disable move if path is not /all + if ( _activatedRoute.snapshot.url[0].path !== 'all' ) + { + this.moveDisabled = true; + } + + // Set the private defaults + this._unsubscribeAll = new Subject(); + } + + // ----------------------------------------------------------------------------------------------------- + // @ Lifecycle hooks + // ----------------------------------------------------------------------------------------------------- + + /** + * On init + */ + ngOnInit(): void + { + // Set the initial values + this.todo = new Todo(this.todo); + this.completed = this.todo.completed; + + // Subscribe to update on selected todo change + this._todoService.onSelectedTodosChanged + .pipe(takeUntil(this._unsubscribeAll)) + .subscribe(selectedTodos => { + this.selected = false; + + if ( selectedTodos.length > 0 ) + { + for ( const todo of selectedTodos ) + { + if ( todo.id === this.todo.id ) + { + this.selected = true; + break; + } + } + } + }); + + // Subscribe to update on tag change + this._todoService.onTagsChanged + .pipe(takeUntil(this._unsubscribeAll)) + .subscribe(tags => { + this.tags = tags; + }); + } + + /** + * On destroy + */ + ngOnDestroy(): void + { + // Unsubscribe from all subscriptions + this._unsubscribeAll.next(); + this._unsubscribeAll.complete(); + } + + // ----------------------------------------------------------------------------------------------------- + // @ Public methods + // ----------------------------------------------------------------------------------------------------- + + /** + * On selected change + */ + onSelectedChange(): void + { + this._todoService.toggleSelectedTodo(this.todo.id); + } + + /** + * Toggle star + */ + toggleStar(event): void + { + event.stopPropagation(); + + this.todo.toggleStar(); + this._todoService.updateTodo(this.todo); + } + + /** + * Toggle Important + */ + toggleImportant(event): void + { + event.stopPropagation(); + + this.todo.toggleImportant(); + this._todoService.updateTodo(this.todo); + } + + /** + * Toggle Completed + */ + toggleCompleted(event): void + { + event.stopPropagation(); + + this.todo.toggleCompleted(); + this._todoService.updateTodo(this.todo); + } +} diff --git a/src/app/main/apps/todo/todo-list/todo-list.component.html b/src/app/main/apps/todo/todo-list/todo-list.component.html new file mode 100644 index 00000000..8fb8f82a --- /dev/null +++ b/src/app/main/apps/todo/todo-list/todo-list.component.html @@ -0,0 +1,14 @@ +
+ There are no todos! +
+
+ + +
diff --git a/src/app/main/apps/todo/todo-list/todo-list.component.ts b/src/app/main/apps/todo/todo-list/todo-list.component.ts new file mode 100644 index 00000000..3f006da4 --- /dev/null +++ b/src/app/main/apps/todo/todo-list/todo-list.component.ts @@ -0,0 +1,126 @@ +import { Component, OnDestroy, OnInit } from '@angular/core'; +import { Location } from '@angular/common'; +import { ActivatedRoute } from '@angular/router'; +import { Subject } from 'rxjs'; + +import { fuseAnimations } from '@fuse/animations'; + +import { Todo } from 'app/main/apps/todo/todo.model'; +import { TodoService } from 'app/main/apps/todo/todo.service'; +import { takeUntil } from 'rxjs/operators'; + +@Component({ + selector : 'todo-list', + templateUrl: './todo-list.component.html', + styleUrls : ['./todo-list.component.scss'], + animations : fuseAnimations +}) +export class TodoListComponent implements OnInit, OnDestroy +{ + todos: Todo[]; + currentTodo: Todo; + + // Private + private _unsubscribeAll: Subject; + + /** + * Constructor + * + * @param {ActivatedRoute} _activatedRoute + * @param {TodoService} _todoService + * @param {Location} _location + */ + constructor( + private _activatedRoute: ActivatedRoute, + private _todoService: TodoService, + private _location: Location + ) + { + // Set the private defaults + this._unsubscribeAll = new Subject(); + } + + // ----------------------------------------------------------------------------------------------------- + // @ Lifecycle hooks + // ----------------------------------------------------------------------------------------------------- + + /** + * On init + */ + ngOnInit(): void + { + // Subscribe to update todos on changes + this._todoService.onTodosChanged + .pipe(takeUntil(this._unsubscribeAll)) + .subscribe(todos => { + this.todos = todos; + }); + + // Subscribe to update current todo on changes + this._todoService.onCurrentTodoChanged + .pipe(takeUntil(this._unsubscribeAll)) + .subscribe(currentTodo => { + if ( !currentTodo ) + { + // Set the current todo id to null to deselect the current todo + this.currentTodo = null; + + // Handle the location changes + const tagHandle = this._activatedRoute.snapshot.params.tagHandle, + filterHandle = this._activatedRoute.snapshot.params.filterHandle; + + if ( tagHandle ) + { + this._location.go('apps/todo/tag/' + tagHandle); + } + else if ( filterHandle ) + { + this._location.go('apps/todo/filter/' + filterHandle); + } + else + { + this._location.go('apps/todo/all'); + } + } + else + { + this.currentTodo = currentTodo; + } + }); + } + + /** + * On destroy + */ + ngOnDestroy(): void + { + // Unsubscribe from all subscriptions + this._unsubscribeAll.next(); + this._unsubscribeAll.complete(); + } + + // ----------------------------------------------------------------------------------------------------- + // @ Public methods + // ----------------------------------------------------------------------------------------------------- + + /** + * Read todo + * + * @param todoId + */ + readTodo(todoId): void + { + // Set current todo + this._todoService.setCurrentTodo(todoId); + } + + /** + * On drop + * + * @param ev + */ + onDrop(ev): void + { + + } +} diff --git a/src/app/main/apps/todo/todo.component.html b/src/app/main/apps/todo/todo.component.html new file mode 100644 index 00000000..bd120432 --- /dev/null +++ b/src/app/main/apps/todo/todo.component.html @@ -0,0 +1,93 @@ + diff --git a/src/app/main/apps/todo/todo.component.ts b/src/app/main/apps/todo/todo.component.ts new file mode 100644 index 00000000..d3f22a4b --- /dev/null +++ b/src/app/main/apps/todo/todo.component.ts @@ -0,0 +1,171 @@ +import { Component, OnDestroy, OnInit } from '@angular/core'; +import { FormControl } from '@angular/forms'; +import { Subject } from 'rxjs'; +import { debounceTime, distinctUntilChanged, takeUntil } from 'rxjs/operators'; + +import { fuseAnimations } from '@fuse/animations'; +import { FuseSidebarService } from '@fuse/components/sidebar/sidebar.service'; + +import { Todo } from 'app/main/apps/todo/todo.model'; +import { TodoService } from 'app/main/apps/todo/todo.service'; + +@Component({ + selector : 'todo', + templateUrl: './todo.component.html', + styleUrls : ['./todo.component.scss'], + animations : fuseAnimations +}) +export class TodoComponent implements OnInit, OnDestroy +{ + hasSelectedTodos: boolean; + isIndeterminate: boolean; + filters: any[]; + tags: any[]; + searchInput: FormControl; + currentTodo: Todo; + + // Private + private _unsubscribeAll: Subject; + + /** + * Constructor + * + * @param {FuseSidebarService} _fuseSidebarService + * @param {TodoService} _todoService + */ + constructor( + private _fuseSidebarService: FuseSidebarService, + private _todoService: TodoService + ) + { + // Set the defaults + this.searchInput = new FormControl(''); + + // Set the private defaults + this._unsubscribeAll = new Subject(); + } + + // ----------------------------------------------------------------------------------------------------- + // @ Lifecycle hooks + // ----------------------------------------------------------------------------------------------------- + + /** + * On init + */ + ngOnInit(): void + { + this._todoService.onSelectedTodosChanged + .pipe(takeUntil(this._unsubscribeAll)) + .subscribe(selectedTodos => { + + setTimeout(() => { + this.hasSelectedTodos = selectedTodos.length > 0; + this.isIndeterminate = (selectedTodos.length !== this._todoService.todos.length && selectedTodos.length > 0); + }, 0); + }); + + this._todoService.onFiltersChanged + .pipe(takeUntil(this._unsubscribeAll)) + .subscribe(folders => { + this.filters = this._todoService.filters; + }); + + this._todoService.onTagsChanged + .pipe(takeUntil(this._unsubscribeAll)) + .subscribe(tags => { + this.tags = this._todoService.tags; + }); + + this.searchInput.valueChanges + .pipe( + takeUntil(this._unsubscribeAll), + debounceTime(300), + distinctUntilChanged() + ) + .subscribe(searchText => { + this._todoService.onSearchTextChanged.next(searchText); + }); + + this._todoService.onCurrentTodoChanged + .pipe(takeUntil(this._unsubscribeAll)) + .subscribe(([currentTodo, formType]) => { + if ( !currentTodo ) + { + this.currentTodo = null; + } + else + { + this.currentTodo = currentTodo; + } + }); + } + + /** + * On destroy + */ + ngOnDestroy(): void + { + // Unsubscribe from all subscriptions + this._unsubscribeAll.next(); + this._unsubscribeAll.complete(); + } + + // ----------------------------------------------------------------------------------------------------- + // @ Public methods + // ----------------------------------------------------------------------------------------------------- + + /** + * Deselect current todo + */ + deselectCurrentTodo(): void + { + this._todoService.onCurrentTodoChanged.next([null, null]); + } + + /** + * Toggle select all + */ + toggleSelectAll(): void + { + this._todoService.toggleSelectAll(); + } + + /** + * Select todos + * + * @param filterParameter + * @param filterValue + */ + selectTodos(filterParameter?, filterValue?): void + { + this._todoService.selectTodos(filterParameter, filterValue); + } + + /** + * Deselect todos + */ + deselectTodos(): void + { + this._todoService.deselectTodos(); + } + + /** + * Toggle tag on selected todos + * + * @param tagId + */ + toggleTagOnSelectedTodos(tagId): void + { + this._todoService.toggleTagOnSelectedTodos(tagId); + } + + /** + * Toggle the sidebar + * + * @param name + */ + toggleSidebar(name): void + { + this._fuseSidebarService.getSidebar(name).toggleOpen(); + } +} diff --git a/src/app/main/content/content.component.html b/src/app/main/content/content.component.html deleted file mode 100644 index 90c6b646..00000000 --- a/src/app/main/content/content.component.html +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/src/app/main/content/content.component.scss b/src/app/main/content/content.component.scss deleted file mode 100644 index 64b48f72..00000000 --- a/src/app/main/content/content.component.scss +++ /dev/null @@ -1,3 +0,0 @@ -:host { - z-index: 1; -} \ No newline at end of file diff --git a/src/app/main/content/content.component.ts b/src/app/main/content/content.component.ts deleted file mode 100644 index 1f2aedee..00000000 --- a/src/app/main/content/content.component.ts +++ /dev/null @@ -1,70 +0,0 @@ -import { Component, HostBinding, OnDestroy } from '@angular/core'; -import { ActivatedRoute, NavigationEnd, Router } from '@angular/router'; - -import { Subscription } from 'rxjs'; -import { filter, map } from 'rxjs/operators'; - -import { fuseAnimations } from '@fuse/animations/index'; -import { FuseConfigService } from '@fuse/services/config.service'; - -@Component({ - selector : 'fuse-content', - templateUrl: './content.component.html', - styleUrls : ['./content.component.scss'], - animations : fuseAnimations -}) -export class FuseContentComponent implements OnDestroy -{ - onConfigChanged: Subscription; - fuseSettings: any; - - @HostBinding('@routerTransitionUp') routeAnimationUp = false; - @HostBinding('@routerTransitionDown') routeAnimationDown = false; - @HostBinding('@routerTransitionRight') routeAnimationRight = false; - @HostBinding('@routerTransitionLeft') routeAnimationLeft = false; - @HostBinding('@routerTransitionFade') routeAnimationFade = false; - - constructor( - private router: Router, - private activatedRoute: ActivatedRoute, - private fuseConfig: FuseConfigService - ) - { - this.router.events.pipe( - filter((event) => event instanceof NavigationEnd), - map(() => this.activatedRoute) - ).subscribe((event) => { - switch ( this.fuseSettings.routerAnimation ) - { - case 'fadeIn': - this.routeAnimationFade = !this.routeAnimationFade; - break; - case 'slideUp': - this.routeAnimationUp = !this.routeAnimationUp; - break; - case 'slideDown': - this.routeAnimationDown = !this.routeAnimationDown; - break; - case 'slideRight': - this.routeAnimationRight = !this.routeAnimationRight; - break; - case 'slideLeft': - this.routeAnimationLeft = !this.routeAnimationLeft; - break; - } - }); - - this.onConfigChanged = - this.fuseConfig.onConfigChanged - .subscribe( - (newSettings) => { - this.fuseSettings = newSettings; - } - ); - } - - ngOnDestroy() - { - this.onConfigChanged.unsubscribe(); - } -} diff --git a/src/app/main/content/pages/authentication/mail-confirm/mail-confirm.component.ts b/src/app/main/content/pages/authentication/mail-confirm/mail-confirm.component.ts new file mode 100644 index 00000000..e69c2256 --- /dev/null +++ b/src/app/main/content/pages/authentication/mail-confirm/mail-confirm.component.ts @@ -0,0 +1,38 @@ +import { Component } from '@angular/core'; + +import { FuseConfigService } from '@fuse/services/config.service'; +import { fuseAnimations } from '@fuse/animations'; + +@Component({ + selector : 'mail-confirm', + templateUrl: './mail-confirm.component.html', + styleUrls : ['./mail-confirm.component.scss'], + animations : fuseAnimations +}) +export class MailConfirmComponent +{ + /** + * Constructor + * + * @param {FuseConfigService} _fuseConfigService + */ + constructor( + private _fuseConfigService: FuseConfigService + ) + { + // Configure the layout + this._fuseConfigService.config = { + layout: { + navbar : { + hidden: true + }, + toolbar: { + hidden: true + }, + footer : { + hidden: true + } + } + }; + } +} diff --git a/src/app/main/content/pages/authentication/mail-confirm/mail-confirm.module.ts b/src/app/main/content/pages/authentication/mail-confirm/mail-confirm.module.ts new file mode 100644 index 00000000..e69c2256 --- /dev/null +++ b/src/app/main/content/pages/authentication/mail-confirm/mail-confirm.module.ts @@ -0,0 +1,38 @@ +import { Component } from '@angular/core'; + +import { FuseConfigService } from '@fuse/services/config.service'; +import { fuseAnimations } from '@fuse/animations'; + +@Component({ + selector : 'mail-confirm', + templateUrl: './mail-confirm.component.html', + styleUrls : ['./mail-confirm.component.scss'], + animations : fuseAnimations +}) +export class MailConfirmComponent +{ + /** + * Constructor + * + * @param {FuseConfigService} _fuseConfigService + */ + constructor( + private _fuseConfigService: FuseConfigService + ) + { + // Configure the layout + this._fuseConfigService.config = { + layout: { + navbar : { + hidden: true + }, + toolbar: { + hidden: true + }, + footer : { + hidden: true + } + } + }; + } +} diff --git a/src/app/main/content/ui/page-layouts/blank/blank.component.html b/src/app/main/content/ui/page-layouts/blank/blank.component.html new file mode 100644 index 00000000..e69de29b diff --git a/src/app/main/documentation/changelog/changelog.component.html b/src/app/main/documentation/changelog/changelog.component.html new file mode 100644 index 00000000..22803863 --- /dev/null +++ b/src/app/main/documentation/changelog/changelog.component.html @@ -0,0 +1,938 @@ +
+ + +
+ +
+ home + chevron_right + Documentation +
+ +
Changelog
+ +
+ + + +
+ +
+ + + + +
+ +
+ v6.1.0 + (2018-06-xx) +
+ +
+ +
+ Breaking Changes +
    +
  • New layout system and layouts
  • +
  • Replaced all mat-sidenav components with fuse-sidebar on apps and pages
  • +
+
+ +
+ New +
    +
  • Navigation service for easier modifications and for easier swapping
  • +
  • fusePerfectScrollbar now accepts a boolean to control the scrollbar's status
  • +
  • fusePerfectScrollbarOptions for Perfect Scrollbar options
  • +
  • Added an extra Angular Material color theme to the styles.scss file as an example
  • +
+
+ +
+ Improved +
    +
  • Updated Angular and Angular Material
  • +
  • Updated various other packages
  • +
  • Improved the codebase and added a lot code comments
  • +
  • Improved the documentation and moved them into the Demo app
  • +
  • Changed the fuse-sidebar "align" input to "position"
  • +
  • Improved the page layouts
  • +
  • Navbar toggle button and fold button alignment on right navbar
  • +
+
+ +
+ Fixed +
    +
  • Set the selected language in toolbar from the translation service
  • +
  • Horizontal nav titles are collapsing on IE11
  • +
  • Angular Material card images not showing correctly
  • +
  • Other small fixes and improvements
  • +
+
+ +
+ +
+ + + + +
+ +
+ v6.0.1 + (2018-05-10) +
+ +
+ +
+ New +
    +
  • Updated ngRx to 6.0.0-beta.1
  • +
  • Updated various other libraries to Angular 6 compatible versions
  • +
  • Updated demo code to make it compatible with RxJS 6.0.0
  • +
+
+ +
+ Fixed +
    +
  • Fixed: Scrumboard "Add a list" button is draggable and causing an error
  • +
+
+ +
+ +
+ + + + +
+ +
+ v6.0.0 + (2018-05-06) +
+ +
+ +
+ New +
    +
  • Updated Angular to 6.0.0
  • +
  • Updated Angular Material to 6.0.0
  • +
  • Updated Angular CLI to 6.0.0
  • +
  • Updated various other packages
  • +
+
+ +
+ Fixed +
    +
  • Fixed: Material icon button colors are being overwritten by Fuse
  • +
  • Fixed: Contacts app edit dialog issues
  • +
  • Fixed: Navigation sidebar doesn't scroll on mobile devices
  • +
  • Fixed: Horizontal navigation doesn't have 'hidden' and 'custom function' features like + the vertical + navigation +
  • +
  • Fixed: Search bar close icon alignment
  • +
  • Fixed: Profile page header background image doesn't cover the header
  • +
+
+ +
+ +
+ + + + +
+ +
+ v5.2.10 + (2018-03-10) +
+ +
+ +
+ Fixed +
    +
  • Fixed: Sidebar folded bugs
  • +
+
+ +
+ +
+ + + + +
+ +
+ v5.2.9 + (2018-03-10) +
+ +
+ +
+ Fixed +
    +
  • Fixed: Sidebar folded doesn't work correctly if activated programmatically
  • +
  • Fixed: Skeleton AoT building issues
  • +
+
+ +
+ +
+ + + + +
+ +
+ v5.2.8 + (2018-03-08) +
+ +
+ +
+ Breaking changes +
    +
  • + core folder moved into the @fuse allowing project owners to + have their own core folder inside the app directory. Also allows for better separation + in between your app and core Fuse features. +
  • +
  • + Removed Angular Material module that includes all Material components at once and added + imports for all modules separately. From now on, you must include the Material + components that you have used in your components manually in that component's module + file. This was a required changed as it does increase the development performance as + well as decrease the building and the AoT building times. +
  • +
  • + Changed how navigation model works. Now it's just a simple const that being exported + from the navigation.ts file. It allows for easier swapping and editing of + the navigation. +
  • +
  • + New sidebar component. Allows us to move main navigation sidebar logic out of your way. + Check out the Demo app to see the full usage. +
  • +
+
+ +
+ New +
    +
  • Updated Angular to 5.2.8
  • +
  • Updated Angular Material to 5.2.4
  • +
  • Updated Angular CLI to 1.7.3
  • +
  • Matched the Fuse version number with the Angular
  • +
  • No more Fuse2, the package name update to Fuse since the version number matched to + Angular's. +
  • +
+
+ +
+ Fixed +
    +
  • Fixed various issues with Fuse Angular Material Color Picker component.
  • +
  • Fixed various other small layout and logic bugs.
  • +
+
+ +
+ +
+ + + + +
+ +
+ v1.3.6 + (2018-02-06) +
+ +
+ +
+ New +
    +
  • Updated Angular to 5.2.3
  • +
  • Updated Angular Material to 5.1.1
  • +
  • Updated Angular CLI to 1.6.7
  • +
  • New Analytics dashboard design
  • +
  • Added Chart.js examples through the new dashboard
  • +
+
+ +
+ +
+ + + + +
+ +
+ v1.3.5 + (2018-01-24) +
+ +
+ +
+ New +
    +
  • Updated ngRx to 5.0.0
  • +
  • Updated Angular CLI to 1.6.5 to fix the wrong devkit version issue
  • +
+
+ +
+ +
+ + + + +
+ +
+ v1.3.4 + (2018-01-18) +
+ +
+ +
+ New +
    +
  • Updated Angular to 5.2.1
  • +
  • Updated Angular Material to 5.1.0
  • +
  • Updated various other packages to latest versions
  • +
+
+ +
+ Fixed +
    +
  • Quick Panel is too wide for smaller screens
  • +
  • Academy App course step doesn't scroll on mobile
  • +
+
+ +
+ +
+ + + + +
+ +
+ v1.3.3 + (2018-01-11) +
+ +
+ +
+ New +
    +
  • Updated Angular to 5.2.0
  • +
  • Updated Angular Material to 5.0.4
  • +
  • Updated various other packages to latest versions
  • +
+
+ +
+ Fixed + +
+ +
+ +
+ + + + +
+ +
+ v1.3.2 + (2018-01-09) +
+ +
+ +
+ New +
    +
  • Updated Angular to 5.1.3
  • +
  • Updated Angular Material to 5.0.3
  • +
  • Updated various other packages to latest versions
  • +
  • Added new card designs
  • +
  • Added new fuse-highlight component
  • +
  • Added lazy load to various other demo modules to make the demo project faster
  • +
+
+ +
+ Fixed +
    +
  • BREAKING CHANGE: Cards are moved to custom classes
  • +
  • BREAKING CHANGE: Removed fuse-hljs (Use fuse-highlight instead)
  • +
  • Various other small fixed and enhancements
  • +
+
+ +
+ +
+ + + + +
+ +
+ v1.3.1 + (2018-01-02) +
+ +
+ +
+ New +
    +
  • Updated Angular to 5.1.2
  • +
  • Updated Angular Material to 5.0.2
  • +
  • Updated various other packages to latest versions
  • +
  • New Academy app
  • +
+
+ +
+ Fixed +
    +
  • Mail compose dialog responsive issues
  • +
  • Fixed for various other bugs
  • +
+
+ +
+ +
+ + + + +
+ +
+ v1.3.0 + (2017-12-15) +
+ +
+ +
+ New +
    +
  • Updated Angular to 5.1.0
  • +
  • Updated Angular Material to 5.0.1
  • +
  • Updated various other packages to latest versions
  • +
  • New NgRx Sample app (Mail-NgRx app)
  • +
  • Form stepper examples
  • +
  • Added support for translations in navigation items
  • +
  • Moved the navigation.model.ts into its own folder
  • +
  • Added badge support for collapsable navigation items
  • +
  • Initialize the navigation from app.component rather then navigation.service
  • +
  • Trigger expand/collapse of the navigation on ngOnInit to update the active item
  • +
  • Replaced Calendar images
  • +
  • Added custom validator for password matching in Auth forms
  • +
+
+ +
+ Fixed +
    +
  • Custom scrollbars are showing in print
  • +
  • Various small issues in Auth pages
  • +
  • ngx-color-picker various style issues
  • +
  • Make sure the nav item has children before trying to get them
  • +
  • Renamed the KnowledgeBase demo module
  • +
+
+ +
+ +
+ + + + +
+ +
+ v1.2.3 + (2017-11-28) +
+ +
+ +
+ Fixed +
    +
  • Sidenav helper causes issues in mobile media steps
  • +
+
+ +
+ +
+ + + + +
+ +
+ v1.2.2 + (2017-11-27) +
+ +
+ +
+ New +
    +
  • Updated Angular to 5.0.3
  • +
  • Updated Angular Material to 5.0.0-rc.1
  • +
  • Updated Flex Layout
  • +
+
+ +
+ Fixed +
    +
  • Contacts app various issues
  • +
  • Duplicate content in Profile page tabs
  • +
  • Folded status of the Navbar shouldn't brake the layout if Horizontal Navbar is active +
  • +
+
+ +
+ +
+ + + + +
+ +
+ v1.2.1 + (2017-11-13) +
+ +
+ +
+ New +
    +
  • Updated Angular to 5.0.1
  • +
  • Updated Angular Material to 5.0.0-rc0
  • +
+
+ +
+ Fixed +
    +
  • Compatibility fixed for Angular Material 5.0.0-rc0
  • +
  • Scrumboard label selector not working properly
  • +
  • Todo detail style refinements
  • +
+
+ +
+ +
+ + + + +
+ +
+ v1.2.0 + (2017-11-06) +
+ +
+ +
+ New +
    +
  • BREAKING CHANGE: Updated Angular to 5.0.0 (clean installation recommended)
  • +
  • Updated Angular Flex Layout to 2.0.0-beta.10
  • +
  • E-Commerce App
  • +
  • File based translation service and its implementation example
  • +
  • Added Material Design cards
  • +
  • New 'Knowledge Base' page design
  • +
  • Added Tabbed versions of the Carded Sidenav layouts
  • +
  • Added an ability to control the folded status of the vertical navigation via + FuseConfig +
  • +
  • + Added 'exactMatch' property to the Navigation Model for more control over the active + item + highlighting +
  • +
+
+ +
+ Fixed +
    +
  • Angular 5 Compatibility fixed
  • +
  • Various iOS10 scrolling issues
  • +
  • FAQ page header shrinks on small heights
  • +
  • Stagger animation doesn't have 'optional' parameter
  • +
  • Toolbar navigation toggle button doesn't actually toggle the navigation bar
  • +
  • Nav items cannot be put on the root in Horizontal menu
  • +
  • Vertical navbar puts out wrong classes when its toggled
  • +
+
+ +
+ +
+ + + + +
+ +
+ v1.1.2 + (2017-10-16) +
+ +
+ +
+ New +
    +
  • BREAKING CHANGE: Updated Angular Material to 2.0.0-beta.12
  • +
  • Updated Angular to 4.4.5
  • +
  • New Reset and Forgot password page styles
  • +
  • Added 'agm-map', Google Maps component library.
  • +
  • New pricing page design
  • +
  • New mail confirmation page
  • +
  • New FAQ page design
  • +
  • Added new methods for accessing and updating specific nav items
  • +
  • Added the ability to add custom functions to the nav items
  • +
+
+ +
+ Fixed +
    +
  • Print styles and page breaks
  • +
  • Inconsistent font sizes across elements
  • +
  • Toolbar search bar button collapses on close
  • +
  • iOS scrolling issues
  • +
  • All 'mat-select' elements wrapped with 'mat-form-field' and fixed related issues
  • +
  • Auth page v2 styles iOS height issues
  • +
  • Chat view is not scrollable on mobile
  • +
  • Terms & Conditions checkbox styling issues on Auth forms
  • +
  • Some page layout header heights not correct on small devices
  • +
  • Lock page layout issues
  • +
  • Calendar & Scrumboard datepicker issues
  • +
+
+ +
+ +
+ + + + +
+ +
+ v1.1.1 + (2017-09-28) +
+ +
+ +
+ New +
    +
  • Updated Angular Material to 2.0.0-beta.11
  • +
  • Nested grouping in navigation
  • +
  • Added Angular Material elements showcase
  • +
+
+ +
+ Improved +
    +
  • Replaced Http module with HttpClient
  • +
+
+ +
+ +
+ + + + +
+ +
+ v1.1.0 + (2017-09-22) +
+ +
+ +
+ New +
    +
  • Updated Angular to 4.4.3
  • +
  • Added HMR config for starting the ng serve with HMR support
  • +
  • Added a way to swap navigation models on the fly
  • +
  • Enhanced animations for all apps and some pages
  • +
  • Custom perfect scrollbar directive
  • +
  • Navigation bar backdrop for closing the navigation easily on mobile
  • +
+
+ +
+ Improved +
    +
  • BREAKING CHANGE: Completely re-structured the navigation model
  • +
  • Locked dev dependency versions to prevent majority of the npm update errors
  • +
  • Updated perfect scrollbar
  • +
  • Calendar, Mail, ToDo and Chat app visual and structural Improved
  • +
  • Disabled the perfect-scrollbar on mobile completely
  • +
+
+ +
+ +
+ + + + +
+ +
+ v1.0.5 + (2017-09-12) +
+ +
+ +
+ New +
    +
  • Horizontal Navigation
  • +
  • Boxed Layout
  • +
  • New fade-in-out animation to Animations service
  • +
+
+ +
+ Improved +
    +
  • Scrumboard & Chat style Improved
  • +
+
+ +
+ Fixed +
    +
  • Removed unused md2 library from skeleton
  • +
+
+ +
+ +
+ + + + +
+ +
+ v1.0.4 + (2017-08-31) +
+ +
+ +
+ New +
    +
  • Scrumboard App
  • +
+
+ +
+ Improved +
    +
  • Responsive Improved, many more will come
  • +
+
+ +
+ Fixed +
    +
  • Dashboard sidenav not correctly working on some mobile devices
  • +
  • Couple MS Edge issues
  • +
+
+ +
+ +
+ + + + +
+ +
+ v1.0.3 + (2017-08-30) +
+ +
+ +
+ Fixed +
    +
  • Reverted to Angular 4.3.5 since animations are not correctly working on 4.3.6
  • +
  • Firefox and Edge scroll issues
  • +
+
+ +
+ +
+ + + + +
+ +
+ v1.0.2 + (2017-08-30) +
+ +
+ +
+ Improved +
    +
  • Angular Material v2.0.0-beta.10 Compatibility
  • +
  • Upgraded to Angular 4.3.6
  • +
  • Shortcuts component now stores the shortcuts in cookies
  • +
  • Added print styles
  • +
+
+ +
+ +
+ + + + +
+ +
+ v1.0.1 + (2017-08-24) +
+ +
+ +
+ Improved +
    +
  • New router animations
  • +
+
+ +
+ Fixed +
    +
  • Fixed AoT compiler issues
  • +
+
+ +
+ +
+ + + + +
+ +
+ v1.0.0 + (2017-08-23) +
+ +
+ +
+ New +
    +
  • Initial Release
  • +
+
+ +
+ +
+ +
+ +
+ + +
\ No newline at end of file diff --git a/src/app/main/documentation/changelog/changelog.component.scss b/src/app/main/documentation/changelog/changelog.component.scss new file mode 100644 index 00000000..6fef4203 --- /dev/null +++ b/src/app/main/documentation/changelog/changelog.component.scss @@ -0,0 +1,6 @@ +@import "src/@fuse/scss/fuse"; + +:host { + + +} diff --git a/src/app/main/documentation/changelog/changelog.component.ts b/src/app/main/documentation/changelog/changelog.component.ts new file mode 100644 index 00000000..4df00d74 --- /dev/null +++ b/src/app/main/documentation/changelog/changelog.component.ts @@ -0,0 +1,13 @@ +import { Component } from '@angular/core'; + +@Component({ + selector : 'docs-changelog', + templateUrl: './changelog.component.html', + styleUrls : ['./changelog.component.scss'] +}) +export class DocsChangelogComponent +{ + constructor() + { + } +} diff --git a/src/app/main/documentation/components-third-party/datatable/ngx-datatable.component.ts b/src/app/main/documentation/components-third-party/datatable/ngx-datatable.component.ts new file mode 100644 index 00000000..de775ca4 --- /dev/null +++ b/src/app/main/documentation/components-third-party/datatable/ngx-datatable.component.ts @@ -0,0 +1,63 @@ +import { Component, OnDestroy, OnInit } from '@angular/core'; +import { HttpClient } from '@angular/common/http'; +import { Subject } from 'rxjs'; +import { takeUntil } from 'rxjs/operators'; + +@Component({ + selector : 'docs-components-third-party-ngx-datatable', + templateUrl: './ngx-datatable.component.html', + styleUrls : ['./ngx-datatable.component.scss'] +}) +export class DocsComponentsThirdPartyNgxDatatableComponent implements OnInit, OnDestroy +{ + rows: any[]; + loadingIndicator: boolean; + reorderable: boolean; + + // Private + private _unsubscribeAll: Subject; + + /** + * Constructor + * + * @param {HttpClient} _httpClient + */ + constructor( + private _httpClient: HttpClient + ) + { + // Set the defaults + this.loadingIndicator = true; + this.reorderable = true; + + // Set the private defaults + this._unsubscribeAll = new Subject(); + } + + // ----------------------------------------------------------------------------------------------------- + // @ Lifecycle hooks + // ----------------------------------------------------------------------------------------------------- + + /** + * On init + */ + ngOnInit(): void + { + this._httpClient.get('api/contacts-contacts') + .pipe(takeUntil(this._unsubscribeAll)) + .subscribe((contacts: any) => { + this.rows = contacts; + this.loadingIndicator = false; + }); + } + + /** + * On destroy + */ + ngOnDestroy(): void + { + // Unsubscribe from all subscriptions + this._unsubscribeAll.next(); + this._unsubscribeAll.complete(); + } +} diff --git a/src/app/main/documentation/components-third-party/google-maps/google-maps.component.html b/src/app/main/documentation/components-third-party/google-maps/google-maps.component.html new file mode 100644 index 00000000..5818799f --- /dev/null +++ b/src/app/main/documentation/components-third-party/google-maps/google-maps.component.html @@ -0,0 +1,57 @@ +
+ + +
+
+
+ home + chevron_right + Documentation + chevron_right + 3rd Party Components +
+
Google Maps
+
+ + + link + Reference + +
+ + + +
+

+ agm-map is a angular component library for Google Maps. +

+ +
Sample
+

+ + + +

+ +
Usage
+

+ + + +

+ +
Inputs
+ Checkout the component api docs for detail: + AgmMap Api + +
+ +
+ diff --git a/src/app/main/documentation/components-third-party/google-maps/google-maps.component.ts b/src/app/main/documentation/components-third-party/google-maps/google-maps.component.ts new file mode 100644 index 00000000..2796c709 --- /dev/null +++ b/src/app/main/documentation/components-third-party/google-maps/google-maps.component.ts @@ -0,0 +1,22 @@ +import { Component } from '@angular/core'; + +@Component({ + selector : 'docs-components-third-party-google-maps', + templateUrl: './google-maps.component.html', + styleUrls : ['./google-maps.component.scss'] +}) +export class DocsComponentsThirdPartyGoogleMapsComponent +{ + lat: number; + lng: number; + + /** + * Constructor + */ + constructor() + { + // Set the defaults + this.lat = -34.397; + this.lng = 150.644; + } +} diff --git a/src/app/main/documentation/components/cards/cards.component.ts b/src/app/main/documentation/components/cards/cards.component.ts new file mode 100644 index 00000000..becba7c1 --- /dev/null +++ b/src/app/main/documentation/components/cards/cards.component.ts @@ -0,0 +1,224 @@ +import { Component } from '@angular/core'; +import * as shape from 'd3-shape'; + +import { fuseAnimations } from '@fuse/animations/index'; + +@Component({ + selector : 'docs-components-cards', + templateUrl: './cards.component.html', + styleUrls : ['./cards.component.scss'], + animations : fuseAnimations +}) +export class DocsComponentsCardsComponent +{ + view: string; + card9Expanded: boolean; + card10Expanded: boolean; + card19: any; + card24: any; + card25: any; + card26: any; + + constructor() + { + // Set the defaults + this.view = 'preview'; + + this.card9Expanded = false; + this.card10Expanded = false; + this.card19 = { + scheme: { + domain: ['#5c84f1'] + }, + data : [ + { + 'name' : 'GOOG', + 'series': [ + { + 'name' : 'Jan 1', + 'value': 540.2 + }, + { + 'name' : 'Jan 2', + 'value': 539.4 + }, + { + 'name' : 'Jan 3', + 'value': 538.9 + }, + { + 'name' : 'Jan 4', + 'value': 539.6 + }, + { + 'name' : 'Jan 5', + 'value': 540 + }, + { + 'name' : 'Jan 6', + 'value': 540.2 + }, + { + 'name' : 'Jan 7', + 'value': 540.48 + } + ] + } + ], + curve : shape.curveBasis + }; + + this.card24 = { + scheme : { + domain: ['#4867d2', '#5c84f1', '#89a9f4'] + }, + devices: [ + { + 'name' : 'Desktop', + 'value' : 92.8, + 'change': -0.6 + }, + { + 'name' : 'Mobile', + 'value' : 6.1, + 'change': 0.7 + }, + { + 'name' : 'Tablet', + 'value' : 1.1, + 'change': 0.1 + } + ] + }; + + this.card25 = { + scheme: { + domain: ['#5c84f1'] + }, + data : [ + { + 'name' : 'Monday', + 'value': 221 + }, + { + 'name' : 'Tuesday', + 'value': 428 + }, + { + 'name' : 'Wednesday', + 'value': 492 + }, + { + 'name' : 'Thursday', + 'value': 471 + }, + { + 'name' : 'Friday', + 'value': 413 + }, + { + 'name' : 'Saturday', + 'value': 344 + }, + { + 'name' : 'Sunday', + 'value': 294 + } + ] + }; + + this.card26 = { + scheme: { + domain: ['#5c84f1'] + }, + data : [ + { + 'name' : 'Impressions', + 'series': [ + { + 'name' : 'Jan 1', + 'value': 670000 + }, + { + 'name' : 'Jan 2', + 'value': 540000 + }, + { + 'name' : 'Jan 3', + 'value': 820000 + }, + { + 'name' : 'Jan 4', + 'value': 570000 + }, + { + 'name' : 'Jan 5', + 'value': 720000 + }, + { + 'name' : 'Jan 6', + 'value': 570000 + }, + { + 'name' : 'Jan 7', + 'value': 870000 + }, + { + 'name' : 'Jan 8', + 'value': 720000 + }, + { + 'name' : 'Jan 9', + 'value': 890000 + }, + { + 'name' : 'Jan 10', + 'value': 987000 + }, + { + 'name' : 'Jan 11', + 'value': 1120000 + }, + { + 'name' : 'Jan 12', + 'value': 1360000 + }, + { + 'name' : 'Jan 13', + 'value': 1100000 + }, + { + 'name' : 'Jan 14', + 'value': 1490000 + }, + { + 'name' : 'Jan 15', + 'value': 980000 + } + ] + } + ], + curve : shape.curveBasis + }; + + } + + // ----------------------------------------------------------------------------------------------------- + // @ Public methods + // ----------------------------------------------------------------------------------------------------- + + /** + * Toggle the view + */ + toggleView(): void + { + if ( this.view === 'preview' ) + { + this.view = 'source'; + } + else + { + this.view = 'preview'; + } + } +} diff --git a/src/app/main/documentation/components/components.module.ts b/src/app/main/documentation/components/components.module.ts new file mode 100644 index 00000000..d1d695ab --- /dev/null +++ b/src/app/main/documentation/components/components.module.ts @@ -0,0 +1,95 @@ +import { NgModule } from '@angular/core'; +import { RouterModule } from '@angular/router'; +import { MatButtonModule, MatButtonToggleModule, MatFormFieldModule, MatIconModule, MatListModule, MatMenuModule, MatSelectModule, MatSlideToggleModule, MatTabsModule } from '@angular/material'; +import { NgxChartsModule } from '@swimlane/ngx-charts'; + +import { FuseSharedModule } from '@fuse/shared.module'; + +import { FuseCountdownModule, FuseHighlightModule, FuseMaterialColorPickerModule, FuseWidgetModule } from '@fuse/components'; +import { DocsComponentsCardsComponent } from 'app/main/documentation/components/cards/cards.component'; +import { DocsComponentsCountdownComponent } from 'app/main/documentation/components/countdown/countdown.component'; +import { DocsComponentsHighlightComponent } from 'app/main/documentation/components/highlight/highlight.component'; +import { DocsComponentsMaterialColorPickerComponent } from 'app/main/documentation/components/material-color-picker/material-color-picker.component'; +import { DocsComponentsNavigationComponent } from 'app/main/documentation/components/navigation/navigation.component'; +import { DocsComponentsSearchBarComponent } from 'app/main/documentation/components/search-bar/search-bar.component'; +import { DocsComponentsSidebarComponent } from 'app/main/documentation/components/sidebar/sidebar.component'; +import { DocsComponentsShortcutsComponent } from 'app/main/documentation/components/shortcuts/shortcuts.component'; +import { DocsComponentsWidgetComponent } from 'app/main/documentation/components/widget/widget.component'; + +const routes = [ + { + path : 'cards', + component: DocsComponentsCardsComponent + }, + { + path : 'countdown', + component: DocsComponentsCountdownComponent + }, + { + path : 'highlight', + component: DocsComponentsHighlightComponent + }, + { + path : 'material-color-picker', + component: DocsComponentsMaterialColorPickerComponent + }, + { + path : 'navigation', + component: DocsComponentsNavigationComponent + }, + { + path : 'search-bar', + component: DocsComponentsSearchBarComponent + }, + { + path : 'sidebar', + component: DocsComponentsSidebarComponent + }, + { + path : 'shortcuts', + component: DocsComponentsShortcutsComponent + }, + { + path : 'widget', + component: DocsComponentsWidgetComponent + } +]; + +@NgModule({ + declarations: [ + DocsComponentsCardsComponent, + DocsComponentsCountdownComponent, + DocsComponentsHighlightComponent, + DocsComponentsMaterialColorPickerComponent, + DocsComponentsNavigationComponent, + DocsComponentsSearchBarComponent, + DocsComponentsSidebarComponent, + DocsComponentsShortcutsComponent, + DocsComponentsWidgetComponent + ], + imports : [ + RouterModule.forChild(routes), + + MatButtonModule, + MatButtonToggleModule, + MatFormFieldModule, + MatIconModule, + MatListModule, + MatMenuModule, + MatSelectModule, + MatSlideToggleModule, + MatTabsModule, + + NgxChartsModule, + + FuseSharedModule, + + FuseCountdownModule, + FuseHighlightModule, + FuseMaterialColorPickerModule, + FuseWidgetModule + ] +}) +export class ComponentsModule +{ +} diff --git a/src/app/main/documentation/components/countdown/countdown.component.html b/src/app/main/documentation/components/countdown/countdown.component.html new file mode 100644 index 00000000..c39da508 --- /dev/null +++ b/src/app/main/documentation/components/countdown/countdown.component.html @@ -0,0 +1,51 @@ +
+ + +
+
+
+ home + chevron_right + Documentation + chevron_right + Components +
+
Countdown
+
+
+ + + +
+ +

+ fuse-countdown is a custom built Fuse component allows you to create a countdowns. +

+ +
Sample
+

+ +

+ +
Usage
+

+ + + +

+ +
Inputs
+

+ eventDate + + The date of the event. Since fuse-countdown uses moment.js to parse the dates, any moment.js + compatible date string can be used. + +

+ +
+ +
+ diff --git a/src/app/main/documentation/components/highlight/highlight.component.html b/src/app/main/documentation/components/highlight/highlight.component.html new file mode 100644 index 00000000..db234e78 --- /dev/null +++ b/src/app/main/documentation/components/highlight/highlight.component.html @@ -0,0 +1,68 @@ +
+ + +
+
+
+ home + chevron_right + Documentation + chevron_right + Components +
+
Highlight
+
+
+ + + +
+ +

+ fuse-highlight is a custom built Fuse component allows to show syntax highlighted codes. +

+ +
Sample
+

+ + + + + +

+ +
Usage
+

+ + + +

+ +
Inputs
+

+ lang + + Language of the code to be highlighted. + +

+ +
+ +
+ diff --git a/src/app/main/documentation/components/material-color-picker/material-color-picker.component.html b/src/app/main/documentation/components/material-color-picker/material-color-picker.component.html new file mode 100644 index 00000000..bd4633fa --- /dev/null +++ b/src/app/main/documentation/components/material-color-picker/material-color-picker.component.html @@ -0,0 +1,69 @@ +
+ + +
+
+
+ home + chevron_right + Documentation + chevron_right + Components +
+
Material Color Picker
+
+
+ + + +
+ +

+ fuse-material-color-picker is a custom built Fuse component allows you to add a color picker + that allows to choose one of the many Material spec. colors. +

+ +
Sample
+

+ +

+ +
Usage
+

+ + + +

+ +
Two-way bindings
+

+ selectedClass + + The name of the Fuse color class to select, e.g. mat-red-500-bg + +

+

+ selectedBg + + The hex code of the color to be selected. It will be only selected if the hex code of the color + matches one of the material colors. + +

+ +
Outputs
+

+ onValueChange + + Event that triggered when a color selected. Returns an object that holds palette, hue, class name, + background and foreground colors. + +

+ +
+ +
+ diff --git a/src/app/main/documentation/components/navigation/navigation.component.html b/src/app/main/documentation/components/navigation/navigation.component.html new file mode 100644 index 00000000..76d6f1a9 --- /dev/null +++ b/src/app/main/documentation/components/navigation/navigation.component.html @@ -0,0 +1,381 @@ + + diff --git a/src/app/main/documentation/components/navigation/navigation.component.ts b/src/app/main/documentation/components/navigation/navigation.component.ts new file mode 100644 index 00000000..8b58a1ea --- /dev/null +++ b/src/app/main/documentation/components/navigation/navigation.component.ts @@ -0,0 +1,163 @@ +import { Component } from '@angular/core'; + +import { FuseNavigationService } from '@fuse/components/navigation/navigation.service'; + +@Component({ + selector : 'docs-components-navigation', + templateUrl: './navigation.component.html', + styleUrls : ['./navigation.component.scss'] +}) +export class DocsComponentsNavigationComponent +{ + navigation: any; + hidden: boolean; + + /** + * Constructor + */ + constructor( + private _fuseNavigationService: FuseNavigationService + ) + { + // Set the defaults + this.hidden = false; + } + + // ----------------------------------------------------------------------------------------------------- + // @ Public methods + // ----------------------------------------------------------------------------------------------------- + + /** + * Show/hide calendar menu item + */ + showHideCalendarMenuItem(): void + { + // Get the calendar item from the navigation + const calendarNavItem = this._fuseNavigationService.getNavigationItem('calendar'); + + // Toggle the visibility + this.hidden = !this.hidden; + calendarNavItem.hidden = this.hidden; + } + + /** + * Update mail badge + */ + updateMailBadge(): void + { + // Get the mail nav item + const mailNavItem = this._fuseNavigationService.getNavigationItem('mail'); + + // Update the badge title + mailNavItem.badge.title = 35; + } + + /** + * Add subitem to the calendar + */ + addSubitemToCalendar(): void + { + // Prepare the new nav item + const newNavItem = { + id : 'sub-item', + title: 'Sub Item', + type : 'item', + url : '/apps/calendar' + }; + + // Get the calendar item from the navigation + const calendarNavItem = this._fuseNavigationService.getNavigationItem('calendar'); + + // Make the calendar navigation item collapsable + calendarNavItem.type = 'collapsable'; + + // Add the navigation item + this._fuseNavigationService.addNavigationItem(newNavItem, 'calendar'); + } + + /** + * Add a nav item with custom function + */ + addNavItemWithCustomFunction(): void + { + // Prepare the new nav item + const newNavItem = { + id : 'custom-item', + title : 'Custom Item', + type : 'item', + function: () => { + alert('Custom function!'); + } + }; + + // Add the new nav item at the beginning of the navigation + this._fuseNavigationService.addNavigationItem(newNavItem, 'start'); + } + + /** + * Remove the dashboard menu item + */ + removeDashboards(): void + { + this._fuseNavigationService.removeNavigationItem('dashboards'); + } + + /** + * Register a new navigation and toggle to it + */ + registerNewNavigationAndToggle(): void + { + const adminNav = [ + { + id : 'admin', + title : 'Admin', + type : 'group', + icon : 'apps', + children: [ + { + id : 'users', + title: 'Users', + type : 'item', + icon : 'person', + url : '/apps/dashboards/analytics' + }, + { + id : 'payments', + title: 'Payments', + type : 'item', + icon : 'attach_money', + url : '/apps/academy' + } + ] + }, + { + id : 'control-panel', + title : 'Control Panel', + type : 'group', + icon : 'apps', + children: [ + { + id : 'cron-jobs', + title: 'Cron Jobs', + type : 'item', + icon : 'settings', + url : '/apps/file-manager' + }, + { + id : 'maintenance-mode', + title: 'Maintenance Mode', + type : 'item', + icon : 'build', + url : '/apps/todo' + } + ] + } + ]; + + // Register the new navigation + this._fuseNavigationService.register('admin-nav', adminNav); + + // Set the current navigation + this._fuseNavigationService.setCurrentNavigation('admin-nav'); + } +} diff --git a/src/app/main/documentation/components/search-bar/search-bar.component.html b/src/app/main/documentation/components/search-bar/search-bar.component.html new file mode 100644 index 00000000..84de7f24 --- /dev/null +++ b/src/app/main/documentation/components/search-bar/search-bar.component.html @@ -0,0 +1,46 @@ + + diff --git a/src/app/main/documentation/components/shortcuts/shortcuts.component.html b/src/app/main/documentation/components/shortcuts/shortcuts.component.html new file mode 100644 index 00000000..8efc4f01 --- /dev/null +++ b/src/app/main/documentation/components/shortcuts/shortcuts.component.html @@ -0,0 +1,45 @@ +
+ + +
+
+
+ home + chevron_right + Documentation + chevron_right + Components +
+
Shortcuts
+
+
+ + + +
+ +

+ fuse-shortcuts is a custom built Fuse component allows you to create and save shortcuts from + the navigation model. +

+ +
Usage
+

+ + + +

+ +
Model
+

+ <fuse-shortcuts></fuse-shortcuts> uses the same service with navigation + component to populate the shortcuts. It can search the navigation items as well as pin and unpin them as + shortcuts. It uses browser cookies to store the shortcuts. +

+ +
+ +
+ diff --git a/src/app/main/documentation/components/widget/widget.component.html b/src/app/main/documentation/components/widget/widget.component.html new file mode 100644 index 00000000..6d684372 --- /dev/null +++ b/src/app/main/documentation/components/widget/widget.component.html @@ -0,0 +1,108 @@ +
+ + +
+
+
+ home + chevron_right + Documentation + chevron_right + Components +
+
Widget
+
+
+ + + +
+ +

+ fuse-widget is a custom built Fuse component allows to create flippable widget boxes. +

+ +
Sample
+
+ + + +
+
+
Widget title
+ + +
+ +
+ Widget Content +
+
+ + + +
+ + +
+ More widget info +
+
+ + +
+
+ +
Usage
+

+ + + + + +

+ +
+ +
+ diff --git a/src/app/main/documentation/directives/directives.module.ts b/src/app/main/documentation/directives/directives.module.ts new file mode 100644 index 00000000..77946060 --- /dev/null +++ b/src/app/main/documentation/directives/directives.module.ts @@ -0,0 +1,51 @@ +import { NgModule } from '@angular/core'; +import { RouterModule } from '@angular/router'; +import { MatButtonModule, MatIconModule } from '@angular/material'; + +import { FuseSharedModule } from '@fuse/shared.module'; +import { FuseHighlightModule } from '@fuse/components'; + +import { DocsDirectivesFuseIfOnDomComponent } from 'app/main/documentation/directives/fuseIfOnDom/fuse-if-on-dom.component'; +import { DocsDirectivesFuseInnerScrollComponent } from 'app/main/documentation/directives/fuseInnerScroll/fuse-inner-scroll.component'; +import { DocsDirectivesFuseMatSidenavComponent } from 'app/main/documentation/directives/fuseMatSidenav/fuse-mat-sidenav.component'; +import { DocsDirectivesFusePerfectScrollbarComponent } from 'app/main/documentation/directives/fusePerfectScrollbar/fuse-perfect-scrollbar.component'; + +const routes = [ + { + path : 'fuse-if-on-dom', + component: DocsDirectivesFuseIfOnDomComponent + }, + { + path : 'fuse-inner-scroll', + component: DocsDirectivesFuseInnerScrollComponent + }, + { + path : 'fuse-mat-sidenav', + component: DocsDirectivesFuseMatSidenavComponent + }, + { + path : 'fuse-perfect-scrollbar', + component: DocsDirectivesFusePerfectScrollbarComponent + } +]; + +@NgModule({ + declarations: [ + DocsDirectivesFuseIfOnDomComponent, + DocsDirectivesFuseInnerScrollComponent, + DocsDirectivesFuseMatSidenavComponent, + DocsDirectivesFusePerfectScrollbarComponent + ], + imports : [ + RouterModule.forChild(routes), + + MatButtonModule, + MatIconModule, + + FuseSharedModule, + FuseHighlightModule + ] +}) +export class DirectivesModule +{ +} diff --git a/src/app/main/documentation/directives/fuseIfOnDom/fuse-if-on-dom.component.html b/src/app/main/documentation/directives/fuseIfOnDom/fuse-if-on-dom.component.html new file mode 100644 index 00000000..73ab0ebf --- /dev/null +++ b/src/app/main/documentation/directives/fuseIfOnDom/fuse-if-on-dom.component.html @@ -0,0 +1,40 @@ +
+ + +
+ +
+ home + chevron_right + Documentation + chevron_right + Directives +
+ +
fuseIfOnDom
+ +
+ + + +
+ +

+ *fuseIfOnDom is a helper directive that detaches and re-attaches the given element if it's + currently in the DOM. This will help in various cases such as charts that don't resize properly or + animations that don't wait to route to be loaded completely. +

+ +
Usage
+

+ + + +

+ +
+ + +
\ No newline at end of file diff --git a/src/app/main/documentation/directives/fuseIfOnDom/fuse-if-on-dom.component.ts b/src/app/main/documentation/directives/fuseIfOnDom/fuse-if-on-dom.component.ts new file mode 100644 index 00000000..387cd5e5 --- /dev/null +++ b/src/app/main/documentation/directives/fuseIfOnDom/fuse-if-on-dom.component.ts @@ -0,0 +1,13 @@ +import { Component } from '@angular/core'; + +@Component({ + selector : 'docs-directives-fuse-if-on-dom', + templateUrl: './fuse-if-on-dom.component.html', + styleUrls : ['./fuse-if-on-dom.component.scss'] +}) +export class DocsDirectivesFuseIfOnDomComponent +{ + constructor() + { + } +} diff --git a/src/app/main/documentation/directives/fuseInnerScroll/fuse-inner-scroll.component.html b/src/app/main/documentation/directives/fuseInnerScroll/fuse-inner-scroll.component.html new file mode 100644 index 00000000..f9256d22 --- /dev/null +++ b/src/app/main/documentation/directives/fuseInnerScroll/fuse-inner-scroll.component.html @@ -0,0 +1,43 @@ +
+ + +
+ +
+ home + chevron_right + Documentation + chevron_right + Directives +
+ +
fuseInnerScroll
+ +
+ + + +
+ +

+ fuseInnerScroll is a class directive that can be used in page layouts. It will lock the + container's scroll allowing for individual scroll such as sidebar and the content itself. +

+ +

+ This directive will only work with Fuse's pre-built page layouts and it's a class directive. +

+ +
Usage
+

+ + + +

+ +
+ + +
\ No newline at end of file diff --git a/src/app/main/documentation/directives/fuseInnerScroll/fuse-inner-scroll.component.scss b/src/app/main/documentation/directives/fuseInnerScroll/fuse-inner-scroll.component.scss new file mode 100644 index 00000000..ca2a0c07 --- /dev/null +++ b/src/app/main/documentation/directives/fuseInnerScroll/fuse-inner-scroll.component.scss @@ -0,0 +1,5 @@ +@import "src/@fuse/scss/fuse"; + +:host { + +} diff --git a/src/app/main/documentation/directives/fuseInnerScroll/fuse-inner-scroll.component.ts b/src/app/main/documentation/directives/fuseInnerScroll/fuse-inner-scroll.component.ts new file mode 100644 index 00000000..8bef2049 --- /dev/null +++ b/src/app/main/documentation/directives/fuseInnerScroll/fuse-inner-scroll.component.ts @@ -0,0 +1,13 @@ +import { Component } from '@angular/core'; + +@Component({ + selector : 'docs-directives-fuse-inner-scroll', + templateUrl: './fuse-inner-scroll.component.html', + styleUrls : ['./fuse-inner-scroll.component.scss'] +}) +export class DocsDirectivesFuseInnerScrollComponent +{ + constructor() + { + } +} diff --git a/src/app/main/documentation/directives/fuseMatSidenav/fuse-mat-sidenav.component.html b/src/app/main/documentation/directives/fuseMatSidenav/fuse-mat-sidenav.component.html new file mode 100644 index 00000000..272b5513 --- /dev/null +++ b/src/app/main/documentation/directives/fuseMatSidenav/fuse-mat-sidenav.component.html @@ -0,0 +1,72 @@ +
+ + +
+ +
+ home + chevron_right + Documentation + chevron_right + Directives +
+ +
fuseMatSidenav
+ +
+ + + +
+ +

+ fuseMatSidenav is a helper directive that enhances the Angular Material's sidenav. It modifies + the sidenav so it will function like the Angular Material 1.x sidenav. It also has a service which you can + register a sidenav in order to access and control its status from anywhere. +

+ +
Usage
+

+ + + +

+ +
Inputs
+

+ fuseMatSidenavHelper + + A unique name for the sidenav. + +

+

+ mat-is-locked-open + + Adds a locked open functionality just like Angular Material 1.x sidenav. Works with the media step + aliases of the FlexLayout library. + +

+ +
Accessing to the sidebav methods from anywhere
+

+ + + +

+ +
+ + +
\ No newline at end of file diff --git a/src/app/main/documentation/directives/fuseMatSidenav/fuse-mat-sidenav.component.scss b/src/app/main/documentation/directives/fuseMatSidenav/fuse-mat-sidenav.component.scss new file mode 100644 index 00000000..a6486575 --- /dev/null +++ b/src/app/main/documentation/directives/fuseMatSidenav/fuse-mat-sidenav.component.scss @@ -0,0 +1,8 @@ +@import "src/@fuse/scss/fuse"; + +:host { + + code { + white-space: nowrap; + } +} diff --git a/src/app/main/documentation/directives/fuseMatSidenav/fuse-mat-sidenav.component.ts b/src/app/main/documentation/directives/fuseMatSidenav/fuse-mat-sidenav.component.ts new file mode 100644 index 00000000..05b13b9e --- /dev/null +++ b/src/app/main/documentation/directives/fuseMatSidenav/fuse-mat-sidenav.component.ts @@ -0,0 +1,13 @@ +import { Component } from '@angular/core'; + +@Component({ + selector : 'docs-directives-fuse-mat-sidenav', + templateUrl: './fuse-mat-sidenav.component.html', + styleUrls : ['./fuse-mat-sidenav.component.scss'] +}) +export class DocsDirectivesFuseMatSidenavComponent +{ + constructor() + { + } +} diff --git a/src/app/main/documentation/directives/fusePerfectScrollbar/fuse-perfect-scrollbar.component.html b/src/app/main/documentation/directives/fusePerfectScrollbar/fuse-perfect-scrollbar.component.html new file mode 100644 index 00000000..900fd2a4 --- /dev/null +++ b/src/app/main/documentation/directives/fusePerfectScrollbar/fuse-perfect-scrollbar.component.html @@ -0,0 +1,65 @@ +
+ + +
+ +
+ home + chevron_right + Documentation + chevron_right + Directives +
+ +
fusePerfectScrollbar
+ +
+ + + +
+ +

+ fusePerfectScrollbar is an Angular directive for the Perfect Scrollbar library. +

+ +
Usage
+

+ + + +

+ +

+ + + +

+ +
Inputs
+

+ fusePerfectScrollbar + + Accepts an optional boolean which you can control the Perfect Scrollbar. If provided false, Perfect + Scrollbar will be destroyed or won't be initialized. + +

+

+ fusePerfectScrollbarOptions + + Accepts the Perfect + Scrollbar options. In addition to those options, there is also a custom updateOnRouteChange + option which updates the scrollbar on route changes. That's useful if your scrollbar wraps a + router-outlet. + +

+ +
+ + +
\ No newline at end of file diff --git a/src/app/main/documentation/directives/fusePerfectScrollbar/fuse-perfect-scrollbar.component.scss b/src/app/main/documentation/directives/fusePerfectScrollbar/fuse-perfect-scrollbar.component.scss new file mode 100644 index 00000000..ca2a0c07 --- /dev/null +++ b/src/app/main/documentation/directives/fusePerfectScrollbar/fuse-perfect-scrollbar.component.scss @@ -0,0 +1,5 @@ +@import "src/@fuse/scss/fuse"; + +:host { + +} diff --git a/src/app/main/documentation/directives/fusePerfectScrollbar/fuse-perfect-scrollbar.component.ts b/src/app/main/documentation/directives/fusePerfectScrollbar/fuse-perfect-scrollbar.component.ts new file mode 100644 index 00000000..66cc507e --- /dev/null +++ b/src/app/main/documentation/directives/fusePerfectScrollbar/fuse-perfect-scrollbar.component.ts @@ -0,0 +1,13 @@ +import { Component } from '@angular/core'; + +@Component({ + selector : 'docs-directives-fuse-perfect-scrollbar', + templateUrl: './fuse-perfect-scrollbar.component.html', + styleUrls : ['./fuse-perfect-scrollbar.component.scss'] +}) +export class DocsDirectivesFusePerfectScrollbarComponent +{ + constructor() + { + } +} diff --git a/src/app/main/documentation/documentation.module.ts b/src/app/main/documentation/documentation.module.ts new file mode 100644 index 00000000..8175f6c0 --- /dev/null +++ b/src/app/main/documentation/documentation.module.ts @@ -0,0 +1,55 @@ +import { NgModule } from '@angular/core'; +import { RouterModule, Routes } from '@angular/router'; + +import { MatIconModule } from '@angular/material'; + +import { FuseSharedModule } from '@fuse/shared.module'; + +import { DocsChangelogComponent } from 'app/main/documentation/changelog/changelog.component'; + +const routes: Routes = [ + { + path : 'changelog', + component: DocsChangelogComponent + }, + { + path : 'getting-started', + loadChildren: './getting-started/getting-started.module#GettingStartedModule' + }, + { + path : 'working-with-fuse', + loadChildren: './working-with-fuse/working-with-fuse.module#WorkingWithFuseModule' + }, + { + path : 'components', + loadChildren: './components/components.module#ComponentsModule' + }, + { + path : 'components-third-party', + loadChildren: './components-third-party/components-third-party.module#ComponentsThirdPartyModule' + }, + { + path : 'directives', + loadChildren: './directives/directives.module#DirectivesModule' + }, + { + path : 'services', + loadChildren: './services/services.module#ServicesModule' + } +]; + +@NgModule({ + declarations: [ + DocsChangelogComponent + ], + imports : [ + RouterModule.forChild(routes), + + MatIconModule, + + FuseSharedModule + ] +}) +export class DocumentationModule +{ +} diff --git a/src/app/main/documentation/getting-started/getting-started.module.ts b/src/app/main/documentation/getting-started/getting-started.module.ts new file mode 100644 index 00000000..468df5f7 --- /dev/null +++ b/src/app/main/documentation/getting-started/getting-started.module.ts @@ -0,0 +1,38 @@ +import { NgModule } from '@angular/core'; +import { RouterModule } from '@angular/router'; +import { MatIconModule } from '@angular/material'; + +import { FuseSharedModule } from '@fuse/shared.module'; +import { FuseHighlightModule } from '@fuse/components'; + +import { DocsGettingStartedIntroductionComponent } from 'app/main/documentation/getting-started/introduction/introduction.component'; +import { DocsGettingStartedInstallationComponent } from 'app/main/documentation/getting-started/installation/installation.component'; + +const routes = [ + { + path : 'introduction', + component: DocsGettingStartedIntroductionComponent + }, + { + path : 'installation', + component: DocsGettingStartedInstallationComponent + } +]; + +@NgModule({ + declarations: [ + DocsGettingStartedIntroductionComponent, + DocsGettingStartedInstallationComponent + ], + imports : [ + RouterModule.forChild(routes), + + MatIconModule, + + FuseSharedModule, + FuseHighlightModule + ] +}) +export class GettingStartedModule +{ +} diff --git a/src/app/main/documentation/getting-started/installation/installation.component.html b/src/app/main/documentation/getting-started/installation/installation.component.html new file mode 100644 index 00000000..af428a68 --- /dev/null +++ b/src/app/main/documentation/getting-started/installation/installation.component.html @@ -0,0 +1,150 @@ +
+ + +
+ +
+ home + chevron_right + Documentation + chevron_right + Getting Started +
+ +
Installation
+ +
+ + + +
+ +
Prerequisites
+ +

+ This section will give you some information about what tools you will need. You can skip to the + Installation section to start installing the template. We already mentioned all the prerequisites and + how to install them in the Installation section. +

+ + +
Angular CLI
+

+ Fuse uses Angular CLI for quickly + bootstrapping the application. You can check out the link for + more detailed information. +

+ +

+ Simply, Angular CLI is a tool to initialize, develop, scaffold and maintain Angular + applications +

+ + + +
Node.js
+

+ To install and use Fuse, you will need Node.js + installed to your computer. We won't get into too much detail about Node.js as it's out of the scope + of this documentation. Also you won't need to actually use Node.js, it's only required for the + development process. +

+ + + +
Git
+

+ To be able to install and use Fuse, you will also need + Git installed to your computer. Git is required for + npm to work correctly. +

+ + + +
Npm - Package Manager
+

+ Fuse uses npm package manager to install and manage 3rd + party components and libraries. +

+ + +
Installation
+ + +
A. Installing Prerequisites
+
    +
  1. + Download and install the latest Node.js from + its web site. +
  2. + +
  3. + Download and install the latest Git from its web + site. +
  4. + +
  5. + To install the Angular CLI: + + Open your favorite console application (Terminal, Command Prompt etc.), run the following command + and wait for it to finish: + +
    + + + +
    +
  6. +
+

+ Now you are ready to install the Fuse. +

+ + + +
B. Installing Fuse
+
    +
  1. + Unzip the zip file that you have downloaded from Themeforest. Inside the zip file, you will find the + Skeleton Project (Fuse-x.x.x-skeleton.zip) along with the Demo Project (Fuse-x.x.x-demo.zip), + PSD designs and a readme file. +
  2. +
  3. + For this documentation, we will be using the Skeleton Project which is the exact same template minus + the demo content so you don't have to clean up the demo content. +
  4. +
  5. + Extract the contents of the zip file (Fuse-x.x.x-skeleton.zip) into a folder that you will + work within. For this documentation, we will refer that as "your work folder". +
  6. +
  7. + Open your favorite console application (Terminal, Command Prompt etc.), navigate into your work + folder, run the following command and wait for it to finish: + +
    + + + +
    + +

    + This command will install all the required Node.js modules into the node_modules + directory inside your work folder. +

    +
  8. + +

    + And now, you are ready to run the Fuse for the first time. Please continue to the + Working with Fuse section. +

    +
+ + +
+ + +
\ No newline at end of file diff --git a/src/app/main/documentation/getting-started/installation/installation.component.scss b/src/app/main/documentation/getting-started/installation/installation.component.scss new file mode 100644 index 00000000..ca2a0c07 --- /dev/null +++ b/src/app/main/documentation/getting-started/installation/installation.component.scss @@ -0,0 +1,5 @@ +@import "src/@fuse/scss/fuse"; + +:host { + +} diff --git a/src/app/main/documentation/getting-started/installation/installation.component.ts b/src/app/main/documentation/getting-started/installation/installation.component.ts new file mode 100644 index 00000000..198c03d4 --- /dev/null +++ b/src/app/main/documentation/getting-started/installation/installation.component.ts @@ -0,0 +1,13 @@ +import { Component } from '@angular/core'; + +@Component({ + selector : 'docs-installation', + templateUrl: './installation.component.html', + styleUrls : ['./installation.component.scss'] +}) +export class DocsGettingStartedInstallationComponent +{ + constructor() + { + } +} diff --git a/src/app/main/documentation/getting-started/introduction/introduction.component.html b/src/app/main/documentation/getting-started/introduction/introduction.component.html new file mode 100644 index 00000000..79244474 --- /dev/null +++ b/src/app/main/documentation/getting-started/introduction/introduction.component.html @@ -0,0 +1,71 @@ +
+ + +
+ +
+ home + chevron_right + Documentation + chevron_right + Getting Started +
+ +
Introduction
+ +
+ + + +
+ +

+ This version of Fuse is NOT a traditional admin template, it's an Angular app written entirely + with Typescript and has no jQuery dependency. +

+

+ While Fuse is a great tool and source for learning Angular, it also requires at least an entry level of + Angular knowledge so you can find your way within the source code. +

+

+ Here you can find a list of core libraries, design specifications and coding standards that we use in Fuse: +

+ + +
Google's Material Design
+

+ All libraries and custom made components are following Google's Material Design Specifications. +

+ + + +
Angular
+

+ Angular is the core of Fuse. +

+ + + +
Angular Material
+

+ Angular Material is the primary UI + library of the Fuse. It's a set of Angular components, directives and services that implements Material + Design Specifications and it's in active development by Google. +

+ + + +
CLI tool for Angular
+

+ The Angular CLI is a tool to initialize, develop, scaffold and maintain Angular applications. + You can find more information about at: + angular-cli +

+ + +
+ + +
\ No newline at end of file diff --git a/src/app/main/documentation/getting-started/introduction/introduction.component.scss b/src/app/main/documentation/getting-started/introduction/introduction.component.scss new file mode 100644 index 00000000..ca2a0c07 --- /dev/null +++ b/src/app/main/documentation/getting-started/introduction/introduction.component.scss @@ -0,0 +1,5 @@ +@import "src/@fuse/scss/fuse"; + +:host { + +} diff --git a/src/app/main/documentation/getting-started/introduction/introduction.component.ts b/src/app/main/documentation/getting-started/introduction/introduction.component.ts new file mode 100644 index 00000000..c23d2cc3 --- /dev/null +++ b/src/app/main/documentation/getting-started/introduction/introduction.component.ts @@ -0,0 +1,13 @@ +import { Component } from '@angular/core'; + +@Component({ + selector : 'docs-introduction', + templateUrl: './introduction.component.html', + styleUrls : ['./introduction.component.scss'] +}) +export class DocsGettingStartedIntroductionComponent +{ + constructor() + { + } +} diff --git a/src/app/main/documentation/services/config/config.component.html b/src/app/main/documentation/services/config/config.component.html new file mode 100644 index 00000000..ed9f752d --- /dev/null +++ b/src/app/main/documentation/services/config/config.component.html @@ -0,0 +1,84 @@ +
+ + +
+
+
+ home + chevron_right + Documentation + chevron_right + Services +
+
Config
+
+
+ + + +
+ +

+ Config is a custom built Fuse service allows to have a granular control over the Fuse. It can + be used for changing theme options (layout, color etc.) by component basis. +

+ +
Usage
+

+ + + + + +

+ +
+ +
+ diff --git a/src/app/main/documentation/services/splash-screen/splash-screen.component.html b/src/app/main/documentation/services/splash-screen/splash-screen.component.html new file mode 100644 index 00000000..f35a2e70 --- /dev/null +++ b/src/app/main/documentation/services/splash-screen/splash-screen.component.html @@ -0,0 +1,55 @@ +
+ + +
+
+
+ home + chevron_right + Documentation + chevron_right + Services +
+
Splash Screen
+
+
+ + + +
+ +

+ Splash screen is a custom Fuse service that allows to have a control on the splash screen. +

+ +
Usage
+

+ + + + + +

+ +
+ +
+ diff --git a/src/app/main/documentation/working-with-fuse/directory-structure/directory-structure.component.html b/src/app/main/documentation/working-with-fuse/directory-structure/directory-structure.component.html new file mode 100644 index 00000000..13e43310 --- /dev/null +++ b/src/app/main/documentation/working-with-fuse/directory-structure/directory-structure.component.html @@ -0,0 +1,76 @@ +
+ + +
+ +
+ home + chevron_right + Documentation + chevron_right + Working with Fuse +
+ +
Directory Structure
+ +
+ + + +
+ +

+ Fuse has a fairly simple directory structure. All source code that you will need stays inside the + /src folder. +

+ +

+ Once you build your app, a /dist folder will appear at the root which will contain the built app. You + can simply upload the contents of it to your server to start running your app. +

+ +
Source directory (/src)
+ +

+ The source folder has the general Angular CLI project structure along with an additional folder called + /@fuse which contains the core elements of the Fuse. +

+ +

+ We recommend you not to touch /@fuse directory to easily update Fuse in the future. +

+ +
/app
+ +

+ This folder contains the AppComponent along with the following directories. Everything that being + contained inside these folders are belong to your app and you can edit them however you like while + building your app: +

+ +
    +
  • + /fake-db: The fake database data files for Fuse apps. +
  • +
  • + /fuse-config: The main config file for configuring the Fuse template. +
  • +
  • + /layout: Contains the template layout components. +
  • +
  • + /main: Example Fuse apps and ready to use pages and page layouts. +
  • +
  • + /navigation: The main navigation data. +
  • +
  • + /store: Ngrx-Mail app related store files. +
  • + +
+ +
+ + +
\ No newline at end of file diff --git a/src/app/main/documentation/working-with-fuse/directory-structure/directory-structure.component.scss b/src/app/main/documentation/working-with-fuse/directory-structure/directory-structure.component.scss new file mode 100644 index 00000000..ca2a0c07 --- /dev/null +++ b/src/app/main/documentation/working-with-fuse/directory-structure/directory-structure.component.scss @@ -0,0 +1,5 @@ +@import "src/@fuse/scss/fuse"; + +:host { + +} diff --git a/src/app/main/documentation/working-with-fuse/directory-structure/directory-structure.component.ts b/src/app/main/documentation/working-with-fuse/directory-structure/directory-structure.component.ts new file mode 100644 index 00000000..2c9bc53b --- /dev/null +++ b/src/app/main/documentation/working-with-fuse/directory-structure/directory-structure.component.ts @@ -0,0 +1,13 @@ +import { Component } from '@angular/core'; + +@Component({ + selector : 'docs-working-with-fuse-directory-structure', + templateUrl: './directory-structure.component.html', + styleUrls : ['./directory-structure.component.scss'] +}) +export class DocsWorkingWithFuseDirectoryStructureComponent +{ + constructor() + { + } +} diff --git a/src/app/main/documentation/working-with-fuse/multi-language/multi-language.component.html b/src/app/main/documentation/working-with-fuse/multi-language/multi-language.component.html new file mode 100644 index 00000000..85e34985 --- /dev/null +++ b/src/app/main/documentation/working-with-fuse/multi-language/multi-language.component.html @@ -0,0 +1,129 @@ +
+ + +
+
+
+ home + chevron_right + Components +
+
Multi Language
+
+
+ + + +
+ +

+ Fuse uses ngx-translate + module and supports multiple languages and translations. +

+ +

+ Since not everybody need multi-language setup for their apps, we decided NOT to put translations everywhere. + If you want to see the translations in action, visit + Mail app and then change the language from the Toolbar. +

+ Mail app is the only app that has translations for demonstration purposes. You can look at its source code + to see the usage. +

+ +
Usage
+

In order to use the translations, create your translation file within the module you want to use + the translations. For example, for the Mail app, create i18n/en.ts file inside the + apps/mail folder. +

+

+ The structure of the translation file is important and it must define the language id along with the + translation data: +

+ +

+ + + +

+ +

+ After you create your translation files, open the *.component.ts file for the module you + want to have translations, and register your translation file. For this example, we will use the + mail.component.ts file: +

+ + + + + +
Changing the language
+ +

+ Changing the current language can happen instantly. Simply call the use method from the + translate service: +

+ + + + + +

+ More detailed usage of the translation service can be found in the toolbar.component.ts + file. +

+ +
+ +
diff --git a/src/app/main/documentation/working-with-fuse/multi-language/multi-language.component.scss b/src/app/main/documentation/working-with-fuse/multi-language/multi-language.component.scss new file mode 100644 index 00000000..32c65c8c --- /dev/null +++ b/src/app/main/documentation/working-with-fuse/multi-language/multi-language.component.scss @@ -0,0 +1,3 @@ +:host { + +} diff --git a/src/app/main/documentation/working-with-fuse/page-layouts/page-layouts.component.html b/src/app/main/documentation/working-with-fuse/page-layouts/page-layouts.component.html new file mode 100644 index 00000000..0a1197ac --- /dev/null +++ b/src/app/main/documentation/working-with-fuse/page-layouts/page-layouts.component.html @@ -0,0 +1,62 @@ +
+ + +
+ +
+ home + chevron_right + Documentation + chevron_right + Working with Fuse +
+ +
Page Layouts
+ +
+ + + +
+ +

+ One of the strong sides of the Fuse is its Page layouts. Every single app, pre-built page and even this + documentation pages uses the Fuse's page layouts. +

+ +

+ Simply, page layouts are pre-built layouts with a demo content which you can simply copy/paste and start + building your own page or app based on it. Because page layouts, it's very easy to replicate any page style + that you can find in Fuse, without needing to remove all the demo functionality from them. +

+ +
Identifying a Page Layout
+ +

+ You can easily identify the layout that particular page or app using by simply looking at its main html + file. The very top wrapper div will tell you everything you need to know: +

+ + + + + +

+ The above example is using the carded style page with a left sidebar setup which can be found + in /ui/page-layouts/carded/left-sidebar-1 directory. +

+ +

+ The numbers in the folder names represents the scrolling style of that particular page layout. For example, + left-sidebar-1 has the exact same layout with left-sidebar-2 but the former one uses + a single scrollbar while the latter one uses separate scrollbars for its content and its sidebar. +

+ +
+ + +
\ No newline at end of file diff --git a/src/app/main/documentation/working-with-fuse/page-layouts/page-layouts.component.scss b/src/app/main/documentation/working-with-fuse/page-layouts/page-layouts.component.scss new file mode 100644 index 00000000..ca2a0c07 --- /dev/null +++ b/src/app/main/documentation/working-with-fuse/page-layouts/page-layouts.component.scss @@ -0,0 +1,5 @@ +@import "src/@fuse/scss/fuse"; + +:host { + +} diff --git a/src/app/main/documentation/working-with-fuse/page-layouts/page-layouts.component.ts b/src/app/main/documentation/working-with-fuse/page-layouts/page-layouts.component.ts new file mode 100644 index 00000000..070eb224 --- /dev/null +++ b/src/app/main/documentation/working-with-fuse/page-layouts/page-layouts.component.ts @@ -0,0 +1,13 @@ +import { Component } from '@angular/core'; + +@Component({ + selector : 'docs-working-with-fuse-page-layouts', + templateUrl: './page-layouts.component.html', + styleUrls : ['./page-layouts.component.scss'] +}) +export class DocsWorkingWithFusePageLayoutsComponent +{ + constructor() + { + } +} diff --git a/src/app/main/documentation/working-with-fuse/production/production.component.html b/src/app/main/documentation/working-with-fuse/production/production.component.html new file mode 100644 index 00000000..bca476a4 --- /dev/null +++ b/src/app/main/documentation/working-with-fuse/production/production.component.html @@ -0,0 +1,143 @@ +
+ + +
+ +
+ home + chevron_right + Documentation + chevron_right + Working with Fuse +
+ +
Production
+ +
+ + + +
+ + +
Build
+ +

+ The following command builds the application into an output directory +

+ +
+ + + +
+ +

+ The build artifacts will be stored in the /dist directory. All commands that build or serve your + project, will delete the output directory. +

+ +
Bundling & Tree-Shaking (AoT)
+ +

+ To build your app with AoT (Ahead of Time) compiler, use the following command: +

+
+ + + +
+

+ or if you want to serve with AoT, use the following: +

+
+ + + +
+

+ This will make use of uglifying and tree-shaking functionality while serving the app from + the memory. +

+ +
Alternative AoT compiler
+ +

+ If you happen to stumble upon an error while running the +

+
+ + + +
+

+ command, there is an alternative one that you can use. The following command will run the ng build + --prod command with an increased memory size so your app can be built: +

+
+ + + +
+ + + +
Running unit tests
+ +
+ + + +
+

+ Tests will execute after a build is executed via + Karma, and it will automatically + watch your files for changes. +

+

+ You can run tests a single time via + --watch=false + or + --single-run +

+ + + +
Running end-to-end tests
+
+ + + +
+

+ Before running the tests make sure you are serving the app via + ng serve. + + End-to-end tests are run via Protractor. +

+ + +

+ For more information about angular-cli commands, check the angular-cli. +

+ +
+ + +
\ No newline at end of file diff --git a/src/app/main/documentation/working-with-fuse/production/production.component.scss b/src/app/main/documentation/working-with-fuse/production/production.component.scss new file mode 100644 index 00000000..ca2a0c07 --- /dev/null +++ b/src/app/main/documentation/working-with-fuse/production/production.component.scss @@ -0,0 +1,5 @@ +@import "src/@fuse/scss/fuse"; + +:host { + +} diff --git a/src/app/main/documentation/working-with-fuse/production/production.component.ts b/src/app/main/documentation/working-with-fuse/production/production.component.ts new file mode 100644 index 00000000..26254ab8 --- /dev/null +++ b/src/app/main/documentation/working-with-fuse/production/production.component.ts @@ -0,0 +1,13 @@ +import { Component } from '@angular/core'; + +@Component({ + selector : 'docs-working-with-fuse-production', + templateUrl: './production.component.html', + styleUrls : ['./production.component.scss'] +}) +export class DocsWorkingWithFuseProductionComponent +{ + constructor() + { + } +} diff --git a/src/app/main/documentation/working-with-fuse/server/server.component.html b/src/app/main/documentation/working-with-fuse/server/server.component.html new file mode 100644 index 00000000..081ee2c4 --- /dev/null +++ b/src/app/main/documentation/working-with-fuse/server/server.component.html @@ -0,0 +1,79 @@ +
+ + +
+ +
+ home + chevron_right + Documentation + chevron_right + Working with Fuse +
+ +
Server
+ +
+ + + +
+ + +
Server
+

+ While still in your work folder, run the following command in the console application: +

+ +
+ + + +
+ +

+ And that's it. Angular CLI will take care everything and start the Fuse. +

+ +

+ You can check out your console application to get further information about the server. By default, it + will run on http://localhost:4200 but it might change depending on your setup. +

+ +

+ Also, there are other commands available in Fuse which may help you in your development. To see the complete + list of available npm commands, check the + package.json + file. +

+ + + +
Reloading the Server
+

+ The + ng serve + command will watch your files and reload the page for you as you make changes. + But for some reason, if you need to manually restart the server, you can do it by pressing Ctrl + + C on your keyboard while in the console application and then run the following command once again: +

+
+ + + +
+ + +

+ For more information about angular-cli commands, check the + angular-cli. +

+ +
+ + +
\ No newline at end of file diff --git a/src/app/main/documentation/working-with-fuse/server/server.component.scss b/src/app/main/documentation/working-with-fuse/server/server.component.scss new file mode 100644 index 00000000..ca2a0c07 --- /dev/null +++ b/src/app/main/documentation/working-with-fuse/server/server.component.scss @@ -0,0 +1,5 @@ +@import "src/@fuse/scss/fuse"; + +:host { + +} diff --git a/src/app/main/documentation/working-with-fuse/server/server.component.ts b/src/app/main/documentation/working-with-fuse/server/server.component.ts new file mode 100644 index 00000000..494254a0 --- /dev/null +++ b/src/app/main/documentation/working-with-fuse/server/server.component.ts @@ -0,0 +1,13 @@ +import { Component } from '@angular/core'; + +@Component({ + selector : 'docs-working-with-fuse-server', + templateUrl: './server.component.html', + styleUrls : ['./server.component.scss'] +}) +export class DocsWorkingWithFuseServerComponent +{ + constructor() + { + } +} diff --git a/src/app/main/documentation/working-with-fuse/theme-layouts/theme-layouts.component.html b/src/app/main/documentation/working-with-fuse/theme-layouts/theme-layouts.component.html new file mode 100644 index 00000000..ddc128f0 --- /dev/null +++ b/src/app/main/documentation/working-with-fuse/theme-layouts/theme-layouts.component.html @@ -0,0 +1,72 @@ +
+ + +
+ +
+ home + chevron_right + Documentation + chevron_right + Working with Fuse +
+ +
Theme Layouts
+ +
+ + + +
+ +

+ Fuse comes with variety of different Theme Layouts which you can see and try them from the configuration + sidebar (Click on the animated, spinning cog button from the right side of your screen). These layouts are + accessible from /src/app/layouts directory and you can modify them however you like. +

+ +

+ Each layout has its own options. Those options allow you to configure the layout elements such as Toolbar, + Footer and Navbar. +

+ +
Directory Structure
+ +

+ Inside the /layouts directory, you will find the following structure: +

+ +
    +
  • + /components: Contains the layout elements such as Toolbar, Footer and Navbar. +
  • +
  • + /vertical: Contains the layout styles with vertical navigation option. +
  • +
  • + /horizontal: Contains the layout styles with horizontal navigation option. +
  • +
+ +

+ Each layout loads the layout elements from /components directory. That means, any modifications + you will make to those elements, will be avilable acrosss the layouts. +

+ +
Configuring the Layout
+ +

+ Fuse has a powerful layout system which allows you to configure and use a different layout per route. Each + route can have its own layout configuration meaning that it's very easy to have pages like login page where + there isn't any toolbar or navbar showing, without leaving the Fuse. +

+ +

+ You can get more information about the Fuse Config Service and its usage from + Config documantation page. +

+ +
+ + +
\ No newline at end of file diff --git a/src/app/main/documentation/working-with-fuse/theme-layouts/theme-layouts.component.scss b/src/app/main/documentation/working-with-fuse/theme-layouts/theme-layouts.component.scss new file mode 100644 index 00000000..ca2a0c07 --- /dev/null +++ b/src/app/main/documentation/working-with-fuse/theme-layouts/theme-layouts.component.scss @@ -0,0 +1,5 @@ +@import "src/@fuse/scss/fuse"; + +:host { + +} diff --git a/src/app/main/documentation/working-with-fuse/theme-layouts/theme-layouts.component.ts b/src/app/main/documentation/working-with-fuse/theme-layouts/theme-layouts.component.ts new file mode 100644 index 00000000..d71fc742 --- /dev/null +++ b/src/app/main/documentation/working-with-fuse/theme-layouts/theme-layouts.component.ts @@ -0,0 +1,13 @@ +import { Component } from '@angular/core'; + +@Component({ + selector : 'docs-working-with-fuse-theme-layouts', + templateUrl: './theme-layouts.component.html', + styleUrls : ['./theme-layouts.component.scss'] +}) +export class DocsWorkingWithFuseThemeLayoutsComponent +{ + constructor() + { + } +} diff --git a/src/app/main/documentation/working-with-fuse/updating-fuse/updating-fuse.component.html b/src/app/main/documentation/working-with-fuse/updating-fuse/updating-fuse.component.html new file mode 100644 index 00000000..2fa9c61c --- /dev/null +++ b/src/app/main/documentation/working-with-fuse/updating-fuse/updating-fuse.component.html @@ -0,0 +1,52 @@ +
+ + +
+ +
+ home + chevron_right + Documentation + chevron_right + Working with Fuse +
+ +
Updating Fuse
+ +
+ + + +
+ +

+ Due to the nature of apps, we cannot give any set instructions for updating Fuse. It heavily depends on your + project and it's up to you to update your code. However, there are couple points that we want to put forward + which might help you to keep Fuse updated. +

+ +
    +
  • + The most important one is not to touch the /@fuse directory but sometimes that is going to be + inevitable and in those cases, try to keep the modifications minimal. +
  • + +
  • + Usually Angular and Angular Material libraries do some breaking changes and force our hands to change + things. In those cases, it's always good to check their official Changelogs to see what they did. + Usually they provide clear instructions and even helper tools to update your code. +
  • + +
  • + Before starting your new project, join our Github repo, fork it and build your + app on top of that fork. This way, in the future, you can easily merge the changes from the main repo + onto your fork. This will require merging a lot of changes manually, but it's the best way to keep the + Fuse updated. +
  • +
+ +
+ + +
\ No newline at end of file diff --git a/src/app/main/documentation/working-with-fuse/updating-fuse/updating-fuse.component.scss b/src/app/main/documentation/working-with-fuse/updating-fuse/updating-fuse.component.scss new file mode 100644 index 00000000..ca2a0c07 --- /dev/null +++ b/src/app/main/documentation/working-with-fuse/updating-fuse/updating-fuse.component.scss @@ -0,0 +1,5 @@ +@import "src/@fuse/scss/fuse"; + +:host { + +} diff --git a/src/app/main/documentation/working-with-fuse/updating-fuse/updating-fuse.component.ts b/src/app/main/documentation/working-with-fuse/updating-fuse/updating-fuse.component.ts new file mode 100644 index 00000000..7afffa00 --- /dev/null +++ b/src/app/main/documentation/working-with-fuse/updating-fuse/updating-fuse.component.ts @@ -0,0 +1,13 @@ +import { Component } from '@angular/core'; + +@Component({ + selector : 'docs-working-with-fuse-updating-fuse', + templateUrl: './updating-fuse.component.html', + styleUrls : ['./updating-fuse.component.scss'] +}) +export class DocsWorkingWithFuseUpdatingFuseComponent +{ + constructor() + { + } +} diff --git a/src/app/main/documentation/working-with-fuse/working-with-fuse.module.ts b/src/app/main/documentation/working-with-fuse/working-with-fuse.module.ts new file mode 100644 index 00000000..394a3563 --- /dev/null +++ b/src/app/main/documentation/working-with-fuse/working-with-fuse.module.ts @@ -0,0 +1,69 @@ +import { NgModule } from '@angular/core'; +import { RouterModule } from '@angular/router'; +import { MatButtonModule, MatIconModule } from '@angular/material'; + +import { FuseSharedModule } from '@fuse/shared.module'; +import { FuseHighlightModule } from '@fuse/components'; + +import { DocsWorkingWithFuseServerComponent } from 'app/main/documentation/working-with-fuse/server/server.component'; +import { DocsWorkingWithFuseProductionComponent } from 'app/main/documentation/working-with-fuse/production/production.component'; +import { DocsWorkingWithFuseDirectoryStructureComponent } from 'app/main/documentation/working-with-fuse/directory-structure/directory-structure.component'; +import { DocsWorkingWithFuseUpdatingFuseComponent } from 'app/main/documentation/working-with-fuse/updating-fuse/updating-fuse.component'; +import { DocsWorkingWithFuseMultiLanguageComponent } from 'app/main/documentation/working-with-fuse/multi-language/multi-language.component'; +import { DocsWorkingWithFuseThemeLayoutsComponent } from 'app/main/documentation/working-with-fuse/theme-layouts/theme-layouts.component'; +import { DocsWorkingWithFusePageLayoutsComponent } from 'app/main/documentation/working-with-fuse/page-layouts/page-layouts.component'; + +const routes = [ + { + path : 'server', + component: DocsWorkingWithFuseServerComponent + }, + { + path : 'production', + component: DocsWorkingWithFuseProductionComponent + }, + { + path : 'directory-structure', + component: DocsWorkingWithFuseDirectoryStructureComponent + }, + { + path : 'updating-fuse', + component: DocsWorkingWithFuseUpdatingFuseComponent + }, + { + path : 'multi-language', + component: DocsWorkingWithFuseMultiLanguageComponent + }, + { + path : 'theme-layouts', + component: DocsWorkingWithFuseThemeLayoutsComponent + }, + { + path : 'page-layouts', + component: DocsWorkingWithFusePageLayoutsComponent + } +]; + +@NgModule({ + declarations: [ + DocsWorkingWithFuseServerComponent, + DocsWorkingWithFuseProductionComponent, + DocsWorkingWithFuseDirectoryStructureComponent, + DocsWorkingWithFuseUpdatingFuseComponent, + DocsWorkingWithFuseMultiLanguageComponent, + DocsWorkingWithFuseThemeLayoutsComponent, + DocsWorkingWithFusePageLayoutsComponent + ], + imports : [ + RouterModule.forChild(routes), + + MatButtonModule, + MatIconModule, + + FuseSharedModule, + FuseHighlightModule + ] +}) +export class WorkingWithFuseModule +{ +} diff --git a/src/app/main/main.component.html b/src/app/main/main.component.html deleted file mode 100644 index a2cc7980..00000000 --- a/src/app/main/main.component.html +++ /dev/null @@ -1,77 +0,0 @@ - - -
- - - - - - - - - - - - -
- - - - - - - -
- - - - - - - - - - - - - - - -
- - - - - - - -
- - - - - - - -
- - - - - - - -
- - diff --git a/src/app/main/main.component.scss b/src/app/main/main.component.scss deleted file mode 100644 index c677d9e3..00000000 --- a/src/app/main/main.component.scss +++ /dev/null @@ -1,75 +0,0 @@ -@import "src/@fuse/scss/fuse"; - -fuse-main { - display: flex; - flex-direction: column; - width: 100%; - height: 100%; - - > .mat-sidenav-container { - display: flex; - flex: 1; - - > .mat-sidenav-content, - > .mat-drawer-content { - display: flex; - flex: 1; - overflow: hidden; - height: 100vh; - - @include media-breakpoint-down('sm') { - height: auto !important; - } - - #fuse-main-content { - display: flex; - flex: 1; - flex-direction: column; - overflow: hidden; - - #wrapper { - display: flex; - position: relative; - flex: 1; - overflow: hidden; - - .content-wrapper { - display: flex; - flex-direction: column; - flex: 1; - overflow: hidden; - - fuse-content { - position: relative; - display: flex; - flex: 1; - flex-direction: row; - width: 100%; - overflow: hidden; - - > *:not(router-outlet):not(.ps__scrollbar-x-rail):not(.ps__scrollbar-y-rail) { - display: flex; - flex: 1; - width: 100%; - min-width: 100%; - } - - > *.ng-animating { - - .mat-tab-body { - height: 100vh; - } - } - } - } - } - } - } - } - - &[fuse-layout-mode="boxed"] { - max-width: 1200px; - margin: 0 auto; - @include mat-elevation(8); - } -} diff --git a/src/app/main/main.component.ts b/src/app/main/main.component.ts deleted file mode 100644 index add7433a..00000000 --- a/src/app/main/main.component.ts +++ /dev/null @@ -1,63 +0,0 @@ -import { Component, ElementRef, HostBinding, Inject, OnDestroy, Renderer2, ViewEncapsulation } from '@angular/core'; -import { DOCUMENT } from '@angular/common'; -import { Platform } from '@angular/cdk/platform'; -import { Subscription } from 'rxjs'; - -import { FuseConfigService } from '@fuse/services/config.service'; - -import { navigation } from 'app/navigation/navigation'; - -@Component({ - selector : 'fuse-main', - templateUrl : './main.component.html', - styleUrls : ['./main.component.scss'], - encapsulation: ViewEncapsulation.None -}) -export class FuseMainComponent implements OnDestroy -{ - onConfigChanged: Subscription; - fuseSettings: any; - navigation: any; - - @HostBinding('attr.fuse-layout-mode') layoutMode; - - constructor( - private _renderer: Renderer2, - private _elementRef: ElementRef, - private fuseConfig: FuseConfigService, - private platform: Platform, - @Inject(DOCUMENT) private document: any - ) - { - this.onConfigChanged = - this.fuseConfig.onConfigChanged - .subscribe( - (newSettings) => { - this.fuseSettings = newSettings; - this.layoutMode = this.fuseSettings.layout.mode; - } - ); - - if ( this.platform.ANDROID || this.platform.IOS ) - { - this.document.body.className += ' is-mobile'; - } - - this.navigation = navigation; - } - - ngOnDestroy() - { - this.onConfigChanged.unsubscribe(); - } - - addClass(className: string) - { - this._renderer.addClass(this._elementRef.nativeElement, className); - } - - removeClass(className: string) - { - this._renderer.removeClass(this._elementRef.nativeElement, className); - } -} diff --git a/src/app/main/main.module.ts b/src/app/main/main.module.ts deleted file mode 100644 index f7c03c72..00000000 --- a/src/app/main/main.module.ts +++ /dev/null @@ -1,46 +0,0 @@ -import { NgModule } from '@angular/core'; -import { RouterModule } from '@angular/router'; -import { MatSidenavModule } from '@angular/material'; - -import { FuseSharedModule } from '@fuse/shared.module'; -import { FuseNavigationModule, FuseSearchBarModule, FuseShortcutsModule, FuseSidebarModule, FuseThemeOptionsModule } from '@fuse/components'; - -import { FuseContentModule } from 'app/main/content/content.module'; -import { FuseFooterModule } from 'app/main/footer/footer.module'; -import { FuseNavbarModule } from 'app/main/navbar/navbar.module'; -import { FuseQuickPanelModule } from 'app/main/quick-panel/quick-panel.module'; -import { FuseToolbarModule } from 'app/main/toolbar/toolbar.module'; - -import { FuseMainComponent } from './main.component'; - - -@NgModule({ - declarations: [ - FuseMainComponent, - ], - imports : [ - RouterModule, - - MatSidenavModule, - - FuseSharedModule, - - FuseThemeOptionsModule, - FuseNavigationModule, - FuseSearchBarModule, - FuseShortcutsModule, - FuseSidebarModule, - - FuseContentModule, - FuseFooterModule, - FuseNavbarModule, - FuseQuickPanelModule, - FuseToolbarModule, - ], - exports : [ - FuseMainComponent - ] -}) -export class FuseMainModule -{ -} diff --git a/src/app/main/navbar/navbar.component.ts b/src/app/main/navbar/navbar.component.ts deleted file mode 100644 index 340ba35d..00000000 --- a/src/app/main/navbar/navbar.component.ts +++ /dev/null @@ -1,95 +0,0 @@ -import { Component, Input, OnDestroy, OnInit, ViewChild, ViewEncapsulation } from '@angular/core'; -import { NavigationEnd, Router } from '@angular/router'; - -import { Subscription } from 'rxjs'; - -import { FusePerfectScrollbarDirective } from '@fuse/directives/fuse-perfect-scrollbar/fuse-perfect-scrollbar.directive'; -import { FuseSidebarService } from '@fuse/components/sidebar/sidebar.service'; - -import { navigation } from 'app/navigation/navigation'; -import { FuseNavigationService } from '@fuse/components/navigation/navigation.service'; -import { FuseSidebarComponent } from '@fuse/components/sidebar/sidebar.component'; - -@Component({ - selector : 'fuse-navbar', - templateUrl : './navbar.component.html', - styleUrls : ['./navbar.component.scss'], - encapsulation: ViewEncapsulation.None -}) -export class FuseNavbarComponent implements OnInit, OnDestroy -{ - private fusePerfectScrollbar: FusePerfectScrollbarDirective; - - @ViewChild(FusePerfectScrollbarDirective) set directive(theDirective: FusePerfectScrollbarDirective) - { - if ( !theDirective ) - { - return; - } - - this.fusePerfectScrollbar = theDirective; - - this.navigationServiceWatcher = - this.navigationService.onItemCollapseToggled.subscribe(() => { - this.fusePerfectScrollbarUpdateTimeout = setTimeout(() => { - this.fusePerfectScrollbar.update(); - }, 310); - }); - } - - @Input() layout; - navigation: any; - navigationServiceWatcher: Subscription; - fusePerfectScrollbarUpdateTimeout; - - constructor( - private sidebarService: FuseSidebarService, - private navigationService: FuseNavigationService, - private router: Router - ) - { - // Navigation data - this.navigation = navigation; - - // Default layout - this.layout = 'vertical'; - } - - ngOnInit() - { - this.router.events.subscribe( - (event) => { - if ( event instanceof NavigationEnd ) - { - if ( this.sidebarService.getSidebar('navbar') ) - { - this.sidebarService.getSidebar('navbar').close(); - } - } - } - ); - } - - ngOnDestroy() - { - if ( this.fusePerfectScrollbarUpdateTimeout ) - { - clearTimeout(this.fusePerfectScrollbarUpdateTimeout); - } - - if ( this.navigationServiceWatcher ) - { - this.navigationServiceWatcher.unsubscribe(); - } - } - - toggleSidebarOpened() - { - this.sidebarService.getSidebar('navbar').toggleOpen(); - } - - toggleSidebarFolded() - { - this.sidebarService.getSidebar('navbar').toggleFold(); - } -} diff --git a/src/app/main/pages/authentication/forgot-password-2/forgot-password-2.component.ts b/src/app/main/pages/authentication/forgot-password-2/forgot-password-2.component.ts new file mode 100644 index 00000000..5a2a75d1 --- /dev/null +++ b/src/app/main/pages/authentication/forgot-password-2/forgot-password-2.component.ts @@ -0,0 +1,116 @@ +import { Component, OnDestroy, OnInit } from '@angular/core'; +import { FormBuilder, FormGroup, Validators } from '@angular/forms'; +import { Subject } from 'rxjs'; +import { takeUntil } from 'rxjs/operators'; + +import { FuseConfigService } from '@fuse/services/config.service'; +import { fuseAnimations } from '@fuse/animations'; + +@Component({ + selector : 'forgot-password-2', + templateUrl: './forgot-password-2.component.html', + styleUrls : ['./forgot-password-2.component.scss'], + animations : fuseAnimations +}) +export class ForgotPassword2Component implements OnInit, OnDestroy +{ + forgotPasswordForm: FormGroup; + forgotPasswordFormErrors: any; + + // Private + private _unsubscribeAll: Subject; + + /** + * Constructor + * + * @param {FuseConfigService} _fuseConfigService + * @param {FormBuilder} _formBuilder + */ + constructor( + private _fuseConfigService: FuseConfigService, + private _formBuilder: FormBuilder + ) + { + // Configure the layout + this._fuseConfigService.config = { + layout: { + navbar : { + hidden: true + }, + toolbar: { + hidden: true + }, + footer : { + hidden: true + } + } + }; + + // Set the defaults + this.forgotPasswordFormErrors = { + email: {} + }; + + // Set the private defaults + this._unsubscribeAll = new Subject(); + } + + // ----------------------------------------------------------------------------------------------------- + // @ Lifecycle hooks + // ----------------------------------------------------------------------------------------------------- + + /** + * On init + */ + ngOnInit(): void + { + this.forgotPasswordForm = this._formBuilder.group({ + email: ['', [Validators.required, Validators.email]] + }); + + this.forgotPasswordForm.valueChanges + .pipe(takeUntil(this._unsubscribeAll)) + .subscribe(() => { + this.onForgotPasswordFormValuesChanged(); + }); + } + + /** + * On destroy + */ + ngOnDestroy(): void + { + // Unsubscribe from all subscriptions + this._unsubscribeAll.next(); + this._unsubscribeAll.complete(); + } + + // ----------------------------------------------------------------------------------------------------- + // @ Public methods + // ----------------------------------------------------------------------------------------------------- + + /** + * On form values changed + */ + onForgotPasswordFormValuesChanged(): void + { + for ( const field in this.forgotPasswordFormErrors ) + { + if ( !this.forgotPasswordFormErrors.hasOwnProperty(field) ) + { + continue; + } + + // Clear previous errors + this.forgotPasswordFormErrors[field] = {}; + + // Get the control + const control = this.forgotPasswordForm.get(field); + + if ( control && control.dirty && !control.valid ) + { + this.forgotPasswordFormErrors[field] = control.errors; + } + } + } +} diff --git a/src/app/main/pages/authentication/forgot-password/forgot-password.component.ts b/src/app/main/pages/authentication/forgot-password/forgot-password.component.ts new file mode 100644 index 00000000..e59477b7 --- /dev/null +++ b/src/app/main/pages/authentication/forgot-password/forgot-password.component.ts @@ -0,0 +1,116 @@ +import { Component, OnDestroy, OnInit } from '@angular/core'; +import { FormBuilder, FormGroup, Validators } from '@angular/forms'; +import { Subject } from 'rxjs'; +import { takeUntil } from 'rxjs/operators'; + +import { FuseConfigService } from '@fuse/services/config.service'; +import { fuseAnimations } from '@fuse/animations'; + +@Component({ + selector : 'forgot-password', + templateUrl: './forgot-password.component.html', + styleUrls : ['./forgot-password.component.scss'], + animations : fuseAnimations +}) +export class ForgotPasswordComponent implements OnInit, OnDestroy +{ + forgotPasswordForm: FormGroup; + forgotPasswordFormErrors: any; + + // Private + private _unsubscribeAll: Subject; + + /** + * Constructor + * + * @param {FuseConfigService} _fuseConfigService + * @param {FormBuilder} _formBuilder + */ + constructor( + private _fuseConfigService: FuseConfigService, + private _formBuilder: FormBuilder + ) + { + // Configure the layout + this._fuseConfigService.config = { + layout: { + navbar : { + hidden: true + }, + toolbar: { + hidden: true + }, + footer : { + hidden: true + } + } + }; + + // Set the defaults + this.forgotPasswordFormErrors = { + email: {} + }; + + // Set the private defaults + this._unsubscribeAll = new Subject(); + } + + // ----------------------------------------------------------------------------------------------------- + // @ Lifecycle hooks + // ----------------------------------------------------------------------------------------------------- + + /** + * On init + */ + ngOnInit(): void + { + this.forgotPasswordForm = this._formBuilder.group({ + email: ['', [Validators.required, Validators.email]] + }); + + this.forgotPasswordForm.valueChanges + .pipe(takeUntil(this._unsubscribeAll)) + .subscribe(() => { + this.onForgotPasswordFormValuesChanged(); + }); + } + + /** + * On destroy + */ + ngOnDestroy(): void + { + // Unsubscribe from all subscriptions + this._unsubscribeAll.next(); + this._unsubscribeAll.complete(); + } + + // ----------------------------------------------------------------------------------------------------- + // @ Public methods + // ----------------------------------------------------------------------------------------------------- + + /** + * On form values changed + */ + onForgotPasswordFormValuesChanged(): void + { + for ( const field in this.forgotPasswordFormErrors ) + { + if ( !this.forgotPasswordFormErrors.hasOwnProperty(field) ) + { + continue; + } + + // Clear previous errors + this.forgotPasswordFormErrors[field] = {}; + + // Get the control + const control = this.forgotPasswordForm.get(field); + + if ( control && control.dirty && !control.valid ) + { + this.forgotPasswordFormErrors[field] = control.errors; + } + } + } +} diff --git a/src/app/main/pages/authentication/lock/lock.component.ts b/src/app/main/pages/authentication/lock/lock.component.ts new file mode 100644 index 00000000..b0399f8b --- /dev/null +++ b/src/app/main/pages/authentication/lock/lock.component.ts @@ -0,0 +1,123 @@ +import { Component, OnDestroy, OnInit } from '@angular/core'; +import { FormBuilder, FormGroup, Validators } from '@angular/forms'; +import { Subject } from 'rxjs'; +import { takeUntil } from 'rxjs/operators'; + +import { FuseConfigService } from '@fuse/services/config.service'; +import { fuseAnimations } from '@fuse/animations'; + +@Component({ + selector : 'lock', + templateUrl: './lock.component.html', + styleUrls : ['./lock.component.scss'], + animations : fuseAnimations +}) +export class LockComponent implements OnInit, OnDestroy +{ + lockForm: FormGroup; + lockFormErrors: any; + + // Private + private _unsubscribeAll: Subject; + + /** + * Constructor + * + * @param {FuseConfigService} _fuseConfigService + * @param {FormBuilder} _formBuilder + */ + constructor( + private _fuseConfigService: FuseConfigService, + private _formBuilder: FormBuilder + ) + { + // Configure the layout + this._fuseConfigService.config = { + layout: { + navbar : { + hidden: true + }, + toolbar: { + hidden: true + }, + footer : { + hidden: true + } + } + }; + + // Set the defaults + this.lockFormErrors = { + username: {}, + password: {} + }; + + // Set the private defaults + this._unsubscribeAll = new Subject(); + } + + // ----------------------------------------------------------------------------------------------------- + // @ Lifecycle hooks + // ----------------------------------------------------------------------------------------------------- + + /** + * On init + */ + ngOnInit(): void + { + this.lockForm = this._formBuilder.group({ + username: [ + { + value : 'Katherine', + disabled: true + }, Validators.required + ], + password: ['', Validators.required] + }); + + this.lockForm.valueChanges + .pipe(takeUntil(this._unsubscribeAll)) + .subscribe(() => { + this.onLockFormValuesChanged(); + }); + } + + /** + * On destroy + */ + ngOnDestroy(): void + { + // Unsubscribe from all subscriptions + this._unsubscribeAll.next(); + this._unsubscribeAll.complete(); + } + + // ----------------------------------------------------------------------------------------------------- + // @ Public methods + // ----------------------------------------------------------------------------------------------------- + + /** + * On form values changed + */ + onLockFormValuesChanged(): void + { + for ( const field in this.lockFormErrors ) + { + if ( !this.lockFormErrors.hasOwnProperty(field) ) + { + continue; + } + + // Clear previous errors + this.lockFormErrors[field] = {}; + + // Get the control + const control = this.lockForm.get(field); + + if ( control && control.dirty && !control.valid ) + { + this.lockFormErrors[field] = control.errors; + } + } + } +} diff --git a/src/app/main/pages/authentication/login-2/login-2.component.ts b/src/app/main/pages/authentication/login-2/login-2.component.ts new file mode 100644 index 00000000..f9da1110 --- /dev/null +++ b/src/app/main/pages/authentication/login-2/login-2.component.ts @@ -0,0 +1,118 @@ +import { Component, OnDestroy, OnInit } from '@angular/core'; +import { FormBuilder, FormGroup, Validators } from '@angular/forms'; +import { Subject } from 'rxjs'; +import { takeUntil } from 'rxjs/operators'; + +import { FuseConfigService } from '@fuse/services/config.service'; +import { fuseAnimations } from '@fuse/animations'; + +@Component({ + selector : 'login-2', + templateUrl: './login-2.component.html', + styleUrls : ['./login-2.component.scss'], + animations : fuseAnimations +}) +export class Login2Component implements OnInit, OnDestroy +{ + loginForm: FormGroup; + loginFormErrors: any; + + // Private + private _unsubscribeAll: Subject; + + /** + * Constructor + * + * @param {FuseConfigService} _fuseConfigService + * @param {FormBuilder} _formBuilder + */ + constructor( + private _fuseConfigService: FuseConfigService, + private _formBuilder: FormBuilder + ) + { + // Configure the layout + this._fuseConfigService.config = { + layout: { + navbar : { + hidden: true + }, + toolbar: { + hidden: true + }, + footer : { + hidden: true + } + } + }; + + // Set the defaults + this.loginFormErrors = { + email : {}, + password: {} + }; + + // Set the private defaults + this._unsubscribeAll = new Subject(); + } + + // ----------------------------------------------------------------------------------------------------- + // @ Lifecycle hooks + // ----------------------------------------------------------------------------------------------------- + + /** + * On init + */ + ngOnInit(): void + { + this.loginForm = this._formBuilder.group({ + email : ['', [Validators.required, Validators.email]], + password: ['', Validators.required] + }); + + this.loginForm.valueChanges + .pipe(takeUntil(this._unsubscribeAll)) + .subscribe(() => { + this.onLoginFormValuesChanged(); + }); + } + + /** + * On destroy + */ + ngOnDestroy(): void + { + // Unsubscribe from all subscriptions + this._unsubscribeAll.next(); + this._unsubscribeAll.complete(); + } + + // ----------------------------------------------------------------------------------------------------- + // @ Public methods + // ----------------------------------------------------------------------------------------------------- + + /** + * On form values changed + */ + onLoginFormValuesChanged(): void + { + for ( const field in this.loginFormErrors ) + { + if ( !this.loginFormErrors.hasOwnProperty(field) ) + { + continue; + } + + // Clear previous errors + this.loginFormErrors[field] = {}; + + // Get the control + const control = this.loginForm.get(field); + + if ( control && control.dirty && !control.valid ) + { + this.loginFormErrors[field] = control.errors; + } + } + } +} diff --git a/src/app/main/pages/authentication/login/login.component.ts b/src/app/main/pages/authentication/login/login.component.ts new file mode 100644 index 00000000..cd3a83b7 --- /dev/null +++ b/src/app/main/pages/authentication/login/login.component.ts @@ -0,0 +1,118 @@ +import { Component, OnDestroy, OnInit } from '@angular/core'; +import { FormBuilder, FormGroup, Validators } from '@angular/forms'; +import { Subject } from 'rxjs'; +import { takeUntil } from 'rxjs/operators'; + +import { FuseConfigService } from '@fuse/services/config.service'; +import { fuseAnimations } from '@fuse/animations'; + +@Component({ + selector : 'login', + templateUrl: './login.component.html', + styleUrls : ['./login.component.scss'], + animations : fuseAnimations +}) +export class LoginComponent implements OnInit, OnDestroy +{ + loginForm: FormGroup; + loginFormErrors: any; + + // Private + private _unsubscribeAll: Subject; + + /** + * Constructor + * + * @param {FuseConfigService} _fuseConfigService + * @param {FormBuilder} _formBuilder + */ + constructor( + private _fuseConfigService: FuseConfigService, + private _formBuilder: FormBuilder + ) + { + // Configure the layout + this._fuseConfigService.config = { + layout: { + navbar : { + hidden: true + }, + toolbar: { + hidden: true + }, + footer : { + hidden: true + } + } + }; + + // Set the defaults + this.loginFormErrors = { + email : {}, + password: {} + }; + + // Set the private defaults + this._unsubscribeAll = new Subject(); + } + + // ----------------------------------------------------------------------------------------------------- + // @ Lifecycle hooks + // ----------------------------------------------------------------------------------------------------- + + /** + * On init + */ + ngOnInit(): void + { + this.loginForm = this._formBuilder.group({ + email : ['', [Validators.required, Validators.email]], + password: ['', Validators.required] + }); + + this.loginForm.valueChanges + .pipe(takeUntil(this._unsubscribeAll)) + .subscribe(() => { + this.onLoginFormValuesChanged(); + }); + } + + /** + * On destroy + */ + ngOnDestroy(): void + { + // Unsubscribe from all subscriptions + this._unsubscribeAll.next(); + this._unsubscribeAll.complete(); + } + + // ----------------------------------------------------------------------------------------------------- + // @ Public methods + // ----------------------------------------------------------------------------------------------------- + + /** + * On form values changed + */ + onLoginFormValuesChanged(): void + { + for ( const field in this.loginFormErrors ) + { + if ( !this.loginFormErrors.hasOwnProperty(field) ) + { + continue; + } + + // Clear previous errors + this.loginFormErrors[field] = {}; + + // Get the control + const control = this.loginForm.get(field); + + if ( control && control.dirty && !control.valid ) + { + this.loginFormErrors[field] = control.errors; + } + } + } +} diff --git a/src/app/main/pages/authentication/mail-confirm/mail-confirm.component.ts b/src/app/main/pages/authentication/mail-confirm/mail-confirm.component.ts new file mode 100644 index 00000000..e69c2256 --- /dev/null +++ b/src/app/main/pages/authentication/mail-confirm/mail-confirm.component.ts @@ -0,0 +1,38 @@ +import { Component } from '@angular/core'; + +import { FuseConfigService } from '@fuse/services/config.service'; +import { fuseAnimations } from '@fuse/animations'; + +@Component({ + selector : 'mail-confirm', + templateUrl: './mail-confirm.component.html', + styleUrls : ['./mail-confirm.component.scss'], + animations : fuseAnimations +}) +export class MailConfirmComponent +{ + /** + * Constructor + * + * @param {FuseConfigService} _fuseConfigService + */ + constructor( + private _fuseConfigService: FuseConfigService + ) + { + // Configure the layout + this._fuseConfigService.config = { + layout: { + navbar : { + hidden: true + }, + toolbar: { + hidden: true + }, + footer : { + hidden: true + } + } + }; + } +} diff --git a/src/app/main/pages/authentication/register-2/register-2.component.ts b/src/app/main/pages/authentication/register-2/register-2.component.ts new file mode 100644 index 00000000..5ef53f56 --- /dev/null +++ b/src/app/main/pages/authentication/register-2/register-2.component.ts @@ -0,0 +1,156 @@ +import { Component, OnDestroy, OnInit } from '@angular/core'; +import { AbstractControl, FormBuilder, FormGroup, Validators } from '@angular/forms'; +import { Subject } from 'rxjs'; +import { takeUntil } from 'rxjs/operators'; + +import { FuseConfigService } from '@fuse/services/config.service'; +import { fuseAnimations } from '@fuse/animations'; + +@Component({ + selector : 'register-2', + templateUrl: './register-2.component.html', + styleUrls : ['./register-2.component.scss'], + animations : fuseAnimations +}) +export class Register2Component implements OnInit, OnDestroy +{ + registerForm: FormGroup; + registerFormErrors: any; + + // Private + private _unsubscribeAll: Subject; + + /** + * Constructor + * + * @param {FuseConfigService} _fuseConfigService + * @param {FormBuilder} _formBuilder + */ + constructor( + private _fuseConfigService: FuseConfigService, + private _formBuilder: FormBuilder + ) + { + // Configure the layout + this._fuseConfigService.config = { + layout: { + navbar : { + hidden: true + }, + toolbar: { + hidden: true + }, + footer : { + hidden: true + } + } + }; + + // Set the defaults + this.registerFormErrors = { + name : {}, + email : {}, + password : {}, + passwordConfirm: {} + }; + + // Set the private defaults + this._unsubscribeAll = new Subject(); + } + + // ----------------------------------------------------------------------------------------------------- + // @ Lifecycle hooks + // ----------------------------------------------------------------------------------------------------- + + /** + * On init + */ + ngOnInit(): void + { + this.registerForm = this._formBuilder.group({ + name : ['', Validators.required], + email : ['', [Validators.required, Validators.email]], + password : ['', Validators.required], + passwordConfirm: ['', [Validators.required, confirmPassword]] + }); + + this.registerForm.valueChanges + .pipe(takeUntil(this._unsubscribeAll)) + .subscribe(() => { + this.onRegisterFormValuesChanged(); + }); + } + + /** + * On destroy + */ + ngOnDestroy(): void + { + // Unsubscribe from all subscriptions + this._unsubscribeAll.next(); + this._unsubscribeAll.complete(); + } + + // ----------------------------------------------------------------------------------------------------- + // @ Public methods + // ----------------------------------------------------------------------------------------------------- + + /** + * On form values changed + */ + onRegisterFormValuesChanged(): void + { + for ( const field in this.registerFormErrors ) + { + if ( !this.registerFormErrors.hasOwnProperty(field) ) + { + continue; + } + + // Clear previous errors + this.registerFormErrors[field] = {}; + + // Get the control + const control = this.registerForm.get(field); + + if ( control && control.dirty && !control.valid ) + { + this.registerFormErrors[field] = control.errors; + } + } + } +} + +/** + * Confirm password + * + * @param {AbstractControl} control + * @returns {{passwordsNotMatch: boolean}} + */ +function confirmPassword(control: AbstractControl): any +{ + if ( !control.parent || !control ) + { + return; + } + + const password = control.parent.get('password'); + const passwordConfirm = control.parent.get('passwordConfirm'); + + if ( !password || !passwordConfirm ) + { + return; + } + + if ( passwordConfirm.value === '' ) + { + return; + } + + if ( password.value !== passwordConfirm.value ) + { + return { + passwordsNotMatch: true + }; + } +} diff --git a/src/app/main/pages/authentication/register/register.component.ts b/src/app/main/pages/authentication/register/register.component.ts new file mode 100644 index 00000000..aebc79a0 --- /dev/null +++ b/src/app/main/pages/authentication/register/register.component.ts @@ -0,0 +1,150 @@ +import { Component, OnDestroy, OnInit } from '@angular/core'; +import { AbstractControl, FormBuilder, FormGroup, Validators } from '@angular/forms'; + +import { FuseConfigService } from '@fuse/services/config.service'; +import { fuseAnimations } from '@fuse/animations'; +import { Subject } from 'rxjs'; +import { takeUntil } from 'rxjs/internal/operators'; + +@Component({ + selector : 'register', + templateUrl: './register.component.html', + styleUrls : ['./register.component.scss'], + animations : fuseAnimations +}) +export class RegisterComponent implements OnInit, OnDestroy +{ + registerForm: FormGroup; + registerFormErrors: any; + + // Private + private _unsubscribeAll: Subject; + + constructor( + private _fuseConfigService: FuseConfigService, + private _formBuilder: FormBuilder + ) + { + // Configure the layout + this._fuseConfigService.config = { + layout: { + navbar : { + hidden: true + }, + toolbar: { + hidden: true + }, + footer : { + hidden: true + } + } + }; + + // Set the defaults + this.registerFormErrors = { + name : {}, + email : {}, + password : {}, + passwordConfirm: {} + }; + + // Set the private defaults + this._unsubscribeAll = new Subject(); + } + + // ----------------------------------------------------------------------------------------------------- + // @ Lifecycle hooks + // ----------------------------------------------------------------------------------------------------- + + /** + * On init + */ + ngOnInit(): void + { + this.registerForm = this._formBuilder.group({ + name : ['', Validators.required], + email : ['', [Validators.required, Validators.email]], + password : ['', Validators.required], + passwordConfirm: ['', [Validators.required, confirmPassword]] + }); + + this.registerForm.valueChanges + .pipe(takeUntil(this._unsubscribeAll)) + .subscribe(() => { + this.onRegisterFormValuesChanged(); + }); + } + + /** + * On destroy + */ + ngOnDestroy(): void + { + // Unsubscribe from all subscriptions + this._unsubscribeAll.next(); + this._unsubscribeAll.complete(); + } + + // ----------------------------------------------------------------------------------------------------- + // @ Public methods + // ----------------------------------------------------------------------------------------------------- + + /** + * On form values changed + */ + onRegisterFormValuesChanged(): void + { + for ( const field in this.registerFormErrors ) + { + if ( !this.registerFormErrors.hasOwnProperty(field) ) + { + continue; + } + + // Clear previous errors + this.registerFormErrors[field] = {}; + + // Get the control + const control = this.registerForm.get(field); + + if ( control && control.dirty && !control.valid ) + { + this.registerFormErrors[field] = control.errors; + } + } + } +} + +/** + * Confirm password + * + * @param {AbstractControl} control + * @returns {{passwordsNotMatch: boolean}} + */ +function confirmPassword(control: AbstractControl): any +{ + if ( !control.parent || !control ) + { + return; + } + + const password = control.parent.get('password'); + const passwordConfirm = control.parent.get('passwordConfirm'); + + if ( !password || !passwordConfirm ) + { + return; + } + + if ( passwordConfirm.value === '' ) + { + return; + } + + if ( password.value !== passwordConfirm.value ) + { + return { + passwordsNotMatch: true + }; + } +} diff --git a/src/app/main/pages/authentication/reset-password-2/reset-password-2.component.ts b/src/app/main/pages/authentication/reset-password-2/reset-password-2.component.ts new file mode 100644 index 00000000..052beba7 --- /dev/null +++ b/src/app/main/pages/authentication/reset-password-2/reset-password-2.component.ts @@ -0,0 +1,148 @@ +import { Component, OnDestroy, OnInit } from '@angular/core'; +import { AbstractControl, FormBuilder, FormGroup, Validators } from '@angular/forms'; + +import { FuseConfigService } from '@fuse/services/config.service'; +import { fuseAnimations } from '@fuse/animations'; +import { Subject } from 'rxjs'; +import { takeUntil } from 'rxjs/internal/operators'; + +@Component({ + selector : 'reset-password-2', + templateUrl: './reset-password-2.component.html', + styleUrls : ['./reset-password-2.component.scss'], + animations : fuseAnimations +}) +export class ResetPassword2Component implements OnInit, OnDestroy +{ + resetPasswordForm: FormGroup; + resetPasswordFormErrors: any; + + // Private + private _unsubscribeAll: Subject; + + constructor( + private _fuseConfigService: FuseConfigService, + private _formBuilder: FormBuilder + ) + { + // Configure the layout + this._fuseConfigService.config = { + layout: { + navbar : { + hidden: true + }, + toolbar: { + hidden: true + }, + footer : { + hidden: true + } + } + }; + + // Set the defaults + this.resetPasswordFormErrors = { + email : {}, + password : {}, + passwordConfirm: {} + }; + + // Set the private defaults + this._unsubscribeAll = new Subject(); + } + + // ----------------------------------------------------------------------------------------------------- + // @ Lifecycle hooks + // ----------------------------------------------------------------------------------------------------- + + /** + * On init + */ + ngOnInit(): void + { + this.resetPasswordForm = this._formBuilder.group({ + email : ['', [Validators.required, Validators.email]], + password : ['', Validators.required], + passwordConfirm: ['', [Validators.required, confirmPassword]] + }); + + this.resetPasswordForm.valueChanges + .pipe(takeUntil(this._unsubscribeAll)) + .subscribe(() => { + this.onResetPasswordFormValuesChanged(); + }); + } + + /** + * On destroy + */ + ngOnDestroy(): void + { + // Unsubscribe from all subscriptions + this._unsubscribeAll.next(); + this._unsubscribeAll.complete(); + } + + // ----------------------------------------------------------------------------------------------------- + // @ Public methods + // ----------------------------------------------------------------------------------------------------- + + /** + * On form values changed + */ + onResetPasswordFormValuesChanged(): void + { + for ( const field in this.resetPasswordFormErrors ) + { + if ( !this.resetPasswordFormErrors.hasOwnProperty(field) ) + { + continue; + } + + // Clear previous errors + this.resetPasswordFormErrors[field] = {}; + + // Get the control + const control = this.resetPasswordForm.get(field); + + if ( control && control.dirty && !control.valid ) + { + this.resetPasswordFormErrors[field] = control.errors; + } + } + } +} + +/** + * Confirm password + * + * @param {AbstractControl} control + * @returns {{passwordsNotMatch: boolean}} + */ +function confirmPassword(control: AbstractControl): any +{ + if ( !control.parent || !control ) + { + return; + } + + const password = control.parent.get('password'); + const passwordConfirm = control.parent.get('passwordConfirm'); + + if ( !password || !passwordConfirm ) + { + return; + } + + if ( passwordConfirm.value === '' ) + { + return; + } + + if ( password.value !== passwordConfirm.value ) + { + return { + passwordsNotMatch: true + }; + } +} diff --git a/src/app/main/pages/authentication/reset-password/reset-password.component.ts b/src/app/main/pages/authentication/reset-password/reset-password.component.ts new file mode 100644 index 00000000..d231c341 --- /dev/null +++ b/src/app/main/pages/authentication/reset-password/reset-password.component.ts @@ -0,0 +1,154 @@ +import { Component, OnDestroy, OnInit } from '@angular/core'; +import { AbstractControl, FormBuilder, FormGroup, Validators } from '@angular/forms'; +import { Subject } from 'rxjs'; +import { takeUntil } from 'rxjs/operators'; + +import { FuseConfigService } from '@fuse/services/config.service'; +import { fuseAnimations } from '@fuse/animations'; + +@Component({ + selector : 'reset-password', + templateUrl: './reset-password.component.html', + styleUrls : ['./reset-password.component.scss'], + animations : fuseAnimations +}) +export class ResetPasswordComponent implements OnInit, OnDestroy +{ + resetPasswordForm: FormGroup; + resetPasswordFormErrors: any; + + // Private + private _unsubscribeAll: Subject; + + /** + * Constructor + * + * @param {FuseConfigService} _fuseConfigService + * @param {FormBuilder} _formBuilder + */ + constructor( + private _fuseConfigService: FuseConfigService, + private _formBuilder: FormBuilder + ) + { + // Configure the layout + this._fuseConfigService.config = { + layout: { + navbar : { + hidden: true + }, + toolbar: { + hidden: true + }, + footer : { + hidden: true + } + } + }; + + // Set the defaults + this.resetPasswordFormErrors = { + email : {}, + password : {}, + passwordConfirm: {} + }; + + // Set the private defaults + this._unsubscribeAll = new Subject(); + } + + // ----------------------------------------------------------------------------------------------------- + // @ Lifecycle hooks + // ----------------------------------------------------------------------------------------------------- + + /** + * On init + */ + ngOnInit(): void + { + this.resetPasswordForm = this._formBuilder.group({ + email : ['', [Validators.required, Validators.email]], + password : ['', Validators.required], + passwordConfirm: ['', [Validators.required, confirmPassword]] + }); + + this.resetPasswordForm.valueChanges + .pipe(takeUntil(this._unsubscribeAll)) + .subscribe(() => { + this.onResetPasswordFormValuesChanged(); + }); + } + + /** + * On destroy + */ + ngOnDestroy(): void + { + // Unsubscribe from all subscriptions + this._unsubscribeAll.next(); + this._unsubscribeAll.complete(); + } + + // ----------------------------------------------------------------------------------------------------- + // @ Public methods + // ----------------------------------------------------------------------------------------------------- + + /** + * On form values changed + */ + onResetPasswordFormValuesChanged(): void + { + for ( const field in this.resetPasswordFormErrors ) + { + if ( !this.resetPasswordFormErrors.hasOwnProperty(field) ) + { + continue; + } + + // Clear previous errors + this.resetPasswordFormErrors[field] = {}; + + // Get the control + const control = this.resetPasswordForm.get(field); + + if ( control && control.dirty && !control.valid ) + { + this.resetPasswordFormErrors[field] = control.errors; + } + } + } +} + +/** + * Confirm password + * + * @param {AbstractControl} control + * @returns {{passwordsNotMatch: boolean}} + */ +function confirmPassword(control: AbstractControl): any +{ + if ( !control.parent || !control ) + { + return; + } + + const password = control.parent.get('password'); + const passwordConfirm = control.parent.get('passwordConfirm'); + + if ( !password || !passwordConfirm ) + { + return; + } + + if ( passwordConfirm.value === '' ) + { + return; + } + + if ( password.value !== passwordConfirm.value ) + { + return { + passwordsNotMatch: true + }; + } +} diff --git a/src/app/main/pages/coming-soon/coming-soon.component.ts b/src/app/main/pages/coming-soon/coming-soon.component.ts new file mode 100644 index 00000000..39cbe734 --- /dev/null +++ b/src/app/main/pages/coming-soon/coming-soon.component.ts @@ -0,0 +1,116 @@ +import { Component, OnDestroy, OnInit } from '@angular/core'; +import { FormBuilder, FormGroup, Validators } from '@angular/forms'; +import { Subject } from 'rxjs'; +import { takeUntil } from 'rxjs/operators'; + +import { FuseConfigService } from '@fuse/services/config.service'; +import { fuseAnimations } from '@fuse/animations'; + +@Component({ + selector : 'coming-soon', + templateUrl: './coming-soon.component.html', + styleUrls : ['./coming-soon.component.scss'], + animations : fuseAnimations +}) +export class ComingSoonComponent implements OnInit, OnDestroy +{ + comingSoonForm: FormGroup; + comingSoonFormErrors: any; + + // Private + private _unsubscribeAll: Subject; + + /** + * Constructor + * + * @param {FuseConfigService} _fuseConfigService + * @param {FormBuilder} _formBuilder + */ + constructor( + private _fuseConfigService: FuseConfigService, + private _formBuilder: FormBuilder + ) + { + // Configure the layout + this._fuseConfigService.config = { + layout: { + navbar : { + hidden: true + }, + toolbar: { + hidden: true + }, + footer : { + hidden: true + } + } + }; + + // Set the defaults + this.comingSoonFormErrors = { + email: {} + }; + + // Set the private defaults + this._unsubscribeAll = new Subject(); + } + + // ----------------------------------------------------------------------------------------------------- + // @ Lifecycle hooks + // ----------------------------------------------------------------------------------------------------- + + /** + * On init + */ + ngOnInit(): void + { + this.comingSoonForm = this._formBuilder.group({ + email: ['', [Validators.required, Validators.email]] + }); + + this.comingSoonForm.valueChanges + .pipe(takeUntil(this._unsubscribeAll)) + .subscribe(() => { + this.onRegisterFormValuesChanged(); + }); + } + + /** + * On destroy + */ + ngOnDestroy(): void + { + // Unsubscribe from all subscriptions + this._unsubscribeAll.next(); + this._unsubscribeAll.complete(); + } + + // ----------------------------------------------------------------------------------------------------- + // @ Public methods + // ----------------------------------------------------------------------------------------------------- + + /** + * On form values changed + */ + onRegisterFormValuesChanged(): void + { + for ( const field in this.comingSoonFormErrors ) + { + if ( !this.comingSoonFormErrors.hasOwnProperty(field) ) + { + continue; + } + + // Clear previous errors + this.comingSoonFormErrors[field] = {}; + + // Get the control + const control = this.comingSoonForm.get(field); + + if ( control && control.dirty && !control.valid ) + { + this.comingSoonFormErrors[field] = control.errors; + } + } + } +} diff --git a/src/app/main/pages/errors/404/error-404.component.ts b/src/app/main/pages/errors/404/error-404.component.ts new file mode 100644 index 00000000..2f8a6986 --- /dev/null +++ b/src/app/main/pages/errors/404/error-404.component.ts @@ -0,0 +1,36 @@ +import { Component } from '@angular/core'; + +import { FuseConfigService } from '@fuse/services/config.service'; + +@Component({ + selector : 'error-404', + templateUrl: './error-404.component.html', + styleUrls : ['./error-404.component.scss'] +}) +export class Error404Component +{ + /** + * Constructor + * + * @param {FuseConfigService} _fuseConfigService + */ + constructor( + private _fuseConfigService: FuseConfigService + ) + { + // Configure the layout + this._fuseConfigService.config = { + layout: { + navbar : { + hidden: true + }, + toolbar: { + hidden: true + }, + footer : { + hidden: true + } + } + }; + } +} diff --git a/src/app/main/pages/errors/500/error-500.component.ts b/src/app/main/pages/errors/500/error-500.component.ts new file mode 100644 index 00000000..f68e94e3 --- /dev/null +++ b/src/app/main/pages/errors/500/error-500.component.ts @@ -0,0 +1,36 @@ +import { Component } from '@angular/core'; + +import { FuseConfigService } from '@fuse/services/config.service'; + +@Component({ + selector : 'error-500', + templateUrl: './error-500.component.html', + styleUrls : ['./error-500.component.scss'] +}) +export class Error500Component +{ + /** + * Constructor + * + * @param {FuseConfigService} _fuseConfigService + */ + constructor( + private _fuseConfigService: FuseConfigService + ) + { + // Configure the layout + this._fuseConfigService.config = { + layout: { + navbar : { + hidden: true + }, + toolbar: { + hidden: true + }, + footer : { + hidden: true + } + } + }; + } +} diff --git a/src/app/main/pages/faq/faq.component.ts b/src/app/main/pages/faq/faq.component.ts new file mode 100644 index 00000000..749aaa3a --- /dev/null +++ b/src/app/main/pages/faq/faq.component.ts @@ -0,0 +1,108 @@ +import { Component, OnInit, OnDestroy } from '@angular/core'; +import { FormControl } from '@angular/forms'; +import { Subject } from 'rxjs'; +import { debounceTime, distinctUntilChanged, takeUntil } from 'rxjs/operators'; + +import { FuseUtils } from '@fuse/utils'; + +import { FaqService } from 'app/main/pages/faq/faq.service'; + +@Component({ + selector : 'faq', + templateUrl: './faq.component.html', + styleUrls : ['./faq.component.scss'] +}) +export class FaqComponent implements OnInit, OnDestroy +{ + faqs: any; + faqsFiltered: any; + step: number; + searchInput: any; + + // Private + private _unsubscribeAll: Subject; + + /** + * Constructor + * + * @param {FaqService} _faqService + */ + constructor( + private _faqService: FaqService + ) + { + // Set the defaults + this.searchInput = new FormControl(''); + this.step = 0; + + // Set the private defaults + this._unsubscribeAll = new Subject(); + } + + // ----------------------------------------------------------------------------------------------------- + // @ Lifecycle hooks + // ----------------------------------------------------------------------------------------------------- + + /** + * On init + */ + ngOnInit(): void + { + this._faqService.onFaqsChanged + .pipe(takeUntil(this._unsubscribeAll)) + .subscribe(response => { + this.faqs = response; + this.faqsFiltered = response; + }); + + this.searchInput.valueChanges + .pipe( + takeUntil(this._unsubscribeAll), + debounceTime(300), + distinctUntilChanged() + ) + .subscribe(searchText => { + this.faqsFiltered = FuseUtils.filterArrayByString(this.faqs, searchText); + }); + } + + /** + * On destroy + */ + ngOnDestroy(): void + { + // Unsubscribe from all subscriptions + this._unsubscribeAll.next(); + this._unsubscribeAll.complete(); + } + + // ----------------------------------------------------------------------------------------------------- + // @ Public methods + // ----------------------------------------------------------------------------------------------------- + + /** + * Set step + * + * @param {number} index + */ + setStep(index: number): void + { + this.step = index; + } + + /** + * Next step + */ + nextStep(): void + { + this.step++; + } + + /** + * Previous step + */ + prevStep(): void + { + this.step--; + } +} diff --git a/src/app/main/pages/invoices/compact/compact.component.ts b/src/app/main/pages/invoices/compact/compact.component.ts new file mode 100644 index 00000000..46e5366b --- /dev/null +++ b/src/app/main/pages/invoices/compact/compact.component.ts @@ -0,0 +1,52 @@ +import { Component, OnDestroy, OnInit } from '@angular/core'; +import { Subject } from 'rxjs'; +import { takeUntil } from 'rxjs/operators'; + +import { InvoiceService } from 'app/main/pages/invoices/invoice.service'; + +@Component({ + selector : 'invoice-compact', + templateUrl: './compact.component.html', + styleUrls : ['./compact.component.scss'] +}) +export class InvoiceCompactComponent implements OnInit, OnDestroy +{ + invoice: any; + + // Private + private _unsubscribeAll: Subject; + + constructor( + private _invoiceService: InvoiceService + ) + { + // Set the private defaults + this._unsubscribeAll = new Subject(); + } + + // ----------------------------------------------------------------------------------------------------- + // @ Lifecycle hooks + // ----------------------------------------------------------------------------------------------------- + + /** + * On init + */ + ngOnInit(): void + { + this._invoiceService.invoiceOnChanged + .pipe(takeUntil(this._unsubscribeAll)) + .subscribe((invoice) => { + this.invoice = invoice; + }); + } + + /** + * On destroy + */ + ngOnDestroy(): void + { + // Unsubscribe from all subscriptions + this._unsubscribeAll.next(); + this._unsubscribeAll.complete(); + } +} diff --git a/src/app/main/pages/invoices/modern/modern.component.ts b/src/app/main/pages/invoices/modern/modern.component.ts new file mode 100644 index 00000000..9757bec2 --- /dev/null +++ b/src/app/main/pages/invoices/modern/modern.component.ts @@ -0,0 +1,58 @@ +import { Component, OnDestroy, OnInit } from '@angular/core'; +import { Subject } from 'rxjs'; +import { takeUntil } from 'rxjs/operators'; + +import { InvoiceService } from 'app/main/pages/invoices/invoice.service'; + +@Component({ + selector : 'invoice-modern', + templateUrl: './modern.component.html', + styleUrls : ['./modern.component.scss'] +}) +export class InvoiceModernComponent implements OnInit, OnDestroy +{ + invoice: any; + + // Private + private _unsubscribeAll: Subject; + + /** + * Constructor + * + * @param {InvoiceService} _invoiceService + */ + constructor( + private _invoiceService: InvoiceService + ) + { + // Set the private defaults + this._unsubscribeAll = new Subject(); + + } + + // ----------------------------------------------------------------------------------------------------- + // @ Lifecycle hooks + // ----------------------------------------------------------------------------------------------------- + + /** + * On init + */ + ngOnInit(): void + { + this._invoiceService.invoiceOnChanged + .pipe(takeUntil(this._unsubscribeAll)) + .subscribe((invoice) => { + this.invoice = invoice; + }); + } + + /** + * On destroy + */ + ngOnDestroy(): void + { + // Unsubscribe from all subscriptions + this._unsubscribeAll.next(); + this._unsubscribeAll.complete(); + } +} diff --git a/src/app/main/pages/knowledge-base/dialogs/article/article.component.ts b/src/app/main/pages/knowledge-base/dialogs/article/article.component.ts new file mode 100644 index 00000000..60f674c4 --- /dev/null +++ b/src/app/main/pages/knowledge-base/dialogs/article/article.component.ts @@ -0,0 +1,24 @@ +import { Component, ViewEncapsulation, Inject } from '@angular/core'; +import { MatDialogRef, MAT_DIALOG_DATA } from '@angular/material'; + +@Component({ + selector : 'knowledge-base-article', + templateUrl : './article.component.html', + styleUrls : ['./article.component.scss'], + encapsulation: ViewEncapsulation.None +}) +export class KnowledgeBaseArticleComponent +{ + /** + * Constructor + * + * @param {MatDialogRef} matDialogRef + * @param _data + */ + constructor( + public matDialogRef: MatDialogRef, + @Inject(MAT_DIALOG_DATA) public _data: any + ) + { + } +} diff --git a/src/app/main/pages/knowledge-base/knowledge-base.component.ts b/src/app/main/pages/knowledge-base/knowledge-base.component.ts new file mode 100644 index 00000000..2f0040da --- /dev/null +++ b/src/app/main/pages/knowledge-base/knowledge-base.component.ts @@ -0,0 +1,79 @@ +import { Component, OnInit, OnDestroy, ViewEncapsulation } from '@angular/core'; +import { MatDialog } from '@angular/material'; +import { Subject } from 'rxjs'; +import { takeUntil } from 'rxjs/operators'; + +import { KnowledgeBaseService } from 'app/main/pages/knowledge-base/knowledge-base.service'; +import { KnowledgeBaseArticleComponent } from 'app/main/pages/knowledge-base/dialogs/article/article.component'; + +@Component({ + selector : 'knowledge-base', + templateUrl : './knowledge-base.component.html', + styleUrls : ['./knowledge-base.component.scss'], + encapsulation: ViewEncapsulation.None +}) +export class KnowledgeBaseComponent implements OnInit, OnDestroy +{ + knowledgeBase: any; + + // Private + private _unsubscribeAll: Subject; + + /** + * Constructor + * + * @param {KnowledgeBaseService} _knowledgeBaseService + * @param {MatDialog} _matDialog + */ + constructor( + private _knowledgeBaseService: KnowledgeBaseService, + private _matDialog: MatDialog + ) + { + // Set the private defaults + this._unsubscribeAll = new Subject(); + } + + // ----------------------------------------------------------------------------------------------------- + // @ Lifecycle hooks + // ----------------------------------------------------------------------------------------------------- + + /** + * On init + */ + ngOnInit(): void + { + this._knowledgeBaseService.onKnowledgeBaseChanged + .pipe(takeUntil(this._unsubscribeAll)) + .subscribe(response => { + this.knowledgeBase = response; + }); + } + + /** + * On destroy + */ + ngOnDestroy(): void + { + // Unsubscribe from all subscriptions + this._unsubscribeAll.next(); + this._unsubscribeAll.complete(); + } + + // ----------------------------------------------------------------------------------------------------- + // @ Public methods + // ----------------------------------------------------------------------------------------------------- + + /** + * Read article + * + * @param article + */ + readArticle(article): void + { + this._matDialog.open(KnowledgeBaseArticleComponent, { + panelClass: 'knowledgebase-article-dialog', + data : {article: article} + }); + } +} diff --git a/src/app/main/pages/maintenance/maintenance.component.ts b/src/app/main/pages/maintenance/maintenance.component.ts new file mode 100644 index 00000000..4e86c78e --- /dev/null +++ b/src/app/main/pages/maintenance/maintenance.component.ts @@ -0,0 +1,38 @@ +import { Component } from '@angular/core'; + +import { FuseConfigService } from '@fuse/services/config.service'; +import { fuseAnimations } from '@fuse/animations'; + +@Component({ + selector : 'maintenance', + templateUrl: './maintenance.component.html', + styleUrls : ['./maintenance.component.scss'], + animations : fuseAnimations +}) +export class MaintenanceComponent +{ + /** + * Constructor + * + * @param {FuseConfigService} _fuseConfigService + */ + constructor( + private _fuseConfigService: FuseConfigService + ) + { + // Configure the layout + this._fuseConfigService.config = { + layout: { + navbar : { + hidden: true + }, + toolbar: { + hidden: true + }, + footer : { + hidden: true + } + } + }; + } +} diff --git a/src/app/main/pages/pages.module.ts b/src/app/main/pages/pages.module.ts new file mode 100644 index 00000000..8cef2f0e --- /dev/null +++ b/src/app/main/pages/pages.module.ts @@ -0,0 +1,72 @@ +import { NgModule } from '@angular/core'; + +import { LoginModule } from 'app/main/pages/authentication/login/login.module'; +import { Login2Module } from 'app/main/pages/authentication/login-2/login-2.module'; +import { RegisterModule } from 'app/main/pages/authentication/register/register.module'; +import { Register2Module } from 'app/main/pages/authentication/register-2/register-2.module'; +import { ForgotPasswordModule } from 'app/main/pages/authentication/forgot-password/forgot-password.module'; +import { ForgotPassword2Module } from 'app/main/pages/authentication/forgot-password-2/forgot-password-2.module'; +import { ResetPasswordModule } from 'app/main/pages/authentication/reset-password/reset-password.module'; +import { ResetPassword2Module } from 'app/main/pages/authentication/reset-password-2/reset-password-2.module'; +import { LockModule } from 'app/main/pages/authentication/lock/lock.module'; +import { MailConfirmModule } from 'app/main/pages/authentication/mail-confirm/mail-confirm.module'; +import { ComingSoonModule } from 'app/main/pages/coming-soon/coming-soon.module'; +import { Error404Module } from 'app/main/pages/errors/404/error-404.module'; +import { Error500Module } from 'app/main/pages/errors/500/error-500.module'; +import { InvoiceModernModule } from 'app/main/pages/invoices/modern/modern.module'; +import { InvoiceCompactModule } from 'app/main/pages/invoices/compact/compact.module'; +import { MaintenanceModule } from 'app/main/pages/maintenance/maintenence.module'; +import { PricingModule } from 'app/main/pages/pricing/pricing.module'; +import { ProfileModule } from 'app/main/pages/profile/profile.module'; +import { SearchModule } from 'app/main/pages/search/search.module'; +import { FaqModule } from 'app/main/pages/faq/faq.module'; +import { KnowledgeBaseModule } from 'app/main/pages/knowledge-base/knowledge-base.module'; + +@NgModule({ + imports: [ + // Authentication + LoginModule, + Login2Module, + RegisterModule, + Register2Module, + ForgotPasswordModule, + ForgotPassword2Module, + ResetPasswordModule, + ResetPassword2Module, + LockModule, + MailConfirmModule, + + // Coming-soon + ComingSoonModule, + + // Errors + Error404Module, + Error500Module, + + // Invoices + InvoiceModernModule, + InvoiceCompactModule, + + // Maintenance + MaintenanceModule, + + // Pricing + PricingModule, + + // Profile + ProfileModule, + + // Search + SearchModule, + + // Faq + FaqModule, + + // Knowledge base + KnowledgeBaseModule + ] +}) +export class PagesModule +{ + +} diff --git a/src/app/main/pages/profile/tabs/about/about.component.ts b/src/app/main/pages/profile/tabs/about/about.component.ts new file mode 100644 index 00000000..f0f2c414 --- /dev/null +++ b/src/app/main/pages/profile/tabs/about/about.component.ts @@ -0,0 +1,59 @@ +import { Component, OnDestroy, OnInit } from '@angular/core'; +import { Subject } from 'rxjs'; +import { takeUntil } from 'rxjs/operators'; + +import { fuseAnimations } from '@fuse/animations'; +import { ProfileService } from 'app/main/pages/profile/profile.service'; + +@Component({ + selector : 'profile-about', + templateUrl: './about.component.html', + styleUrls : ['./about.component.scss'], + animations : fuseAnimations +}) +export class ProfileAboutComponent implements OnInit, OnDestroy +{ + about: any; + + // Private + private _unsubscribeAll: Subject; + + /** + * Constructor + * + * @param {ProfileService} _profileService + */ + constructor( + private _profileService: ProfileService + ) + { + // Set the private defaults + this._unsubscribeAll = new Subject(); + } + + // ----------------------------------------------------------------------------------------------------- + // @ Lifecycle hooks + // ----------------------------------------------------------------------------------------------------- + + /** + * On init + */ + ngOnInit(): void + { + this._profileService.aboutOnChanged + .pipe(takeUntil(this._unsubscribeAll)) + .subscribe(about => { + this.about = about; + }); + } + + /** + * On destroy + */ + ngOnDestroy(): void + { + // Unsubscribe from all subscriptions + this._unsubscribeAll.next(); + this._unsubscribeAll.complete(); + } +} diff --git a/src/app/main/pages/profile/tabs/photos-videos/photos-videos.component.ts b/src/app/main/pages/profile/tabs/photos-videos/photos-videos.component.ts new file mode 100644 index 00000000..c6a62320 --- /dev/null +++ b/src/app/main/pages/profile/tabs/photos-videos/photos-videos.component.ts @@ -0,0 +1,60 @@ +import { Component, OnDestroy, OnInit } from '@angular/core'; + +import { fuseAnimations } from '@fuse/animations'; + +import { ProfileService } from 'app/main/pages/profile/profile.service'; +import { takeUntil } from 'rxjs/operators'; +import { Subject } from 'rxjs'; + +@Component({ + selector : 'profile-photos-videos', + templateUrl: './photos-videos.component.html', + styleUrls : ['./photos-videos.component.scss'], + animations : fuseAnimations +}) +export class ProfilePhotosVideosComponent implements OnInit, OnDestroy +{ + photosVideos: any; + + // Private + private _unsubscribeAll: Subject; + + /** + * Constructor + * + * @param {ProfileService} _profileService + */ + constructor( + private _profileService: ProfileService + ) + { + // Set the private defaults + this._unsubscribeAll = new Subject(); + } + + // ----------------------------------------------------------------------------------------------------- + // @ Lifecycle hooks + // ----------------------------------------------------------------------------------------------------- + + /** + * On init + */ + ngOnInit(): void + { + this._profileService.photosVideosOnChanged + .pipe(takeUntil(this._unsubscribeAll)) + .subscribe(photosVideos => { + this.photosVideos = photosVideos; + }); + } + + /** + * On destroy + */ + ngOnDestroy(): void + { + // Unsubscribe from all subscriptions + this._unsubscribeAll.next(); + this._unsubscribeAll.complete(); + } +} diff --git a/src/app/main/pages/profile/tabs/timeline/timeline.component.ts b/src/app/main/pages/profile/tabs/timeline/timeline.component.ts new file mode 100644 index 00000000..9c905b66 --- /dev/null +++ b/src/app/main/pages/profile/tabs/timeline/timeline.component.ts @@ -0,0 +1,60 @@ +import { Component, OnDestroy, OnInit } from '@angular/core'; + +import { fuseAnimations } from '@fuse/animations'; + +import { ProfileService } from '../../profile.service'; +import { Subject } from 'rxjs'; +import { takeUntil } from 'rxjs/operators'; + +@Component({ + selector : 'profile-timeline', + templateUrl: './timeline.component.html', + styleUrls : ['./timeline.component.scss'], + animations : fuseAnimations +}) +export class ProfileTimelineComponent implements OnInit, OnDestroy +{ + timeline: any; + + // Private + private _unsubscribeAll: Subject; + + /** + * Constructor + * + * @param {ProfileService} _profileService + */ + constructor( + private _profileService: ProfileService + ) + { + // Set the private defaults + this._unsubscribeAll = new Subject(); + } + + // ----------------------------------------------------------------------------------------------------- + // @ Lifecycle hooks + // ----------------------------------------------------------------------------------------------------- + + /** + * On init + */ + ngOnInit(): void + { + this._profileService.timelineOnChanged + .pipe(takeUntil(this._unsubscribeAll)) + .subscribe(timeline => { + this.timeline = timeline; + }); + } + + /** + * On destroy + */ + ngOnDestroy(): void + { + // Unsubscribe from all subscriptions + this._unsubscribeAll.next(); + this._unsubscribeAll.complete(); + } +} diff --git a/src/app/main/pages/search/tabs/classic/classic.component.ts b/src/app/main/pages/search/tabs/classic/classic.component.ts new file mode 100644 index 00000000..eab6fdaf --- /dev/null +++ b/src/app/main/pages/search/tabs/classic/classic.component.ts @@ -0,0 +1,57 @@ +import { Component, OnDestroy, OnInit } from '@angular/core'; +import { Subject } from 'rxjs'; +import { takeUntil } from 'rxjs/operators'; + +import { SearchService } from 'app/main/pages/search/search.service'; + +@Component({ + selector : 'search-classic', + templateUrl: './classic.component.html', + styleUrls : ['./classic.component.scss'] +}) +export class SearchClassicComponent implements OnInit, OnDestroy +{ + classic: any; + + // Private + private _unsubscribeAll: Subject; + + /** + * Constructor + * + * @param {SearchService} _searchService + */ + constructor( + private _searchService: SearchService + ) + { + // Set the private defaults + this._unsubscribeAll = new Subject(); + } + + // ----------------------------------------------------------------------------------------------------- + // @ Lifecycle hooks + // ----------------------------------------------------------------------------------------------------- + + /** + * On init + */ + ngOnInit(): void + { + this._searchService.classicOnChanged + .pipe(takeUntil(this._unsubscribeAll)) + .subscribe(classic => { + this.classic = classic; + }); + } + + /** + * On destroy + */ + ngOnDestroy(): void + { + // Unsubscribe from all subscriptions + this._unsubscribeAll.next(); + this._unsubscribeAll.complete(); + } +} diff --git a/src/app/main/pages/search/tabs/table/table.component.scss b/src/app/main/pages/search/tabs/table/table.component.scss new file mode 100644 index 00000000..ca2a0c07 --- /dev/null +++ b/src/app/main/pages/search/tabs/table/table.component.scss @@ -0,0 +1,5 @@ +@import "src/@fuse/scss/fuse"; + +:host { + +} diff --git a/src/app/main/pages/search/tabs/table/table.component.ts b/src/app/main/pages/search/tabs/table/table.component.ts new file mode 100644 index 00000000..30207d1d --- /dev/null +++ b/src/app/main/pages/search/tabs/table/table.component.ts @@ -0,0 +1,98 @@ +import { Component, OnDestroy, OnInit } from '@angular/core'; +import { DataSource } from '@angular/cdk/collections'; +import { takeUntil } from 'rxjs/operators'; +import { BehaviorSubject, Subject } from 'rxjs'; + +import { SearchService } from 'app/main/pages/search/search.service'; + +@Component({ + selector : 'search-table', + templateUrl: './table.component.html', + styleUrls : ['./table.component.scss'] +}) +export class SearchTableComponent implements OnInit, OnDestroy +{ + table: any; + dataSource: SearchTableDataSource; + displayedColumns: string[]; + + // Private + private _unsubscribeAll: Subject; + + /** + * Constructor + * + * @param {SearchService} _searchService + */ + constructor( + private _searchService: SearchService + ) + { + // Set the defaults + this.displayedColumns = ['name', 'position', 'office', 'salary']; + + // Set the private defaults + this._unsubscribeAll = new Subject(); + } + + // ----------------------------------------------------------------------------------------------------- + // @ Lifecycle hooks + // ----------------------------------------------------------------------------------------------------- + + /** + * On init + */ + ngOnInit(): void + { + this.dataSource = new SearchTableDataSource(this._searchService); + + this._searchService.tableOnChanged + .pipe(takeUntil(this._unsubscribeAll)) + .subscribe(table => { + this.table = table; + }); + } + + /** + * On destroy + */ + ngOnDestroy(): void + { + // Unsubscribe from all subscriptions + this._unsubscribeAll.next(); + this._unsubscribeAll.complete(); + } +} + +export class SearchTableDataSource extends DataSource +{ + /** + * Constructor + * + * @param {SearchService} _searchService + */ + constructor( + private _searchService: SearchService + ) + { + super(); + } + + /** + * Connect + * + * @returns {BehaviorSubject} + */ + connect(): BehaviorSubject + { + return this._searchService.tableOnChanged; + } + + /** + * Disconnect + */ + disconnect(): void + { + + } +} diff --git a/src/app/main/toolbar/toolbar.component.ts b/src/app/main/toolbar/toolbar.component.ts deleted file mode 100644 index 72550420..00000000 --- a/src/app/main/toolbar/toolbar.component.ts +++ /dev/null @@ -1,115 +0,0 @@ -import { Component } from '@angular/core'; -import { NavigationEnd, NavigationStart, Router } from '@angular/router'; -import { TranslateService } from '@ngx-translate/core'; - -import { FuseConfigService } from '@fuse/services/config.service'; -import { FuseSidebarService } from '@fuse/components/sidebar/sidebar.service'; - -import { navigation } from 'app/navigation/navigation'; - -@Component({ - selector : 'fuse-toolbar', - templateUrl: './toolbar.component.html', - styleUrls : ['./toolbar.component.scss'] -}) - -export class FuseToolbarComponent -{ - userStatusOptions: any[]; - languages: any; - selectedLanguage: any; - showLoadingBar: boolean; - horizontalNav: boolean; - noNav: boolean; - navigation: any; - - constructor( - private router: Router, - private fuseConfig: FuseConfigService, - private sidebarService: FuseSidebarService, - private translate: TranslateService - ) - { - this.userStatusOptions = [ - { - 'title': 'Online', - 'icon' : 'icon-checkbox-marked-circle', - 'color': '#4CAF50' - }, - { - 'title': 'Away', - 'icon' : 'icon-clock', - 'color': '#FFC107' - }, - { - 'title': 'Do not Disturb', - 'icon' : 'icon-minus-circle', - 'color': '#F44336' - }, - { - 'title': 'Invisible', - 'icon' : 'icon-checkbox-blank-circle-outline', - 'color': '#BDBDBD' - }, - { - 'title': 'Offline', - 'icon' : 'icon-checkbox-blank-circle-outline', - 'color': '#616161' - } - ]; - - this.languages = [ - { - 'id' : 'en', - 'title': 'English', - 'flag' : 'us' - }, - { - 'id' : 'tr', - 'title': 'Turkish', - 'flag' : 'tr' - } - ]; - - this.selectedLanguage = this.languages[0]; - - router.events.subscribe( - (event) => { - if ( event instanceof NavigationStart ) - { - this.showLoadingBar = true; - } - if ( event instanceof NavigationEnd ) - { - this.showLoadingBar = false; - } - }); - - this.fuseConfig.onConfigChanged.subscribe((settings) => { - this.horizontalNav = settings.layout.navigation === 'top'; - this.noNav = settings.layout.navigation === 'none'; - }); - - this.navigation = navigation; - } - - toggleSidebarOpened(key) - { - this.sidebarService.getSidebar(key).toggleOpen(); - } - - search(value) - { - // Do your search here... - console.log(value); - } - - setLanguage(lang) - { - // Set the selected language for toolbar - this.selectedLanguage = lang; - - // Use the selected language for translations - this.translate.use(lang.id); - } -} diff --git a/src/app/main/ui/colors/colors.component.ts b/src/app/main/ui/colors/colors.component.ts new file mode 100644 index 00000000..f336f69d --- /dev/null +++ b/src/app/main/ui/colors/colors.component.ts @@ -0,0 +1,51 @@ +import { Component, OnInit } from '@angular/core'; + +import { MatColors } from '@fuse/mat-colors'; + +@Component({ + selector : 'colors', + templateUrl: './colors.component.html', + styleUrls : ['./colors.component.scss'] +}) +export class ColorsComponent +{ + colors: {}; + selectedColor: string; + selectedColorDefaultValue: string; + + /** + * Constructor + */ + constructor() + { + // Set the defaults + this.colors = MatColors.all; + this._updateSelectedColor('primary'); + } + + // ----------------------------------------------------------------------------------------------------- + // @ Public methods + // ----------------------------------------------------------------------------------------------------- + + /** + * Select color + * + * @param selected + */ + selectColor(selected): void + { + this._updateSelectedColor(selected.tab.textLabel); + } + + /** + * Update selected color + * + * @param colorName + * @private + */ + private _updateSelectedColor(colorName): void + { + this.selectedColor = colorName; + this.selectedColorDefaultValue = MatColors.getColor(this.selectedColor)[500]; + } +} diff --git a/src/app/main/ui/icons/icons.component.ts b/src/app/main/ui/icons/icons.component.ts new file mode 100644 index 00000000..e289964a --- /dev/null +++ b/src/app/main/ui/icons/icons.component.ts @@ -0,0 +1,81 @@ +import { Component, OnDestroy, OnInit } from '@angular/core'; +import { HttpClient } from '@angular/common/http'; +import { takeUntil } from 'rxjs/operators'; +import { Subject } from 'rxjs'; + +@Component({ + selector : 'icons', + templateUrl: './icons.component.html', + styleUrls : ['./icons.component.scss'] +}) +export class IconsComponent implements OnInit, OnDestroy +{ + icons: string[]; + filteredIcons: string[]; + loading: boolean; + + // Private + private _unsubscribeAll: Subject; + + /** + * Constructor + * + * @param {HttpClient} _httpClient + */ + constructor( + private _httpClient: HttpClient + ) + { + // Set the defaults + this.loading = true; + + // Set the private defaults + this._unsubscribeAll = new Subject(); + } + + // ----------------------------------------------------------------------------------------------------- + // @ Lifecycle hooks + // ----------------------------------------------------------------------------------------------------- + + /** + * On init + */ + ngOnInit(): void + { + this._httpClient.get('api/icons') + .pipe(takeUntil(this._unsubscribeAll)) + .subscribe((icons: any) => { + this.icons = icons; + this.filteredIcons = this.icons; + this.loading = false; + }); + } + + /** + * On destroy + */ + ngOnDestroy(): void + { + // Unsubscribe from all subscriptions + this._unsubscribeAll.next(); + this._unsubscribeAll.complete(); + } + + // ----------------------------------------------------------------------------------------------------- + // @ Public methods + // ----------------------------------------------------------------------------------------------------- + + /** + * Filter icons + * + * @param event + */ + filterIcons(event): void + { + const value = event.target.value; + + this.filteredIcons = this.icons.filter(icon => { + return icon.includes(value); + }); + } +} diff --git a/src/app/main/ui/page-layouts/blank/blank.component.scss b/src/app/main/ui/page-layouts/blank/blank.component.scss new file mode 100644 index 00000000..e69de29b diff --git a/src/app/main/ui/page-layouts/carded/full-width-1/full-width-1.component.scss b/src/app/main/ui/page-layouts/carded/full-width-1/full-width-1.component.scss new file mode 100644 index 00000000..e69de29b diff --git a/src/app/main/ui/page-layouts/carded/full-width-1/full-width-1.component.ts b/src/app/main/ui/page-layouts/carded/full-width-1/full-width-1.component.ts new file mode 100644 index 00000000..5a3e0daf --- /dev/null +++ b/src/app/main/ui/page-layouts/carded/full-width-1/full-width-1.component.ts @@ -0,0 +1,16 @@ +import { Component } from '@angular/core'; + +@Component({ + selector : 'carded-fullwidth-1', + templateUrl: './full-width-1.component.html', + styleUrls : ['./full-width-1.component.scss'] +}) +export class CardedFullWidth1Component +{ + /** + * Constructor + */ + constructor() + { + } +} diff --git a/src/app/main/ui/page-layouts/carded/full-width-2/full-width-2.component.scss b/src/app/main/ui/page-layouts/carded/full-width-2/full-width-2.component.scss new file mode 100644 index 00000000..e69de29b diff --git a/src/app/main/ui/page-layouts/carded/full-width-2/full-width-2.component.ts b/src/app/main/ui/page-layouts/carded/full-width-2/full-width-2.component.ts new file mode 100644 index 00000000..fa38a5db --- /dev/null +++ b/src/app/main/ui/page-layouts/carded/full-width-2/full-width-2.component.ts @@ -0,0 +1,16 @@ +import { Component } from '@angular/core'; + +@Component({ + selector : 'carded-fullwidth-2', + templateUrl: './full-width-2.component.html', + styleUrls : ['./full-width-2.component.scss'] +}) +export class CardedFullWidth2Component +{ + /** + * Constructor + */ + constructor() + { + } +} diff --git a/src/app/main/ui/page-layouts/carded/full-width-tabbed-1/full-width-tabbed-1.component.html b/src/app/main/ui/page-layouts/carded/full-width-tabbed-1/full-width-tabbed-1.component.html new file mode 100644 index 00000000..7b494058 --- /dev/null +++ b/src/app/main/ui/page-layouts/carded/full-width-tabbed-1/full-width-tabbed-1.component.html @@ -0,0 +1,115 @@ +
+ + +
+ + + +
+ + +
+

Full width with tabs and content scroll

+
+ + + +
+ + +
+ + + + +
+ + + +
+
+ + +
+ + + +
+
+ + +
+ + + +
+
+ + +
+ + + +
+
+ + +
+ + + +
+
+ + +
+ + + +
+
+ + +
+ + + +
+
+ + +
+ + + +
+
+ + +
+ + + +
+
+ + +
+ + + +
+
+ +
+ +
+ + +
+ + +
+ + +
diff --git a/src/app/main/ui/page-layouts/carded/full-width-tabbed-1/full-width-tabbed-1.component.scss b/src/app/main/ui/page-layouts/carded/full-width-tabbed-1/full-width-tabbed-1.component.scss new file mode 100644 index 00000000..e69de29b diff --git a/src/app/main/ui/page-layouts/carded/full-width-tabbed-1/full-width-tabbed-1.component.ts b/src/app/main/ui/page-layouts/carded/full-width-tabbed-1/full-width-tabbed-1.component.ts new file mode 100644 index 00000000..2da39a05 --- /dev/null +++ b/src/app/main/ui/page-layouts/carded/full-width-tabbed-1/full-width-tabbed-1.component.ts @@ -0,0 +1,16 @@ +import { Component } from '@angular/core'; + +@Component({ + selector : 'carded-fullwidth-tabbed-1', + templateUrl: './full-width-tabbed-1.component.html', + styleUrls : ['./full-width-tabbed-1.component.scss'] +}) +export class CardedFullWidthTabbed1Component +{ + /** + * Constructor + */ + constructor() + { + } +} diff --git a/src/app/main/ui/page-layouts/carded/full-width-tabbed-2/full-width-tabbed-2.component.html b/src/app/main/ui/page-layouts/carded/full-width-tabbed-2/full-width-tabbed-2.component.html new file mode 100644 index 00000000..573e0e63 --- /dev/null +++ b/src/app/main/ui/page-layouts/carded/full-width-tabbed-2/full-width-tabbed-2.component.html @@ -0,0 +1,115 @@ +
+ + +
+ + + +
+ + +
+

Full width with tabs and inner scroll

+
+ + + +
+ + +
+ + + + +
+ + + +
+
+ + +
+ + + +
+
+ + +
+ + + +
+
+ + +
+ + + +
+
+ + +
+ + + +
+
+ + +
+ + + +
+
+ + +
+ + + +
+
+ + +
+ + + +
+
+ + +
+ + + +
+
+ + +
+ + + +
+
+ +
+ +
+ + +
+ + +
+ + +
diff --git a/src/app/main/ui/page-layouts/carded/full-width-tabbed-2/full-width-tabbed-2.component.scss b/src/app/main/ui/page-layouts/carded/full-width-tabbed-2/full-width-tabbed-2.component.scss new file mode 100644 index 00000000..e69de29b diff --git a/src/app/main/ui/page-layouts/carded/full-width-tabbed-2/full-width-tabbed-2.component.ts b/src/app/main/ui/page-layouts/carded/full-width-tabbed-2/full-width-tabbed-2.component.ts new file mode 100644 index 00000000..dc746bb4 --- /dev/null +++ b/src/app/main/ui/page-layouts/carded/full-width-tabbed-2/full-width-tabbed-2.component.ts @@ -0,0 +1,16 @@ +import { Component } from '@angular/core'; + +@Component({ + selector : 'carded-fullwidth-tabbed-2', + templateUrl: './full-width-tabbed-2.component.html', + styleUrls : ['./full-width-tabbed-2.component.scss'] +}) +export class CardedFullWidthTabbed2Component +{ + /** + * Constructor + */ + constructor() + { + } +} diff --git a/src/app/main/ui/page-layouts/carded/left-sidebar-1/left-sidebar-1.component.html b/src/app/main/ui/page-layouts/carded/left-sidebar-1/left-sidebar-1.component.html new file mode 100644 index 00000000..9a21b456 --- /dev/null +++ b/src/app/main/ui/page-layouts/carded/left-sidebar-1/left-sidebar-1.component.html @@ -0,0 +1,62 @@ + diff --git a/src/app/main/ui/page-layouts/carded/left-sidebar-1/left-sidebar-1.component.scss b/src/app/main/ui/page-layouts/carded/left-sidebar-1/left-sidebar-1.component.scss new file mode 100644 index 00000000..e69de29b diff --git a/src/app/main/ui/page-layouts/carded/left-sidebar-1/left-sidebar-1.component.ts b/src/app/main/ui/page-layouts/carded/left-sidebar-1/left-sidebar-1.component.ts new file mode 100644 index 00000000..a803f877 --- /dev/null +++ b/src/app/main/ui/page-layouts/carded/left-sidebar-1/left-sidebar-1.component.ts @@ -0,0 +1,36 @@ +import { Component } from '@angular/core'; + +import { FuseSidebarService } from '@fuse/components/sidebar/sidebar.service'; + +@Component({ + selector : 'carded-left-sidebar-1', + templateUrl: './left-sidebar-1.component.html', + styleUrls : ['./left-sidebar-1.component.scss'] +}) +export class CardedLeftSidebar1Component +{ + /** + * Constructor + * + * @param {FuseSidebarService} _fuseSidebarService + */ + constructor( + private _fuseSidebarService: FuseSidebarService + ) + { + } + + // ----------------------------------------------------------------------------------------------------- + // @ Public methods + // ----------------------------------------------------------------------------------------------------- + + /** + * Toggle sidebar + * + * @param name + */ + toggleSidebar(name): void + { + this._fuseSidebarService.getSidebar(name).toggleOpen(); + } +} diff --git a/src/app/main/ui/page-layouts/carded/left-sidebar-2/left-sidebar-2.component.html b/src/app/main/ui/page-layouts/carded/left-sidebar-2/left-sidebar-2.component.html new file mode 100644 index 00000000..c046980f --- /dev/null +++ b/src/app/main/ui/page-layouts/carded/left-sidebar-2/left-sidebar-2.component.html @@ -0,0 +1,62 @@ + diff --git a/src/app/main/ui/page-layouts/carded/left-sidebar-2/left-sidebar-2.component.scss b/src/app/main/ui/page-layouts/carded/left-sidebar-2/left-sidebar-2.component.scss new file mode 100644 index 00000000..e69de29b diff --git a/src/app/main/ui/page-layouts/carded/left-sidebar-2/left-sidebar-2.component.ts b/src/app/main/ui/page-layouts/carded/left-sidebar-2/left-sidebar-2.component.ts new file mode 100644 index 00000000..1dac72ce --- /dev/null +++ b/src/app/main/ui/page-layouts/carded/left-sidebar-2/left-sidebar-2.component.ts @@ -0,0 +1,36 @@ +import { Component } from '@angular/core'; + +import { FuseSidebarService } from '@fuse/components/sidebar/sidebar.service'; + +@Component({ + selector : 'carded-left-sidebar-2', + templateUrl: './left-sidebar-2.component.html', + styleUrls : ['./left-sidebar-2.component.scss'] +}) +export class CardedLeftSidebar2Component +{ + /** + * Constructor + * + * @param {FuseSidebarService} _fuseSidebarService + */ + constructor( + private _fuseSidebarService: FuseSidebarService + ) + { + } + + // ----------------------------------------------------------------------------------------------------- + // @ Public methods + // ----------------------------------------------------------------------------------------------------- + + /** + * Toggle sidebar + * + * @param name + */ + toggleSidebar(name): void + { + this._fuseSidebarService.getSidebar(name).toggleOpen(); + } +} diff --git a/src/app/main/ui/page-layouts/carded/left-sidebar-tabbed-1/left-sidebar-tabbed-1.component.html b/src/app/main/ui/page-layouts/carded/left-sidebar-tabbed-1/left-sidebar-tabbed-1.component.html new file mode 100644 index 00000000..671c54a6 --- /dev/null +++ b/src/app/main/ui/page-layouts/carded/left-sidebar-tabbed-1/left-sidebar-tabbed-1.component.html @@ -0,0 +1,144 @@ + diff --git a/src/app/main/ui/page-layouts/carded/left-sidebar-tabbed-1/left-sidebar-tabbed-1.component.scss b/src/app/main/ui/page-layouts/carded/left-sidebar-tabbed-1/left-sidebar-tabbed-1.component.scss new file mode 100644 index 00000000..e69de29b diff --git a/src/app/main/ui/page-layouts/carded/left-sidebar-tabbed-1/left-sidebar-tabbed-1.component.ts b/src/app/main/ui/page-layouts/carded/left-sidebar-tabbed-1/left-sidebar-tabbed-1.component.ts new file mode 100644 index 00000000..db5902c6 --- /dev/null +++ b/src/app/main/ui/page-layouts/carded/left-sidebar-tabbed-1/left-sidebar-tabbed-1.component.ts @@ -0,0 +1,36 @@ +import { Component } from '@angular/core'; + +import { FuseSidebarService } from '@fuse/components/sidebar/sidebar.service'; + +@Component({ + selector : 'carded-left-sidebar-tabbed-1', + templateUrl: './left-sidebar-tabbed-1.component.html', + styleUrls : ['./left-sidebar-tabbed-1.component.scss'] +}) +export class CardedLeftSidebarTabbed1Component +{ + /** + * Constructor + * + * @param {FuseSidebarService} _fuseSidebarService + */ + constructor( + private _fuseSidebarService: FuseSidebarService + ) + { + } + + // ----------------------------------------------------------------------------------------------------- + // @ Public methods + // ----------------------------------------------------------------------------------------------------- + + /** + * Toggle sidebar + * + * @param name + */ + toggleSidebar(name): void + { + this._fuseSidebarService.getSidebar(name).toggleOpen(); + } +} diff --git a/src/app/main/ui/page-layouts/carded/left-sidebar-tabbed-2/left-sidebar-tabbed-2.component.html b/src/app/main/ui/page-layouts/carded/left-sidebar-tabbed-2/left-sidebar-tabbed-2.component.html new file mode 100644 index 00000000..5c138941 --- /dev/null +++ b/src/app/main/ui/page-layouts/carded/left-sidebar-tabbed-2/left-sidebar-tabbed-2.component.html @@ -0,0 +1,144 @@ + diff --git a/src/app/main/ui/page-layouts/carded/left-sidebar-tabbed-2/left-sidebar-tabbed-2.component.scss b/src/app/main/ui/page-layouts/carded/left-sidebar-tabbed-2/left-sidebar-tabbed-2.component.scss new file mode 100644 index 00000000..e69de29b diff --git a/src/app/main/ui/page-layouts/carded/left-sidebar-tabbed-2/left-sidebar-tabbed-2.component.ts b/src/app/main/ui/page-layouts/carded/left-sidebar-tabbed-2/left-sidebar-tabbed-2.component.ts new file mode 100644 index 00000000..8d4d7c2c --- /dev/null +++ b/src/app/main/ui/page-layouts/carded/left-sidebar-tabbed-2/left-sidebar-tabbed-2.component.ts @@ -0,0 +1,36 @@ +import { Component } from '@angular/core'; + +import { FuseSidebarService } from '@fuse/components/sidebar/sidebar.service'; + +@Component({ + selector : 'carded-left-sidebar-tabbed-2', + templateUrl: './left-sidebar-tabbed-2.component.html', + styleUrls : ['./left-sidebar-tabbed-2.component.scss'] +}) +export class CardedLeftSidebarTabbed2Component +{ + /** + * Constructor + * + * @param {FuseSidebarService} _fuseSidebarService + */ + constructor( + private _fuseSidebarService: FuseSidebarService + ) + { + } + + // ----------------------------------------------------------------------------------------------------- + // @ Public methods + // ----------------------------------------------------------------------------------------------------- + + /** + * Toggle sidebar + * + * @param name + */ + toggleSidebar(name): void + { + this._fuseSidebarService.getSidebar(name).toggleOpen(); + } +} diff --git a/src/app/main/ui/page-layouts/carded/right-sidebar-1/right-sidebar-1.component.html b/src/app/main/ui/page-layouts/carded/right-sidebar-1/right-sidebar-1.component.html new file mode 100644 index 00000000..4cb2b652 --- /dev/null +++ b/src/app/main/ui/page-layouts/carded/right-sidebar-1/right-sidebar-1.component.html @@ -0,0 +1,62 @@ + diff --git a/src/app/main/ui/page-layouts/carded/right-sidebar-1/right-sidebar-1.component.scss b/src/app/main/ui/page-layouts/carded/right-sidebar-1/right-sidebar-1.component.scss new file mode 100644 index 00000000..e69de29b diff --git a/src/app/main/ui/page-layouts/carded/right-sidebar-1/right-sidebar-1.component.ts b/src/app/main/ui/page-layouts/carded/right-sidebar-1/right-sidebar-1.component.ts new file mode 100644 index 00000000..c3b9e890 --- /dev/null +++ b/src/app/main/ui/page-layouts/carded/right-sidebar-1/right-sidebar-1.component.ts @@ -0,0 +1,36 @@ +import { Component } from '@angular/core'; + +import { FuseSidebarService } from '@fuse/components/sidebar/sidebar.service'; + +@Component({ + selector : 'carded-right-sidebar-1', + templateUrl: './right-sidebar-1.component.html', + styleUrls : ['./right-sidebar-1.component.scss'] +}) +export class CardedRightSidebar1Component +{ + /** + * Constructor + * + * @param {FuseSidebarService} _fuseSidebarService + */ + constructor( + private _fuseSidebarService: FuseSidebarService + ) + { + } + + // ----------------------------------------------------------------------------------------------------- + // @ Public methods + // ----------------------------------------------------------------------------------------------------- + + /** + * Toggle sidebar + * + * @param name + */ + toggleSidebar(name): void + { + this._fuseSidebarService.getSidebar(name).toggleOpen(); + } +} diff --git a/src/app/main/ui/page-layouts/carded/right-sidebar-2/right-sidebar-2.component.html b/src/app/main/ui/page-layouts/carded/right-sidebar-2/right-sidebar-2.component.html new file mode 100644 index 00000000..57fbf33d --- /dev/null +++ b/src/app/main/ui/page-layouts/carded/right-sidebar-2/right-sidebar-2.component.html @@ -0,0 +1,62 @@ + diff --git a/src/app/main/ui/page-layouts/carded/right-sidebar-2/right-sidebar-2.component.scss b/src/app/main/ui/page-layouts/carded/right-sidebar-2/right-sidebar-2.component.scss new file mode 100644 index 00000000..e69de29b diff --git a/src/app/main/ui/page-layouts/carded/right-sidebar-2/right-sidebar-2.component.ts b/src/app/main/ui/page-layouts/carded/right-sidebar-2/right-sidebar-2.component.ts new file mode 100644 index 00000000..c41c15f2 --- /dev/null +++ b/src/app/main/ui/page-layouts/carded/right-sidebar-2/right-sidebar-2.component.ts @@ -0,0 +1,36 @@ +import { Component } from '@angular/core'; + +import { FuseSidebarService } from '@fuse/components/sidebar/sidebar.service'; + +@Component({ + selector : 'carded-right-sidebar-2', + templateUrl: './right-sidebar-2.component.html', + styleUrls : ['./right-sidebar-2.component.scss'] +}) +export class CardedRightSidebar2Component +{ + /** + * Constructor + * + * @param {FuseSidebarService} _fuseSidebarService + */ + constructor( + private _fuseSidebarService: FuseSidebarService + ) + { + } + + // ----------------------------------------------------------------------------------------------------- + // @ Public methods + // ----------------------------------------------------------------------------------------------------- + + /** + * Toggle sidebar + * + * @param name + */ + toggleSidebar(name): void + { + this._fuseSidebarService.getSidebar(name).toggleOpen(); + } +} diff --git a/src/app/main/ui/page-layouts/carded/right-sidebar-tabbed-1/right-sidebar-tabbed-1.component.html b/src/app/main/ui/page-layouts/carded/right-sidebar-tabbed-1/right-sidebar-tabbed-1.component.html new file mode 100644 index 00000000..3c67bed4 --- /dev/null +++ b/src/app/main/ui/page-layouts/carded/right-sidebar-tabbed-1/right-sidebar-tabbed-1.component.html @@ -0,0 +1,144 @@ + diff --git a/src/app/main/ui/page-layouts/carded/right-sidebar-tabbed-1/right-sidebar-tabbed-1.component.scss b/src/app/main/ui/page-layouts/carded/right-sidebar-tabbed-1/right-sidebar-tabbed-1.component.scss new file mode 100644 index 00000000..e69de29b diff --git a/src/app/main/ui/page-layouts/carded/right-sidebar-tabbed-1/right-sidebar-tabbed-1.component.ts b/src/app/main/ui/page-layouts/carded/right-sidebar-tabbed-1/right-sidebar-tabbed-1.component.ts new file mode 100644 index 00000000..2cb92bd5 --- /dev/null +++ b/src/app/main/ui/page-layouts/carded/right-sidebar-tabbed-1/right-sidebar-tabbed-1.component.ts @@ -0,0 +1,36 @@ +import { Component } from '@angular/core'; + +import { FuseSidebarService } from '@fuse/components/sidebar/sidebar.service'; + +@Component({ + selector : 'carded-right-sidebar-tabbed-1', + templateUrl: './right-sidebar-tabbed-1.component.html', + styleUrls : ['./right-sidebar-tabbed-1.component.scss'] +}) +export class CardedRightSidebarTabbed1Component +{ + /** + * Constructor + * + * @param {FuseSidebarService} _fuseSidebarService + */ + constructor( + private _fuseSidebarService: FuseSidebarService + ) + { + } + + // ----------------------------------------------------------------------------------------------------- + // @ Public methods + // ----------------------------------------------------------------------------------------------------- + + /** + * Toggle sidebar + * + * @param name + */ + toggleSidebar(name): void + { + this._fuseSidebarService.getSidebar(name).toggleOpen(); + } +} diff --git a/src/app/main/ui/page-layouts/carded/right-sidebar-tabbed-2/right-sidebar-tabbed-2.component.html b/src/app/main/ui/page-layouts/carded/right-sidebar-tabbed-2/right-sidebar-tabbed-2.component.html new file mode 100644 index 00000000..9de17b71 --- /dev/null +++ b/src/app/main/ui/page-layouts/carded/right-sidebar-tabbed-2/right-sidebar-tabbed-2.component.html @@ -0,0 +1,144 @@ + diff --git a/src/app/main/ui/page-layouts/carded/right-sidebar-tabbed-2/right-sidebar-tabbed-2.component.scss b/src/app/main/ui/page-layouts/carded/right-sidebar-tabbed-2/right-sidebar-tabbed-2.component.scss new file mode 100644 index 00000000..e69de29b diff --git a/src/app/main/ui/page-layouts/carded/right-sidebar-tabbed-2/right-sidebar-tabbed-2.component.ts b/src/app/main/ui/page-layouts/carded/right-sidebar-tabbed-2/right-sidebar-tabbed-2.component.ts new file mode 100644 index 00000000..e564e4e8 --- /dev/null +++ b/src/app/main/ui/page-layouts/carded/right-sidebar-tabbed-2/right-sidebar-tabbed-2.component.ts @@ -0,0 +1,36 @@ +import { Component } from '@angular/core'; + +import { FuseSidebarService } from '@fuse/components/sidebar/sidebar.service'; + +@Component({ + selector : 'carded-right-sidebar-tabbed-2', + templateUrl: './right-sidebar-tabbed-2.component.html', + styleUrls : ['./right-sidebar-tabbed-2.component.scss'] +}) +export class CardedRightSidebarTabbed2Component +{ + /** + * Constructor + * + * @param {FuseSidebarService} _fuseSidebarService + */ + constructor( + private _fuseSidebarService: FuseSidebarService + ) + { + } + + // ----------------------------------------------------------------------------------------------------- + // @ Public methods + // ----------------------------------------------------------------------------------------------------- + + /** + * Toggle sidebar + * + * @param name + */ + toggleSidebar(name): void + { + this._fuseSidebarService.getSidebar(name).toggleOpen(); + } +} diff --git a/src/app/main/ui/page-layouts/page-layouts.module.ts b/src/app/main/ui/page-layouts/page-layouts.module.ts new file mode 100644 index 00000000..9c21e745 --- /dev/null +++ b/src/app/main/ui/page-layouts/page-layouts.module.ts @@ -0,0 +1,172 @@ +import { NgModule } from '@angular/core'; +import { RouterModule, Routes } from '@angular/router'; +import { MatButtonModule, MatIconModule, MatTabsModule } from '@angular/material'; + +import { FuseSharedModule } from '@fuse/shared.module'; +import { FuseDemoModule } from '@fuse/components/demo/demo.module'; + +import { CardedFullWidth1Component } from 'app/main/ui/page-layouts/carded/full-width-1/full-width-1.component'; +import { CardedFullWidth2Component } from 'app/main/ui/page-layouts/carded/full-width-2/full-width-2.component'; +import { CardedFullWidthTabbed1Component } from 'app/main/ui/page-layouts/carded/full-width-tabbed-1/full-width-tabbed-1.component'; +import { CardedFullWidthTabbed2Component } from 'app/main/ui/page-layouts/carded/full-width-tabbed-2/full-width-tabbed-2.component'; +import { CardedLeftSidebar1Component } from 'app/main/ui/page-layouts/carded/left-sidebar-1/left-sidebar-1.component'; +import { CardedLeftSidebar2Component } from 'app/main/ui/page-layouts/carded/left-sidebar-2/left-sidebar-2.component'; +import { CardedLeftSidebarTabbed1Component } from 'app/main/ui/page-layouts/carded/left-sidebar-tabbed-1/left-sidebar-tabbed-1.component'; +import { CardedLeftSidebarTabbed2Component } from 'app/main/ui/page-layouts/carded/left-sidebar-tabbed-2/left-sidebar-tabbed-2.component'; +import { CardedRightSidebar1Component } from 'app/main/ui/page-layouts/carded/right-sidebar-1/right-sidebar-1.component'; +import { CardedRightSidebar2Component } from 'app/main/ui/page-layouts/carded/right-sidebar-2/right-sidebar-2.component'; +import { CardedRightSidebarTabbed1Component } from 'app/main/ui/page-layouts/carded/right-sidebar-tabbed-1/right-sidebar-tabbed-1.component'; +import { CardedRightSidebarTabbed2Component } from 'app/main/ui/page-layouts/carded/right-sidebar-tabbed-2/right-sidebar-tabbed-2.component'; +import { SimpleFullWidth1Component } from 'app/main/ui/page-layouts/simple/full-width-1/full-width-1.component'; +import { SimpleFullWidthTabbed1Component } from 'app/main/ui/page-layouts/simple/full-width-tabbed-1/full-width-tabbed-1.component'; +import { SimpleLeftSidebar1Component } from 'app/main/ui/page-layouts/simple/left-sidebar-1/left-sidebar-1.component'; +import { SimpleLeftSidebar2Component } from 'app/main/ui/page-layouts/simple/left-sidebar-2/left-sidebar-2.component'; +import { SimpleLeftSidebar3Component } from 'app/main/ui/page-layouts/simple/left-sidebar-3/left-sidebar-3.component'; +import { SimpleLeftSidebar4Component } from 'app/main/ui/page-layouts/simple/left-sidebar-4/left-sidebar-4.component'; +import { SimpleRightSidebar1Component } from 'app/main/ui/page-layouts/simple/right-sidebar-1/right-sidebar-1.component'; +import { SimpleRightSidebar2Component } from 'app/main/ui/page-layouts/simple/right-sidebar-2/right-sidebar-2.component'; +import { SimpleRightSidebar3Component } from 'app/main/ui/page-layouts/simple/right-sidebar-3/right-sidebar-3.component'; +import { SimpleRightSidebar4Component } from 'app/main/ui/page-layouts/simple/right-sidebar-4/right-sidebar-4.component'; +import { BlankComponent } from 'app/main/ui/page-layouts/blank/blank.component'; + +import { FuseSidebarModule } from '@fuse/components'; + +const routes: Routes = [ + // Carded + { + path : 'page-layouts/carded/full-width-1', + component: CardedFullWidth1Component + }, + { + path : 'page-layouts/carded/full-width-2', + component: CardedFullWidth2Component + }, + { + path : 'page-layouts/carded/full-width-tabbed-1', + component: CardedFullWidthTabbed1Component + }, + { + path : 'page-layouts/carded/full-width-tabbed-2', + component: CardedFullWidthTabbed2Component + }, + { + path : 'page-layouts/carded/left-sidebar-1', + component: CardedLeftSidebar1Component + }, + { + path : 'page-layouts/carded/left-sidebar-tabbed-1', + component: CardedLeftSidebarTabbed1Component + }, + { + path : 'page-layouts/carded/left-sidebar-2', + component: CardedLeftSidebar2Component + }, + { + path : 'page-layouts/carded/left-sidebar-tabbed-2', + component: CardedLeftSidebarTabbed2Component + }, + { + path : 'page-layouts/carded/right-sidebar-1', + component: CardedRightSidebar1Component + }, + { + path : 'page-layouts/carded/right-sidebar-tabbed-1', + component: CardedRightSidebarTabbed1Component + }, + { + path : 'page-layouts/carded/right-sidebar-2', + component: CardedRightSidebar2Component + }, + { + path : 'page-layouts/carded/right-sidebar-tabbed-2', + component: CardedRightSidebarTabbed2Component + }, + // Simple + { + path : 'page-layouts/simple/full-width-1', + component: SimpleFullWidth1Component + }, + { + path : 'page-layouts/simple/full-width-tabbed-1', + component: SimpleFullWidthTabbed1Component + }, + { + path : 'page-layouts/simple/left-sidebar-1', + component: SimpleLeftSidebar1Component + }, + { + path : 'page-layouts/simple/left-sidebar-2', + component: SimpleLeftSidebar2Component + }, + { + path : 'page-layouts/simple/left-sidebar-3', + component: SimpleLeftSidebar3Component + }, + { + path : 'page-layouts/simple/left-sidebar-4', + component: SimpleLeftSidebar4Component + }, + { + path : 'page-layouts/simple/right-sidebar-1', + component: SimpleRightSidebar1Component + }, + { + path : 'page-layouts/simple/right-sidebar-2', + component: SimpleRightSidebar2Component + }, + { + path : 'page-layouts/simple/right-sidebar-3', + component: SimpleRightSidebar3Component + }, + { + path : 'page-layouts/simple/right-sidebar-4', + component: SimpleRightSidebar4Component + }, + // Blank + { + path : 'page-layouts/blank', + component: BlankComponent + } +]; + +@NgModule({ + declarations: [ + CardedFullWidth1Component, + CardedFullWidth2Component, + CardedFullWidthTabbed1Component, + CardedFullWidthTabbed2Component, + CardedLeftSidebar1Component, + CardedLeftSidebar2Component, + CardedLeftSidebarTabbed1Component, + CardedLeftSidebarTabbed2Component, + CardedRightSidebar1Component, + CardedRightSidebar2Component, + CardedRightSidebarTabbed1Component, + CardedRightSidebarTabbed2Component, + SimpleFullWidth1Component, + SimpleFullWidthTabbed1Component, + SimpleLeftSidebar1Component, + SimpleLeftSidebar2Component, + SimpleLeftSidebar3Component, + SimpleLeftSidebar4Component, + SimpleRightSidebar1Component, + SimpleRightSidebar2Component, + SimpleRightSidebar3Component, + SimpleRightSidebar4Component, + BlankComponent + ], + imports : [ + RouterModule.forChild(routes), + + MatButtonModule, + MatIconModule, + MatTabsModule, + + FuseSidebarModule, + FuseSharedModule, + FuseDemoModule + ] +}) +export class UIPageLayoutsModule +{ +} diff --git a/src/app/main/ui/page-layouts/simple/full-width-1/full-width-1.component.scss b/src/app/main/ui/page-layouts/simple/full-width-1/full-width-1.component.scss new file mode 100644 index 00000000..e69de29b diff --git a/src/app/main/ui/page-layouts/simple/full-width-1/full-width-1.component.ts b/src/app/main/ui/page-layouts/simple/full-width-1/full-width-1.component.ts new file mode 100644 index 00000000..74e45bb1 --- /dev/null +++ b/src/app/main/ui/page-layouts/simple/full-width-1/full-width-1.component.ts @@ -0,0 +1,16 @@ +import { Component } from '@angular/core'; + +@Component({ + selector : 'simple-fullwidth-1', + templateUrl: './full-width-1.component.html', + styleUrls : ['./full-width-1.component.scss'] +}) +export class SimpleFullWidth1Component +{ + /** + * Constructor + */ + constructor() + { + } +} diff --git a/src/app/main/ui/page-layouts/simple/full-width-tabbed-1/full-width-tabbed-1.component.scss b/src/app/main/ui/page-layouts/simple/full-width-tabbed-1/full-width-tabbed-1.component.scss new file mode 100644 index 00000000..e69de29b diff --git a/src/app/main/ui/page-layouts/simple/full-width-tabbed-1/full-width-tabbed-1.component.ts b/src/app/main/ui/page-layouts/simple/full-width-tabbed-1/full-width-tabbed-1.component.ts new file mode 100644 index 00000000..929abb3e --- /dev/null +++ b/src/app/main/ui/page-layouts/simple/full-width-tabbed-1/full-width-tabbed-1.component.ts @@ -0,0 +1,17 @@ +import { Component } from '@angular/core'; + +@Component({ + selector : 'simple-full-width-tabbed-1', + templateUrl: './full-width-tabbed-1.component.html', + styleUrls : ['./full-width-tabbed-1.component.scss'] +}) +export class SimpleFullWidthTabbed1Component +{ + /** + * Constructor + */ + constructor() + { + } + +} diff --git a/src/app/main/ui/page-layouts/simple/left-sidebar-1/left-sidebar-1.component.html b/src/app/main/ui/page-layouts/simple/left-sidebar-1/left-sidebar-1.component.html new file mode 100644 index 00000000..df67aba7 --- /dev/null +++ b/src/app/main/ui/page-layouts/simple/left-sidebar-1/left-sidebar-1.component.html @@ -0,0 +1,40 @@ + diff --git a/src/app/main/ui/page-layouts/simple/left-sidebar-1/left-sidebar-1.component.scss b/src/app/main/ui/page-layouts/simple/left-sidebar-1/left-sidebar-1.component.scss new file mode 100644 index 00000000..e69de29b diff --git a/src/app/main/ui/page-layouts/simple/left-sidebar-1/left-sidebar-1.component.ts b/src/app/main/ui/page-layouts/simple/left-sidebar-1/left-sidebar-1.component.ts new file mode 100644 index 00000000..72b8a444 --- /dev/null +++ b/src/app/main/ui/page-layouts/simple/left-sidebar-1/left-sidebar-1.component.ts @@ -0,0 +1,36 @@ +import { Component } from '@angular/core'; + +import { FuseSidebarService } from '@fuse/components/sidebar/sidebar.service'; + +@Component({ + selector : 'simple-left-sidebar-1', + templateUrl: './left-sidebar-1.component.html', + styleUrls : ['./left-sidebar-1.component.scss'] +}) +export class SimpleLeftSidebar1Component +{ + /** + * Constructor + * + * @param {FuseSidebarService} _fuseSidebarService + */ + constructor( + private _fuseSidebarService: FuseSidebarService + ) + { + } + + // ----------------------------------------------------------------------------------------------------- + // @ Public methods + // ----------------------------------------------------------------------------------------------------- + + /** + * Toggle sidebar + * + * @param name + */ + toggleSidebar(name): void + { + this._fuseSidebarService.getSidebar(name).toggleOpen(); + } +} diff --git a/src/app/main/ui/page-layouts/simple/left-sidebar-2/left-sidebar-2.component.html b/src/app/main/ui/page-layouts/simple/left-sidebar-2/left-sidebar-2.component.html new file mode 100644 index 00000000..976cd2f9 --- /dev/null +++ b/src/app/main/ui/page-layouts/simple/left-sidebar-2/left-sidebar-2.component.html @@ -0,0 +1,40 @@ + diff --git a/src/app/main/ui/page-layouts/simple/left-sidebar-2/left-sidebar-2.component.scss b/src/app/main/ui/page-layouts/simple/left-sidebar-2/left-sidebar-2.component.scss new file mode 100644 index 00000000..e69de29b diff --git a/src/app/main/ui/page-layouts/simple/left-sidebar-2/left-sidebar-2.component.ts b/src/app/main/ui/page-layouts/simple/left-sidebar-2/left-sidebar-2.component.ts new file mode 100644 index 00000000..30b30671 --- /dev/null +++ b/src/app/main/ui/page-layouts/simple/left-sidebar-2/left-sidebar-2.component.ts @@ -0,0 +1,36 @@ +import { Component } from '@angular/core'; + +import { FuseSidebarService } from '@fuse/components/sidebar/sidebar.service'; + +@Component({ + selector : 'simple-left-sidebar-2', + templateUrl: './left-sidebar-2.component.html', + styleUrls : ['./left-sidebar-2.component.scss'] +}) +export class SimpleLeftSidebar2Component +{ + /** + * Constructor + * + * @param {FuseSidebarService} _fuseSidebarService + */ + constructor( + private _fuseSidebarService: FuseSidebarService + ) + { + } + + // ----------------------------------------------------------------------------------------------------- + // @ Public methods + // ----------------------------------------------------------------------------------------------------- + + /** + * Toggle sidebar + * + * @param name + */ + toggleSidebar(name): void + { + this._fuseSidebarService.getSidebar(name).toggleOpen(); + } +} diff --git a/src/app/main/ui/page-layouts/simple/left-sidebar-3/left-sidebar-3.component.html b/src/app/main/ui/page-layouts/simple/left-sidebar-3/left-sidebar-3.component.html new file mode 100644 index 00000000..ba0b8580 --- /dev/null +++ b/src/app/main/ui/page-layouts/simple/left-sidebar-3/left-sidebar-3.component.html @@ -0,0 +1,48 @@ + diff --git a/src/app/main/ui/page-layouts/simple/left-sidebar-3/left-sidebar-3.component.scss b/src/app/main/ui/page-layouts/simple/left-sidebar-3/left-sidebar-3.component.scss new file mode 100644 index 00000000..e69de29b diff --git a/src/app/main/ui/page-layouts/simple/left-sidebar-3/left-sidebar-3.component.ts b/src/app/main/ui/page-layouts/simple/left-sidebar-3/left-sidebar-3.component.ts new file mode 100644 index 00000000..145c341a --- /dev/null +++ b/src/app/main/ui/page-layouts/simple/left-sidebar-3/left-sidebar-3.component.ts @@ -0,0 +1,36 @@ +import { Component } from '@angular/core'; + +import { FuseSidebarService } from '@fuse/components/sidebar/sidebar.service'; + +@Component({ + selector : 'simple-left-sidebar-4', + templateUrl: './left-sidebar-3.component.html', + styleUrls : ['./left-sidebar-3.component.scss'] +}) +export class SimpleLeftSidebar3Component +{ + /** + * Constructor + * + * @param {FuseSidebarService} _fuseSidebarService + */ + constructor( + private _fuseSidebarService: FuseSidebarService + ) + { + } + + // ----------------------------------------------------------------------------------------------------- + // @ Public methods + // ----------------------------------------------------------------------------------------------------- + + /** + * Toggle sidebar + * + * @param name + */ + toggleSidebar(name): void + { + this._fuseSidebarService.getSidebar(name).toggleOpen(); + } +} diff --git a/src/app/main/ui/page-layouts/simple/left-sidebar-4/left-sidebar-4.component.html b/src/app/main/ui/page-layouts/simple/left-sidebar-4/left-sidebar-4.component.html new file mode 100644 index 00000000..52596e3e --- /dev/null +++ b/src/app/main/ui/page-layouts/simple/left-sidebar-4/left-sidebar-4.component.html @@ -0,0 +1,48 @@ + diff --git a/src/app/main/ui/page-layouts/simple/left-sidebar-4/left-sidebar-4.component.scss b/src/app/main/ui/page-layouts/simple/left-sidebar-4/left-sidebar-4.component.scss new file mode 100644 index 00000000..e69de29b diff --git a/src/app/main/ui/page-layouts/simple/left-sidebar-4/left-sidebar-4.component.ts b/src/app/main/ui/page-layouts/simple/left-sidebar-4/left-sidebar-4.component.ts new file mode 100644 index 00000000..4fb5f4b3 --- /dev/null +++ b/src/app/main/ui/page-layouts/simple/left-sidebar-4/left-sidebar-4.component.ts @@ -0,0 +1,36 @@ +import { Component } from '@angular/core'; + +import { FuseSidebarService } from '@fuse/components/sidebar/sidebar.service'; + +@Component({ + selector : 'simple-left-sidebar-4', + templateUrl: './left-sidebar-4.component.html', + styleUrls : ['./left-sidebar-4.component.scss'] +}) +export class SimpleLeftSidebar4Component +{ + /** + * Constructor + * + * @param {FuseSidebarService} _fuseSidebarService + */ + constructor( + private _fuseSidebarService: FuseSidebarService + ) + { + } + + // ----------------------------------------------------------------------------------------------------- + // @ Public methods + // ----------------------------------------------------------------------------------------------------- + + /** + * Toggle sidebar + * + * @param name + */ + toggleSidebar(name): void + { + this._fuseSidebarService.getSidebar(name).toggleOpen(); + } +} diff --git a/src/app/main/ui/page-layouts/simple/right-sidebar-1/right-sidebar-1.component.html b/src/app/main/ui/page-layouts/simple/right-sidebar-1/right-sidebar-1.component.html new file mode 100644 index 00000000..25f385bc --- /dev/null +++ b/src/app/main/ui/page-layouts/simple/right-sidebar-1/right-sidebar-1.component.html @@ -0,0 +1,40 @@ + diff --git a/src/app/main/ui/page-layouts/simple/right-sidebar-1/right-sidebar-1.component.scss b/src/app/main/ui/page-layouts/simple/right-sidebar-1/right-sidebar-1.component.scss new file mode 100644 index 00000000..e69de29b diff --git a/src/app/main/ui/page-layouts/simple/right-sidebar-1/right-sidebar-1.component.ts b/src/app/main/ui/page-layouts/simple/right-sidebar-1/right-sidebar-1.component.ts new file mode 100644 index 00000000..0d129ac2 --- /dev/null +++ b/src/app/main/ui/page-layouts/simple/right-sidebar-1/right-sidebar-1.component.ts @@ -0,0 +1,36 @@ +import { Component } from '@angular/core'; + +import { FuseSidebarService } from '@fuse/components/sidebar/sidebar.service'; + +@Component({ + selector : 'simple-right-sidebar-1', + templateUrl: './right-sidebar-1.component.html', + styleUrls : ['./right-sidebar-1.component.scss'] +}) +export class SimpleRightSidebar1Component +{ + /** + * Constructor + * + * @param {FuseSidebarService} _fuseSidebarService + */ + constructor( + private _fuseSidebarService: FuseSidebarService + ) + { + } + + // ----------------------------------------------------------------------------------------------------- + // @ Public methods + // ----------------------------------------------------------------------------------------------------- + + /** + * Toggle sidebar + * + * @param name + */ + toggleSidebar(name): void + { + this._fuseSidebarService.getSidebar(name).toggleOpen(); + } +} diff --git a/src/app/main/ui/page-layouts/simple/right-sidebar-2/right-sidebar-2.component.html b/src/app/main/ui/page-layouts/simple/right-sidebar-2/right-sidebar-2.component.html new file mode 100644 index 00000000..aa027714 --- /dev/null +++ b/src/app/main/ui/page-layouts/simple/right-sidebar-2/right-sidebar-2.component.html @@ -0,0 +1,40 @@ + diff --git a/src/app/main/ui/page-layouts/simple/right-sidebar-2/right-sidebar-2.component.scss b/src/app/main/ui/page-layouts/simple/right-sidebar-2/right-sidebar-2.component.scss new file mode 100644 index 00000000..e69de29b diff --git a/src/app/main/ui/page-layouts/simple/right-sidebar-2/right-sidebar-2.component.ts b/src/app/main/ui/page-layouts/simple/right-sidebar-2/right-sidebar-2.component.ts new file mode 100644 index 00000000..a5969ad8 --- /dev/null +++ b/src/app/main/ui/page-layouts/simple/right-sidebar-2/right-sidebar-2.component.ts @@ -0,0 +1,36 @@ +import { Component } from '@angular/core'; + +import { FuseSidebarService } from '@fuse/components/sidebar/sidebar.service'; + +@Component({ + selector : 'simple-right-sidebar-2', + templateUrl: './right-sidebar-2.component.html', + styleUrls : ['./right-sidebar-2.component.scss'] +}) +export class SimpleRightSidebar2Component +{ + /** + * Constructor + * + * @param {FuseSidebarService} _fuseSidebarService + */ + constructor( + private _fuseSidebarService: FuseSidebarService + ) + { + } + + // ----------------------------------------------------------------------------------------------------- + // @ Public methods + // ----------------------------------------------------------------------------------------------------- + + /** + * Toggle sidebar + * + * @param name + */ + toggleSidebar(name): void + { + this._fuseSidebarService.getSidebar(name).toggleOpen(); + } +} diff --git a/src/app/main/ui/page-layouts/simple/right-sidebar-3/right-sidebar-3.component.html b/src/app/main/ui/page-layouts/simple/right-sidebar-3/right-sidebar-3.component.html new file mode 100644 index 00000000..9a2aa27d --- /dev/null +++ b/src/app/main/ui/page-layouts/simple/right-sidebar-3/right-sidebar-3.component.html @@ -0,0 +1,48 @@ + diff --git a/src/app/main/ui/page-layouts/simple/right-sidebar-3/right-sidebar-3.component.scss b/src/app/main/ui/page-layouts/simple/right-sidebar-3/right-sidebar-3.component.scss new file mode 100644 index 00000000..e69de29b diff --git a/src/app/main/ui/page-layouts/simple/right-sidebar-3/right-sidebar-3.component.ts b/src/app/main/ui/page-layouts/simple/right-sidebar-3/right-sidebar-3.component.ts new file mode 100644 index 00000000..bece4802 --- /dev/null +++ b/src/app/main/ui/page-layouts/simple/right-sidebar-3/right-sidebar-3.component.ts @@ -0,0 +1,36 @@ +import { Component } from '@angular/core'; + +import { FuseSidebarService } from '@fuse/components/sidebar/sidebar.service'; + +@Component({ + selector : 'simple-right-sidebar-4', + templateUrl: './right-sidebar-3.component.html', + styleUrls : ['./right-sidebar-3.component.scss'] +}) +export class SimpleRightSidebar3Component +{ + /** + * Constructor + * + * @param {FuseSidebarService} _fuseSidebarService + */ + constructor( + private _fuseSidebarService: FuseSidebarService + ) + { + } + + // ----------------------------------------------------------------------------------------------------- + // @ Public methods + // ----------------------------------------------------------------------------------------------------- + + /** + * Toggle sidebar + * + * @param name + */ + toggleSidebar(name): void + { + this._fuseSidebarService.getSidebar(name).toggleOpen(); + } +} diff --git a/src/app/main/ui/page-layouts/simple/right-sidebar-4/right-sidebar-4.component.html b/src/app/main/ui/page-layouts/simple/right-sidebar-4/right-sidebar-4.component.html new file mode 100644 index 00000000..75b0c8b2 --- /dev/null +++ b/src/app/main/ui/page-layouts/simple/right-sidebar-4/right-sidebar-4.component.html @@ -0,0 +1,48 @@ + diff --git a/src/app/main/ui/page-layouts/simple/right-sidebar-4/right-sidebar-4.component.scss b/src/app/main/ui/page-layouts/simple/right-sidebar-4/right-sidebar-4.component.scss new file mode 100644 index 00000000..e69de29b diff --git a/src/app/main/ui/page-layouts/simple/right-sidebar-4/right-sidebar-4.component.ts b/src/app/main/ui/page-layouts/simple/right-sidebar-4/right-sidebar-4.component.ts new file mode 100644 index 00000000..3d9e9ee3 --- /dev/null +++ b/src/app/main/ui/page-layouts/simple/right-sidebar-4/right-sidebar-4.component.ts @@ -0,0 +1,36 @@ +import { Component } from '@angular/core'; + +import { FuseSidebarService } from '@fuse/components/sidebar/sidebar.service'; + +@Component({ + selector : 'simple-right-sidebar-4', + templateUrl: './right-sidebar-4.component.html', + styleUrls : ['./right-sidebar-4.component.scss'] +}) +export class SimpleRightSidebar4Component +{ + /** + * Constructor + * + * @param {FuseSidebarService} _fuseSidebarService + */ + constructor( + private _fuseSidebarService: FuseSidebarService + ) + { + } + + // ----------------------------------------------------------------------------------------------------- + // @ Public methods + // ----------------------------------------------------------------------------------------------------- + + /** + * Toggle sidebar + * + * @param name + */ + toggleSidebar(name): void + { + this._fuseSidebarService.getSidebar(name).toggleOpen(); + } +} diff --git a/src/app/main/ui/typography/tabs/message-boxes/message-boxes.component.html b/src/app/main/ui/typography/tabs/message-boxes/message-boxes.component.html new file mode 100644 index 00000000..e3a27221 --- /dev/null +++ b/src/app/main/ui/typography/tabs/message-boxes/message-boxes.component.html @@ -0,0 +1,105 @@ +
+ +
Message Boxes
+ +
+ +
+ +
+
+ This is a standard message box +
+
+ + + + + +
+ +
+ +
+
+ This is an alert message box! +
+
+ + + + + +
+ +
+ +
+
+ This is a warning message box +
+
+ + + + + +
+ +
+ +
+
+ This is a success message box +
+
+ + + + + +
+ +
+ +
+
+ This is a info message box +
+
+ + + + + +
+ + +
+ +
\ No newline at end of file diff --git a/src/app/main/ui/typography/tabs/message-boxes/message-boxes.component.scss b/src/app/main/ui/typography/tabs/message-boxes/message-boxes.component.scss new file mode 100644 index 00000000..04a80218 --- /dev/null +++ b/src/app/main/ui/typography/tabs/message-boxes/message-boxes.component.scss @@ -0,0 +1,31 @@ +:host { + + #typography-message-boxes { + + .source-code { + position: relative; + margin-bottom: 24px; + min-height: 180px; + max-height: 500px; + + code { + background: none !important; + } + } + + .preview { + font-size: 16px; + padding: 16px; + margin-bottom: 24px; + min-height: 180px; + + &:last-child { + margin-bottom: 0; + } + + .mat-caption { + margin-bottom: 16px; + } + } + } +} \ No newline at end of file diff --git a/src/app/main/ui/typography/tabs/message-boxes/message-boxes.component.ts b/src/app/main/ui/typography/tabs/message-boxes/message-boxes.component.ts new file mode 100644 index 00000000..9949aee7 --- /dev/null +++ b/src/app/main/ui/typography/tabs/message-boxes/message-boxes.component.ts @@ -0,0 +1,17 @@ +import { Component } from '@angular/core'; + +@Component({ + selector : 'typography-message-boxes', + templateUrl: './message-boxes.component.html', + styleUrls : ['./message-boxes.component.scss'] +}) +export class TypographyMessageBoxesComponent +{ + /** + * Constructor + */ + constructor() + { + + } +} diff --git a/src/app/main/ui/typography/typography.module.ts b/src/app/main/ui/typography/typography.module.ts new file mode 100644 index 00000000..38aa6db0 --- /dev/null +++ b/src/app/main/ui/typography/typography.module.ts @@ -0,0 +1,43 @@ +import { NgModule } from '@angular/core'; +import { RouterModule, Routes } from '@angular/router'; +import { MatIconModule, MatTabsModule } from '@angular/material'; + +import { FuseSharedModule } from '@fuse/shared.module'; +import { FuseHighlightModule } from '@fuse/components'; + +import { TypographyComponent } from 'app/main/ui/typography/typography.component'; +import { TypographyHeadingsComponent } from 'app/main/ui/typography/tabs/headings/headings.component'; +import { TypographyInlineTextElementsComponent } from 'app/main/ui/typography/tabs/inline-text-elements/inline-text-elements.component'; +import { TypographyBlockquotesListsComponent } from 'app/main/ui/typography/tabs/blockquotes-lists/blockquotes-lists.component'; +import { TypographyMessageBoxesComponent } from 'app/main/ui/typography/tabs/message-boxes/message-boxes.component'; +import { TypographyHelpersComponent } from 'app/main/ui/typography/tabs/helpers/helpers.component'; + +const routes: Routes = [ + { + path : 'typography', + component: TypographyComponent + } +]; + +@NgModule({ + declarations: [ + TypographyComponent, + TypographyHeadingsComponent, + TypographyInlineTextElementsComponent, + TypographyBlockquotesListsComponent, + TypographyMessageBoxesComponent, + TypographyHelpersComponent + ], + imports : [ + RouterModule.forChild(routes), + + MatIconModule, + MatTabsModule, + + FuseSharedModule, + FuseHighlightModule + ] +}) +export class UITypographyModule +{ +} diff --git a/src/app/main/ui/ui.module.ts b/src/app/main/ui/ui.module.ts new file mode 100644 index 00000000..1d594101 --- /dev/null +++ b/src/app/main/ui/ui.module.ts @@ -0,0 +1,22 @@ +import { NgModule } from '@angular/core'; + +import { UIFormsModule } from 'app/main/ui/forms/forms.module'; +import { UIIconsModule } from 'app/main/ui/icons/icons.module'; +import { UITypographyModule } from 'app/main/ui/typography/typography.module'; +import { UIHelperClassesModule } from 'app/main/ui/helper-classes/helper-classes.module'; +import { UIPageLayoutsModule } from 'app/main/ui/page-layouts/page-layouts.module'; +import { UIColorsModule } from 'app/main/ui/colors/colors.module'; + +@NgModule({ + imports: [ + UIFormsModule, + UIIconsModule, + UITypographyModule, + UIHelperClassesModule, + UIPageLayoutsModule, + UIColorsModule + ] +}) +export class UIModule +{ +} diff --git a/src/index.html b/src/index.html index 865a7105..534f3c25 100644 --- a/src/index.html +++ b/src/index.html @@ -181,7 +181,7 @@ - + @@ -213,7 +213,7 @@ - + diff --git a/src/karma.conf.js b/src/karma.conf.js index 11f4e6aa..eab90d9b 100644 --- a/src/karma.conf.js +++ b/src/karma.conf.js @@ -4,7 +4,7 @@ module.exports = function (config) { config.set({ - basePath : '..', + basePath : '', frameworks : ['jasmine', '@angular-devkit/build-angular'], plugins : [ require('karma-jasmine'), diff --git a/src/styles.scss b/src/styles.scss index 47998044..b8f60696 100644 --- a/src/styles.scss +++ b/src/styles.scss @@ -1,2 +1,24 @@ // Import Fuse core library -@import "@fuse/scss/core"; \ No newline at end of file +@import "@fuse/scss/core"; + +// ----------------------------------------------------------------------------------------------------- +// @ Multiple material themes example +// ----------------------------------------------------------------------------------------------------- + +// Define the Material palettes +$yellow-theme-primary: mat-palette($mat-fusedark); +$yellow-theme-accent: mat-palette($mat-yellow, 600, 400, 700); +$yellow-theme-warn: mat-palette($mat-red); + +// Create the Material theme object +$yellow-theme: mat-light-theme($yellow-theme-primary, $yellow-theme-accent, $yellow-theme-warn); + +// Add ".yellow-theme" class to the body to activate this theme +.yellow-theme { + + // Generate the Angular Material theme + @include angular-material-theme($yellow-theme); + + // Generate the fuse color classes with the new colors... + @include generateFuseColorClasses($yellow-theme-primary, $yellow-theme-accent, $yellow-theme-warn); +} \ No newline at end of file diff --git a/src/tslint.json b/src/tslint.json index 04494aa2..d88db874 100644 --- a/src/tslint.json +++ b/src/tslint.json @@ -4,14 +4,23 @@ "directive-selector": [ true, "attribute", - "fuse", + [ + "fuse", + "" + ], "camelCase" ], "component-selector": [ true, "element", - "fuse", - "kebab-case" + [ + "fuse", + "" + ], + [ + "kebab-case", + "camelCase" + ] ] } } diff --git a/tslint.json b/tslint.json index 6583c181..eca56dcb 100644 --- a/tslint.json +++ b/tslint.json @@ -90,6 +90,11 @@ true, "allow-null-check" ], + "typedef": [ + true, + "call-signature", + "property-declaration" + ], "typedef-whitespace": [ true, {