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/angular.json b/angular.json index b3d10f35..37ba479d 100644 --- a/angular.json +++ b/angular.json @@ -25,7 +25,7 @@ "assets": [ "src/favicon.ico", "src/assets", - "src/app/main/content/components/angular-material" + "src/app/main/angular-material-elements" ], "styles": [ "src/styles.scss" @@ -104,7 +104,7 @@ ], "exclude": [ "**/node_modules/**", - "**/src/app/fuse-fake-db/**/*", + "**/src/app/fake-db/**/*", "**/src/assets/angular-material-examples/**/*" ] } @@ -128,7 +128,7 @@ "tsConfig": "e2e/tsconfig.e2e.json", "exclude": [ "**/node_modules/**", - "**/src/app/fuse-fake-db/**/*", + "**/src/app/fake-db/**/*", "**/src/assets/angular-material-examples/**/*" ] } diff --git a/package-lock.json b/package-lock.json index 35ecb7c4..5f7f5482 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,34 +1,34 @@ { "name": "fuse", - "version": "6.0.2", + "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.3", - "resolved": "https://registry.npmjs.org/@angular-devkit/architect/-/architect-0.6.3.tgz", - "integrity": "sha512-w9tK3VACU+CnOQQZT6o7QO2brn/OVNDf2Y11rI+ZQH7UIn6N0ZFoMl9WyFB//K2Gkoa7hAobykhRTtP8lrTF1g==", + "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.3", + "@angular-devkit/core": "0.6.8", "rxjs": "^6.0.0" } }, "@angular-devkit/build-angular": { - "version": "0.6.3", - "resolved": "https://registry.npmjs.org/@angular-devkit/build-angular/-/build-angular-0.6.3.tgz", - "integrity": "sha512-ce+uAXQXyuMy6IxSnsGKeHlLVjsI77DblNvkcO1NilP7iYxujEJx6qDq/Hrf1uhuqRpm+8pt5zY6QD90gQrDcg==", + "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.3", - "@angular-devkit/build-optimizer": "0.6.3", - "@angular-devkit/core": "0.6.3", - "@ngtools/webpack": "6.0.3", + "@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.4.1", "cache-loader": "^1.2.2", @@ -79,21 +79,29 @@ } }, "@angular-devkit/build-optimizer": { - "version": "0.6.3", - "resolved": "https://registry.npmjs.org/@angular-devkit/build-optimizer/-/build-optimizer-0.6.3.tgz", - "integrity": "sha512-C0LGWh7+rYjpE1T1guaq9EMovwhEJ1QR25qjJxUoYvN+sM+MfVpMhoa6ruqnxh+eQCfRiMdIsnbOboiZxNHTQw==", + "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.3", - "resolved": "https://registry.npmjs.org/@angular-devkit/core/-/core-0.6.3.tgz", - "integrity": "sha512-97hFVW6in8oYJUEqjmUP0Tb/mPlTG3sc0THpe5MCGEkDPjlp2cObt9rUCAVOjugBlScV8rzTpVQ+95PT60Py8A==", + "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,42 +111,42 @@ } }, "@angular-devkit/schematics": { - "version": "0.6.3", - "resolved": "https://registry.npmjs.org/@angular-devkit/schematics/-/schematics-0.6.3.tgz", - "integrity": "sha512-dXlyVNuFRhiOnhAk0NojEUThLrZBpVZmWvEQ4h/pnyHS0P9CfnHqJ8DCcCrjOwYkzdBwBrYchXOCYfo8zuxYGw==", + "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.3", + "@angular-devkit/core": "0.6.8", "rxjs": "^6.0.0" } }, "@angular/animations": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/@angular/animations/-/animations-6.0.2.tgz", - "integrity": "sha512-QoNJ/L0Xgtrj1KBp8wvxhHwRt+sQ5tBihWm82UbNgN82ZNnfNzQoAqtahbZN5AY7XFmGbDX+lVt3TdO8omXhmg==", + "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.2", - "resolved": "https://registry.npmjs.org/@angular/cdk/-/cdk-6.0.2.tgz", - "integrity": "sha512-UY+S0FZkyDoxn5aaj5Ue3fGlOQKEnNBJXasaUQbSYKZiUkyFJkgmcSHRJlJuCAunJAtW3IIOhPSFxLZIj7lCHA==", + "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.3", - "resolved": "https://registry.npmjs.org/@angular/cli/-/cli-6.0.3.tgz", - "integrity": "sha512-G8jfgJublsRjveX1P+F5awHvpC07mKAF7f5lebowIs+QAHSOD6HxQ/JhMbJTwz/aj20iWgZOygA5LhkP0Wr+UQ==", + "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.3", - "@angular-devkit/core": "0.6.3", - "@angular-devkit/schematics": "0.6.3", - "@schematics/angular": "0.6.3", - "@schematics/update": "0.6.3", + "@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", @@ -166,31 +174,31 @@ } }, "@angular/common": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/@angular/common/-/common-6.0.2.tgz", - "integrity": "sha512-Yc3NnLGs1ltnDhUCOoMCQMRSkJv/sCv+jKx3uSdrvd8Y55APl2boZhZUK4WphPfWIkpvC7odpiLXAmnVgP6vcw==", + "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.2", - "resolved": "https://registry.npmjs.org/@angular/compiler/-/compiler-6.0.2.tgz", - "integrity": "sha512-uKuM7dcTWwcElklT4E/tckp5fnGNUq4wDna3gZWO6fvc7FQK0SUU4l+A6C1d5YdCRgAsv6gxIrk3MxbSF9UwEw==", + "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.2", - "resolved": "https://registry.npmjs.org/@angular/compiler-cli/-/compiler-cli-6.0.2.tgz", - "integrity": "sha512-6hupeihL+MKYbP0xvHZiaVpYVF1XAlLpI1aTVLUhpzgnR8vgXCwni9iJlr7BZFyicVgApn6l7Oh2xIvMWftYhw==", + "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": { @@ -327,79 +335,79 @@ } }, "@angular/core": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/@angular/core/-/core-6.0.2.tgz", - "integrity": "sha512-+ahJofKZFyaq0kLhKUOCa3Fo4WQ4mkMmYRqwFjKgjPupzPgMh0FkBsojuP1WiBd5KTIkv7U8B4sTziUxRDrKgg==", + "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.2", - "resolved": "https://registry.npmjs.org/@angular/forms/-/forms-6.0.2.tgz", - "integrity": "sha512-Oc234cLjTj1tx2gF/nS/TIC3Auc+LCyC8H6GYqTxXQUyZQeGHqUptvDQz3KwM9Num3EKFUr9J2yzGPnz6lZVmQ==", + "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.2", - "resolved": "https://registry.npmjs.org/@angular/http/-/http-6.0.2.tgz", - "integrity": "sha512-BONrdNMKOaQdXiWnrCAaUiP1akf/nuUG6xm/PJe684SrgcqWHN4JJuwgMhGRGIZZCIKEWcIEaZSp+DbWqnj1kg==", + "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.2", - "resolved": "https://registry.npmjs.org/@angular/language-service/-/language-service-6.0.2.tgz", - "integrity": "sha512-EznIei5QGv4Hv+RtfCnI8TQPW7gLZBw7LrGPXSbwV/CXfY11ziEsd/h1lBfN3Wch3soIOXs3Qqk3zx//MrBG/Q==", + "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.2", - "resolved": "https://registry.npmjs.org/@angular/material/-/material-6.0.2.tgz", - "integrity": "sha512-928g7cnnRIJJx9/pC5GWqypcxrKkfijTCrCC6yeypvcgab1pmsk7m+1uE8VSFGIsUb6x8W3CF5nJUT1viuBIZg==", + "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.2", - "resolved": "https://registry.npmjs.org/@angular/material-moment-adapter/-/material-moment-adapter-6.0.2.tgz", - "integrity": "sha512-tOWQcnio4Yk5hs83mZEdvz85fK3QbGHGzpR5YjcHFFybs6KSKi/BXkHoDC5bC1pcLE6sn2/btq9+Jt1tknGhiw==", + "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.2", - "resolved": "https://registry.npmjs.org/@angular/platform-browser/-/platform-browser-6.0.2.tgz", - "integrity": "sha512-iMBHckhknJ8Wfw9ZVloiw0WPZDtzQFLE2e7D42of7SgXuHloStXUchb0qLr6ZTZwTY0oBPSvDKgJJVmEjZUZvw==", + "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.2", - "resolved": "https://registry.npmjs.org/@angular/platform-browser-dynamic/-/platform-browser-dynamic-6.0.2.tgz", - "integrity": "sha512-g1EC0wIWd4OhcEvUnisTfp3y0eMAXgXbACdtgsrozG//xzyqiRFUnBTYTAP4ecninCEltyZYK7EBGfzp8KwQjw==", + "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.2", - "resolved": "https://registry.npmjs.org/@angular/router/-/router-6.0.2.tgz", - "integrity": "sha512-XqTtfs/UzT2k2MeVQG1pOP+wR1zcH8V71S6kmWIwFcfyKUgZfIm45sNsZyBZPwY2RUqwCeZYQFjPlVW8wD1PBw==", + "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" } @@ -411,82 +419,73 @@ "dev": true }, "@ngrx/effects": { - "version": "6.0.0-beta.3", - "resolved": "https://registry.npmjs.org/@ngrx/effects/-/effects-6.0.0-beta.3.tgz", - "integrity": "sha512-THTjnYUKFxPJCtxaKZepTnwGm0Zn5826qbNIpcTITjfIDXstOufAtb5CGH07zXrfJ8Ipdir/7bPE46kAdU4lkg==" + "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.3", - "resolved": "https://registry.npmjs.org/@ngrx/router-store/-/router-store-6.0.0-beta.3.tgz", - "integrity": "sha512-x5Z9G0H/3HTh+1UDceflGhk/2gfzbDTyOg6yhrzxAp9daD7wUPr21Jk+ecw3NqKMvqn3SDQIkWjwPdO756xrYw==" + "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.3", - "resolved": "https://registry.npmjs.org/@ngrx/store/-/store-6.0.0-beta.3.tgz", - "integrity": "sha512-LOQdv2bt3KsFHEYBcNZdVoRZGSBlHBF9C51siPABSWfAenwrNiOz9Ga/qe4hl3cfM3UoCNIYtdsbZ2N/ZCY5RQ==" + "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.3", - "resolved": "https://registry.npmjs.org/@ngrx/store-devtools/-/store-devtools-6.0.0-beta.3.tgz", - "integrity": "sha512-KwmMELWY+WA1fL/myhQGiqM1uvRIjQ7yUaViVwknhRf7UsBPlWTMrSiFqUIb3QkwGYnVdqRjdYVQrJTIdJpolQ==" + "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.3", - "resolved": "https://registry.npmjs.org/@ngtools/webpack/-/webpack-6.0.3.tgz", - "integrity": "sha512-wrhSFItcZp4Yzp6lgSuy23YdhaUs9D+KdGZPjwzzXtJIJCSzGkWuXzwlCwyKSFRQ6thyH/T3nffpHNaS3dWn2A==", + "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.3", + "@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.3", - "resolved": "https://registry.npmjs.org/@schematics/angular/-/angular-0.6.3.tgz", - "integrity": "sha512-YhldE1K6x/8D0PxFusjtB32iOAayyD1PSxPCx/q7I7T6x/lG7l35ZDV6ZZE6bDvIaxQBsjhIm8ACy2n+xwFxTA==", + "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.3", - "@angular-devkit/schematics": "0.6.3", + "@angular-devkit/core": "0.6.8", + "@angular-devkit/schematics": "0.6.8", "typescript": ">=2.6.2 <2.8" } }, "@schematics/update": { - "version": "0.6.3", - "resolved": "https://registry.npmjs.org/@schematics/update/-/update-0.6.3.tgz", - "integrity": "sha512-UsKrg02+jwdsz9BdMVxDMeAZCF+c+dvHRWww4D2RcNzWdCTVWeBqRAmlreJJ0TGE54r7PEBnmQe0t5mS4F3d4w==", + "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.3", - "@angular-devkit/schematics": "0.6.3", + "@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", "semver-intersect": "^1.1.2" } }, - "@swimlane/dragula": { - "version": "3.7.3", - "resolved": "https://registry.npmjs.org/@swimlane/dragula/-/dragula-3.7.3.tgz", - "integrity": "sha512-S5hhbgEX/pEg6bM1RhBOLSQQj7DV7TKe5XF40N9g2zBu1Gw1Bh4sf9tl+YCBeospC33R/PjyvBKt47K7XEuvjg==", - "requires": { - "contra": "1.9.4", - "crossvent": "1.5.4" - } - }, "@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,17 +501,19 @@ } }, "@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.1", - "resolved": "https://registry.npmjs.org/@swimlane/ngx-dnd/-/ngx-dnd-4.0.1.tgz", - "integrity": "sha512-Ya2zKD3p/XSMLOctnFIXD3Gg+M2lF90ocxnD6ibNcUeKKKpuWkG3ThzcwXuUpTyW6k45VwmeWHDWlgn8qp40Qw==", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@swimlane/ngx-dnd/-/ngx-dnd-4.0.0.tgz", + "integrity": "sha512-OTfGHKNFe+0FOHIhnR8oGgrTUVkWPPkTIyD5+DqMDOYXSBUpoivs7W64cqU+m5sL2N5ULBUtXJTvMD2MpNjxNg==", "requires": { - "@swimlane/dragula": "^3.7.3", - "@types/dragula": "^2.1.33" + "@types/dragula": "^2.1.32", + "dragula": "github:swimlane/dragula#0ddf66546a483691b98f3420abc576a2e5c0cc58", + "install": "^0.11.0", + "npm": "^5.8.0" } }, "@types/dragula": { @@ -521,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": { @@ -958,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": { @@ -973,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", @@ -1101,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": { @@ -1158,13 +1176,13 @@ "dev": true }, "autoprefixer": { - "version": "8.5.0", - "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-8.5.0.tgz", - "integrity": "sha512-buY1XxFoBrXvLsoFb0jP+niSu1tCj2RwMwHj96+RfQ8DJTgb0vUhh0dg6wjJT3JzsFYBrkSj8/sGtarNdlxTFw==", + "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.7", - "caniuse-lite": "^1.0.30000839", + "browserslist": "^3.2.8", + "caniuse-lite": "^1.0.30000851", "normalize-range": "^0.1.2", "num2fraction": "^1.2.2", "postcss": "^6.0.22", @@ -1659,13 +1677,13 @@ } }, "browserslist": { - "version": "3.2.7", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-3.2.7.tgz", - "integrity": "sha512-oYVLxFVqpX9uMhOIQBLtZL+CX4uY8ZpWcjNTaxyWl5rO8yA9SSNikFnAfvk8J3P/7z3BZwNmEqFKaJoYltj3MQ==", + "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.30000835", - "electron-to-chromium": "^1.3.45" + "caniuse-lite": "^1.0.30000844", + "electron-to-chromium": "^1.3.47" } }, "buffer": { @@ -1818,9 +1836,9 @@ } }, "caniuse-lite": { - "version": "1.0.30000843", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30000843.tgz", - "integrity": "sha512-1ntiW826MhRBmM0CeI7w1cQr16gxwOoM8doJWh3BFalPZoKWdZXs27Bc04xth/3NR1/wNXn9cpP4F92lVenCvg==", + "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": { @@ -2117,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": { @@ -2141,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": { @@ -2328,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", @@ -2880,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": { @@ -3167,6 +3201,14 @@ "domelementtype": "1" } }, + "dragula": { + "version": "github:swimlane/dragula#0ddf66546a483691b98f3420abc576a2e5c0cc58", + "from": "github:swimlane/dragula#fix-drag-issue", + "requires": { + "contra": "1.9.4", + "crossvent": "1.5.4" + } + }, "duplexer": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/duplexer/-/duplexer-0.1.1.tgz", @@ -3208,9 +3250,9 @@ "dev": true }, "electron-to-chromium": { - "version": "1.3.47", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.47.tgz", - "integrity": "sha1-dk6IfKkQTQGgrI6r7n38DizhQQQ=", + "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": { @@ -3383,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", @@ -3407,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", @@ -4719,9 +4761,9 @@ } }, "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": { @@ -4870,14 +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" } }, @@ -4992,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": { @@ -5162,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", @@ -5271,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": { @@ -5346,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": { @@ -5436,6 +5478,11 @@ "integrity": "sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw==", "dev": true }, + "install": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/install/-/install-0.11.0.tgz", + "integrity": "sha512-30UqvWKr/59SStU2/bRye4wT1S3mzjwa0oV+BxusB0neGqhxUrwLlnXDbt6QtIfBxCNWFqg+ARnGNjFj8XuV5A==" + }, "internal-ip": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/internal-ip/-/internal-ip-1.2.0.tgz", @@ -5897,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" } } } @@ -5949,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": { @@ -6002,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", @@ -6130,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", @@ -6148,6 +6205,13 @@ "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", @@ -6399,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" } }, @@ -7000,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", @@ -7094,17 +7158,17 @@ } }, "ngrx-store-freeze": { - "version": "0.2.3", - "resolved": "https://registry.npmjs.org/ngrx-store-freeze/-/ngrx-store-freeze-0.2.3.tgz", - "integrity": "sha512-IO2zBWMAyAWZgK6zbPhmR3tNRgW+jfi/Z+Xkvaa42w6eYNQ8bEwYv7uxZo/3MQJ5RglxZ+6KsDLXPzjN+ZUEZw==", + "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.1.0", - "resolved": "https://registry.npmjs.org/ngx-color-picker/-/ngx-color-picker-6.1.0.tgz", - "integrity": "sha512-qt7dczjKRSNZbFwBP7NAoX/bSsOTX5soOHTk+YHLaFEp0s51hb1GnWUBtNQ4foFUTAloG3MZsSqsraoVeDHRUg==" + "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", @@ -7127,33 +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, "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" + } } } }, @@ -7436,6 +7659,4163 @@ "integrity": "sha1-LRDAa9/TEuqXd2laTShDlFa3WUI=", "dev": true }, + "npm": { + "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", + "ansi-regex": "~3.0.0", + "ansicolors": "~0.3.2", + "ansistyles": "~0.1.3", + "aproba": "~1.2.0", + "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", + "config-chain": "~1.1.11", + "debuglog": "*", + "detect-indent": "~5.0.0", + "detect-newline": "^2.1.0", + "dezalgo": "~1.0.3", + "editor": "~1.0.0", + "find-npm-prefix": "^1.0.2", + "fs-vacuum": "~1.2.10", + "fs-write-stream-atomic": "~1.0.10", + "gentle-fs": "^2.0.1", + "glob": "~7.1.2", + "graceful-fs": "~4.1.11", + "has-unicode": "~2.0.1", + "hosted-git-info": "^2.6.0", + "iferr": "~0.1.5", + "imurmurhash": "*", + "inflight": "~1.0.6", + "inherits": "~2.0.3", + "ini": "^1.3.5", + "init-package-json": "^1.10.3", + "is-cidr": "~1.0.0", + "json-parse-better-errors": "^1.0.2", + "lazy-property": "~1.0.0", + "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": "*", + "lodash._cacheindexof": "*", + "lodash._createcache": "*", + "lodash._getnative": "*", + "lodash.clonedeep": "~4.5.0", + "lodash.restparam": "*", + "lodash.union": "~4.6.0", + "lodash.uniq": "~4.5.0", + "lodash.without": "~4.4.0", + "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.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", + "opener": "~1.4.3", + "osenv": "^0.1.5", + "pacote": "^7.6.1", + "path-is-inside": "~1.0.2", + "promise-inflight": "~1.0.1", + "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.2.1", + "readable-stream": "^2.3.6", + "readdir-scoped-modules": "*", + "request": "^2.85.0", + "retry": "^0.12.0", + "rimraf": "~2.6.2", + "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.3.0", + "strip-ansi": "~4.0.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.5.0", + "uuid": "^3.2.1", + "validate-npm-package-license": "^3.0.3", + "validate-npm-package-name": "~3.0.0", + "which": "~1.3.0", + "worker-farm": "^1.6.0", + "wrappy": "~1.0.2", + "write-file-atomic": "^2.3.0" + }, + "dependencies": { + "JSONStream": { + "version": "1.3.2", + "bundled": true, + "requires": { + "jsonparse": "^1.2.0", + "through": ">=2.2.7 <3" + }, + "dependencies": { + "jsonparse": { + "version": "1.3.1", + "bundled": true + }, + "through": { + "version": "2.3.8", + "bundled": true + } + } + }, + "abbrev": { + "version": "1.1.1", + "bundled": true + }, + "ansi-regex": { + "version": "3.0.0", + "bundled": true + }, + "ansicolors": { + "version": "0.3.2", + "bundled": true + }, + "ansistyles": { + "version": "0.1.3", + "bundled": true + }, + "aproba": { + "version": "1.2.0", + "bundled": true + }, + "archy": { + "version": "1.0.0", + "bundled": true + }, + "bin-links": { + "version": "1.1.0", + "bundled": true, + "requires": { + "bluebird": "^3.5.0", + "cmd-shim": "^2.0.2", + "fs-write-stream-atomic": "^1.0.10", + "gentle-fs": "^2.0.0", + "graceful-fs": "^4.1.11", + "slide": "^1.1.6" + } + }, + "bluebird": { + "version": "3.5.1", + "bundled": true + }, + "byte-size": { + "version": "4.0.2", + "bundled": true + }, + "cacache": { + "version": "10.0.4", + "bundled": true, + "requires": { + "bluebird": "^3.5.1", + "chownr": "^1.0.1", + "glob": "^7.1.2", + "graceful-fs": "^4.1.11", + "lru-cache": "^4.1.1", + "mississippi": "^2.0.0", + "mkdirp": "^0.5.1", + "move-concurrently": "^1.0.1", + "promise-inflight": "^1.0.1", + "rimraf": "^2.6.2", + "ssri": "^5.2.4", + "unique-filename": "^1.1.0", + "y18n": "^4.0.0" + }, + "dependencies": { + "mississippi": { + "version": "2.0.0", + "bundled": true, + "requires": { + "concat-stream": "^1.5.0", + "duplexify": "^3.4.2", + "end-of-stream": "^1.1.0", + "flush-write-stream": "^1.0.0", + "from2": "^2.1.0", + "parallel-transform": "^1.1.0", + "pump": "^2.0.1", + "pumpify": "^1.3.3", + "stream-each": "^1.1.0", + "through2": "^2.0.0" + }, + "dependencies": { + "concat-stream": { + "version": "1.6.1", + "bundled": true, + "requires": { + "inherits": "^2.0.3", + "readable-stream": "^2.2.2", + "typedarray": "^0.0.6" + }, + "dependencies": { + "typedarray": { + "version": "0.0.6", + "bundled": true + } + } + }, + "duplexify": { + "version": "3.5.4", + "bundled": true, + "requires": { + "end-of-stream": "^1.0.0", + "inherits": "^2.0.1", + "readable-stream": "^2.0.0", + "stream-shift": "^1.0.0" + }, + "dependencies": { + "stream-shift": { + "version": "1.0.0", + "bundled": true + } + } + }, + "end-of-stream": { + "version": "1.4.1", + "bundled": true, + "requires": { + "once": "^1.4.0" + } + }, + "flush-write-stream": { + "version": "1.0.2", + "bundled": true, + "requires": { + "inherits": "^2.0.1", + "readable-stream": "^2.0.4" + } + }, + "from2": { + "version": "2.3.0", + "bundled": true, + "requires": { + "inherits": "^2.0.1", + "readable-stream": "^2.0.0" + } + }, + "parallel-transform": { + "version": "1.1.0", + "bundled": true, + "requires": { + "cyclist": "~0.2.2", + "inherits": "^2.0.3", + "readable-stream": "^2.1.5" + }, + "dependencies": { + "cyclist": { + "version": "0.2.2", + "bundled": true + } + } + }, + "pump": { + "version": "2.0.1", + "bundled": true, + "requires": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } + }, + "pumpify": { + "version": "1.4.0", + "bundled": true, + "requires": { + "duplexify": "^3.5.3", + "inherits": "^2.0.3", + "pump": "^2.0.0" + } + }, + "stream-each": { + "version": "1.2.2", + "bundled": true, + "requires": { + "end-of-stream": "^1.1.0", + "stream-shift": "^1.0.0" + }, + "dependencies": { + "stream-shift": { + "version": "1.0.0", + "bundled": true + } + } + }, + "through2": { + "version": "2.0.3", + "bundled": true, + "requires": { + "readable-stream": "^2.1.5", + "xtend": "~4.0.1" + }, + "dependencies": { + "xtend": { + "version": "4.0.1", + "bundled": true + } + } + } + } + }, + "y18n": { + "version": "4.0.0", + "bundled": true + } + } + }, + "call-limit": { + "version": "1.1.0", + "bundled": true + }, + "chownr": { + "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, + "requires": { + "colors": "^1.1.2", + "lodash": "^3.10.1", + "string-width": "^1.0.1" + }, + "dependencies": { + "colors": { + "version": "1.1.2", + "bundled": true, + "optional": true + }, + "lodash": { + "version": "3.10.1", + "bundled": true + }, + "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 + } + } + } + } + } + } + }, + "cmd-shim": { + "version": "2.0.2", + "bundled": true, + "requires": { + "graceful-fs": "^4.1.2", + "mkdirp": "~0.5.0" + } + }, + "columnify": { + "version": "1.5.4", + "bundled": true, + "requires": { + "strip-ansi": "^3.0.0", + "wcwidth": "^1.0.0" + }, + "dependencies": { + "strip-ansi": { + "version": "3.0.1", + "bundled": true, + "requires": { + "ansi-regex": "^2.0.0" + }, + "dependencies": { + "ansi-regex": { + "version": "2.1.1", + "bundled": true + } + } + }, + "wcwidth": { + "version": "1.0.1", + "bundled": true, + "requires": { + "defaults": "^1.0.3" + }, + "dependencies": { + "defaults": { + "version": "1.0.3", + "bundled": true, + "requires": { + "clone": "^1.0.2" + }, + "dependencies": { + "clone": { + "version": "1.0.2", + "bundled": true + } + } + } + } + } + } + }, + "config-chain": { + "version": "1.1.11", + "bundled": true, + "requires": { + "ini": "^1.3.4", + "proto-list": "~1.2.1" + }, + "dependencies": { + "proto-list": { + "version": "1.2.4", + "bundled": true + } + } + }, + "debuglog": { + "version": "1.0.1", + "bundled": true + }, + "detect-indent": { + "version": "5.0.0", + "bundled": true + }, + "detect-newline": { + "version": "2.1.0", + "bundled": true + }, + "dezalgo": { + "version": "1.0.3", + "bundled": true, + "requires": { + "asap": "^2.0.0", + "wrappy": "1" + }, + "dependencies": { + "asap": { + "version": "2.0.5", + "bundled": true + } + } + }, + "editor": { + "version": "1.0.0", + "bundled": true + }, + "find-npm-prefix": { + "version": "1.0.2", + "bundled": true + }, + "fs-vacuum": { + "version": "1.2.10", + "bundled": true, + "requires": { + "graceful-fs": "^4.1.2", + "path-is-inside": "^1.0.1", + "rimraf": "^2.5.2" + } + }, + "fs-write-stream-atomic": { + "version": "1.0.10", + "bundled": true, + "requires": { + "graceful-fs": "^4.1.2", + "iferr": "^0.1.5", + "imurmurhash": "^0.1.4", + "readable-stream": "1 || 2" + } + }, + "gentle-fs": { + "version": "2.0.1", + "bundled": true, + "requires": { + "aproba": "^1.1.2", + "fs-vacuum": "^1.2.10", + "graceful-fs": "^4.1.11", + "iferr": "^0.1.5", + "mkdirp": "^0.5.1", + "path-is-inside": "^1.0.2", + "read-cmd-shim": "^1.0.1", + "slide": "^1.1.6" + } + }, + "glob": { + "version": "7.1.2", + "bundled": true, + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "dependencies": { + "fs.realpath": { + "version": "1.0.0", + "bundled": true + }, + "minimatch": { + "version": "3.0.4", + "bundled": true, + "requires": { + "brace-expansion": "^1.1.7" + }, + "dependencies": { + "brace-expansion": { + "version": "1.1.8", + "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 + } + } + } + } + }, + "path-is-absolute": { + "version": "1.0.1", + "bundled": true + } + } + }, + "graceful-fs": { + "version": "4.1.11", + "bundled": true + }, + "has-unicode": { + "version": "2.0.1", + "bundled": true + }, + "hosted-git-info": { + "version": "2.6.0", + "bundled": true + }, + "iferr": { + "version": "0.1.5", + "bundled": true + }, + "imurmurhash": { + "version": "0.1.4", + "bundled": true + }, + "inflight": { + "version": "1.0.6", + "bundled": true, + "requires": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "inherits": { + "version": "2.0.3", + "bundled": true + }, + "ini": { + "version": "1.3.5", + "bundled": true + }, + "init-package-json": { + "version": "1.10.3", + "bundled": true, + "requires": { + "glob": "^7.1.1", + "npm-package-arg": "^4.0.0 || ^5.0.0 || ^6.0.0", + "promzard": "^0.3.0", + "read": "~1.0.1", + "read-package-json": "1 || 2", + "semver": "2.x || 3.x || 4 || 5", + "validate-npm-package-license": "^3.0.1", + "validate-npm-package-name": "^3.0.0" + }, + "dependencies": { + "promzard": { + "version": "0.3.0", + "bundled": true, + "requires": { + "read": "1" + } + } + } + }, + "is-cidr": { + "version": "1.0.0", + "bundled": true, + "requires": { + "cidr-regex": "1.0.6" + }, + "dependencies": { + "cidr-regex": { + "version": "1.0.6", + "bundled": true + } + } + }, + "json-parse-better-errors": { + "version": "1.0.2", + "bundled": true + }, + "lazy-property": { + "version": "1.0.0", + "bundled": true + }, + "libcipm": { + "version": "1.6.2", + "bundled": true, + "requires": { + "bin-links": "^1.1.0", + "bluebird": "^3.5.1", + "find-npm-prefix": "^1.0.2", + "graceful-fs": "^4.1.11", + "lock-verify": "^2.0.0", + "npm-lifecycle": "^2.0.0", + "npm-logical-tree": "^1.2.1", + "npm-package-arg": "^6.0.0", + "pacote": "^7.5.1", + "protoduck": "^5.0.0", + "read-package-json": "^2.0.12", + "rimraf": "^2.6.2", + "worker-farm": "^1.5.4" + }, + "dependencies": { + "lock-verify": { + "version": "2.0.1", + "bundled": true, + "requires": { + "npm-package-arg": "^5.1.2", + "semver": "^5.4.1" + }, + "dependencies": { + "npm-package-arg": { + "version": "5.1.2", + "bundled": true, + "requires": { + "hosted-git-info": "^2.4.2", + "osenv": "^0.1.4", + "semver": "^5.1.0", + "validate-npm-package-name": "^3.0.0" + } + } + } + }, + "npm-logical-tree": { + "version": "1.2.1", + "bundled": true + }, + "protoduck": { + "version": "5.0.0", + "bundled": true, + "requires": { + "genfun": "^4.0.1" + }, + "dependencies": { + "genfun": { + "version": "4.0.1", + "bundled": true + } + } + } + } + }, + "libnpx": { + "version": "10.2.0", + "bundled": true, + "requires": { + "dotenv": "^5.0.1", + "npm-package-arg": "^6.0.0", + "rimraf": "^2.6.2", + "safe-buffer": "^5.1.0", + "update-notifier": "^2.3.0", + "which": "^1.3.0", + "y18n": "^4.0.0", + "yargs": "^11.0.0" + }, + "dependencies": { + "dotenv": { + "version": "5.0.1", + "bundled": true + }, + "y18n": { + "version": "4.0.0", + "bundled": true + }, + "yargs": { + "version": "11.0.0", + "bundled": true, + "requires": { + "cliui": "^4.0.0", + "decamelize": "^1.1.1", + "find-up": "^2.1.0", + "get-caller-file": "^1.0.1", + "os-locale": "^2.0.0", + "require-directory": "^2.1.1", + "require-main-filename": "^1.0.1", + "set-blocking": "^2.0.0", + "string-width": "^2.0.0", + "which-module": "^2.0.0", + "y18n": "^3.2.1", + "yargs-parser": "^9.0.2" + }, + "dependencies": { + "cliui": { + "version": "4.1.0", + "bundled": true, + "requires": { + "string-width": "^2.1.1", + "strip-ansi": "^4.0.0", + "wrap-ansi": "^2.0.0" + }, + "dependencies": { + "wrap-ansi": { + "version": "2.1.0", + "bundled": true, + "requires": { + "string-width": "^1.0.1", + "strip-ansi": "^3.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 + } + } + } + } + } + } + }, + "decamelize": { + "version": "1.2.0", + "bundled": true + }, + "find-up": { + "version": "2.1.0", + "bundled": true, + "requires": { + "locate-path": "^2.0.0" + }, + "dependencies": { + "locate-path": { + "version": "2.0.0", + "bundled": true, + "requires": { + "p-locate": "^2.0.0", + "path-exists": "^3.0.0" + }, + "dependencies": { + "p-locate": { + "version": "2.0.0", + "bundled": true, + "requires": { + "p-limit": "^1.1.0" + }, + "dependencies": { + "p-limit": { + "version": "1.2.0", + "bundled": true, + "requires": { + "p-try": "^1.0.0" + }, + "dependencies": { + "p-try": { + "version": "1.0.0", + "bundled": true + } + } + } + } + }, + "path-exists": { + "version": "3.0.0", + "bundled": true + } + } + } + } + }, + "get-caller-file": { + "version": "1.0.2", + "bundled": true + }, + "os-locale": { + "version": "2.1.0", + "bundled": true, + "requires": { + "execa": "^0.7.0", + "lcid": "^1.0.0", + "mem": "^1.1.0" + }, + "dependencies": { + "execa": { + "version": "0.7.0", + "bundled": true, + "requires": { + "cross-spawn": "^5.0.1", + "get-stream": "^3.0.0", + "is-stream": "^1.1.0", + "npm-run-path": "^2.0.0", + "p-finally": "^1.0.0", + "signal-exit": "^3.0.0", + "strip-eof": "^1.0.0" + }, + "dependencies": { + "cross-spawn": { + "version": "5.1.0", + "bundled": true, + "requires": { + "lru-cache": "^4.0.1", + "shebang-command": "^1.2.0", + "which": "^1.2.9" + }, + "dependencies": { + "shebang-command": { + "version": "1.2.0", + "bundled": true, + "requires": { + "shebang-regex": "^1.0.0" + }, + "dependencies": { + "shebang-regex": { + "version": "1.0.0", + "bundled": true + } + } + } + } + }, + "get-stream": { + "version": "3.0.0", + "bundled": true + }, + "is-stream": { + "version": "1.1.0", + "bundled": true + }, + "npm-run-path": { + "version": "2.0.2", + "bundled": true, + "requires": { + "path-key": "^2.0.0" + }, + "dependencies": { + "path-key": { + "version": "2.0.1", + "bundled": true + } + } + }, + "p-finally": { + "version": "1.0.0", + "bundled": true + }, + "signal-exit": { + "version": "3.0.2", + "bundled": true + }, + "strip-eof": { + "version": "1.0.0", + "bundled": true + } + } + }, + "lcid": { + "version": "1.0.0", + "bundled": true, + "requires": { + "invert-kv": "^1.0.0" + }, + "dependencies": { + "invert-kv": { + "version": "1.0.0", + "bundled": true + } + } + }, + "mem": { + "version": "1.1.0", + "bundled": true, + "requires": { + "mimic-fn": "^1.0.0" + }, + "dependencies": { + "mimic-fn": { + "version": "1.2.0", + "bundled": true + } + } + } + } + }, + "require-directory": { + "version": "2.1.1", + "bundled": true + }, + "require-main-filename": { + "version": "1.0.1", + "bundled": true + }, + "set-blocking": { + "version": "2.0.0", + "bundled": true + }, + "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 + } + } + }, + "which-module": { + "version": "2.0.0", + "bundled": true + }, + "y18n": { + "version": "3.2.1", + "bundled": true + }, + "yargs-parser": { + "version": "9.0.2", + "bundled": true, + "requires": { + "camelcase": "^4.1.0" + }, + "dependencies": { + "camelcase": { + "version": "4.1.0", + "bundled": true + } + } + } + } + } + } + }, + "lock-verify": { + "version": "2.0.2", + "bundled": true, + "requires": { + "npm-package-arg": "^5.1.2 || 6", + "semver": "^5.4.1" + } + }, + "lockfile": { + "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", + "bundled": true + }, + "lodash._baseuniq": { + "version": "4.6.0", + "bundled": true, + "requires": { + "lodash._createset": "~4.0.0", + "lodash._root": "~3.0.0" + }, + "dependencies": { + "lodash._createset": { + "version": "4.0.3", + "bundled": true + }, + "lodash._root": { + "version": "3.0.1", + "bundled": true + } + } + }, + "lodash._bindcallback": { + "version": "3.0.1", + "bundled": true + }, + "lodash._cacheindexof": { + "version": "3.0.2", + "bundled": true + }, + "lodash._createcache": { + "version": "3.1.2", + "bundled": true, + "requires": { + "lodash._getnative": "^3.0.0" + } + }, + "lodash._getnative": { + "version": "3.9.1", + "bundled": true + }, + "lodash.clonedeep": { + "version": "4.5.0", + "bundled": true + }, + "lodash.restparam": { + "version": "3.6.1", + "bundled": true + }, + "lodash.union": { + "version": "4.6.0", + "bundled": true + }, + "lodash.uniq": { + "version": "4.5.0", + "bundled": true + }, + "lodash.without": { + "version": "4.4.0", + "bundled": true + }, + "lru-cache": { + "version": "4.1.2", + "bundled": true, + "requires": { + "pseudomap": "^1.0.2", + "yallist": "^2.1.2" + }, + "dependencies": { + "pseudomap": { + "version": "1.0.2", + "bundled": true + }, + "yallist": { + "version": "2.1.2", + "bundled": true + } + } + }, + "meant": { + "version": "1.0.1", + "bundled": true + }, + "mississippi": { + "version": "3.0.0", + "bundled": true, + "requires": { + "concat-stream": "^1.5.0", + "duplexify": "^3.4.2", + "end-of-stream": "^1.1.0", + "flush-write-stream": "^1.0.0", + "from2": "^2.1.0", + "parallel-transform": "^1.1.0", + "pump": "^3.0.0", + "pumpify": "^1.3.3", + "stream-each": "^1.1.0", + "through2": "^2.0.0" + }, + "dependencies": { + "concat-stream": { + "version": "1.6.1", + "bundled": true, + "requires": { + "inherits": "^2.0.3", + "readable-stream": "^2.2.2", + "typedarray": "^0.0.6" + }, + "dependencies": { + "typedarray": { + "version": "0.0.6", + "bundled": true + } + } + }, + "duplexify": { + "version": "3.5.4", + "bundled": true, + "requires": { + "end-of-stream": "^1.0.0", + "inherits": "^2.0.1", + "readable-stream": "^2.0.0", + "stream-shift": "^1.0.0" + }, + "dependencies": { + "stream-shift": { + "version": "1.0.0", + "bundled": true + } + } + }, + "end-of-stream": { + "version": "1.4.1", + "bundled": true, + "requires": { + "once": "^1.4.0" + } + }, + "flush-write-stream": { + "version": "1.0.2", + "bundled": true, + "requires": { + "inherits": "^2.0.1", + "readable-stream": "^2.0.4" + } + }, + "from2": { + "version": "2.3.0", + "bundled": true, + "requires": { + "inherits": "^2.0.1", + "readable-stream": "^2.0.0" + } + }, + "parallel-transform": { + "version": "1.1.0", + "bundled": true, + "requires": { + "cyclist": "~0.2.2", + "inherits": "^2.0.3", + "readable-stream": "^2.1.5" + }, + "dependencies": { + "cyclist": { + "version": "0.2.2", + "bundled": true + } + } + }, + "pump": { + "version": "3.0.0", + "bundled": true, + "requires": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } + }, + "pumpify": { + "version": "1.4.0", + "bundled": true, + "requires": { + "duplexify": "^3.5.3", + "inherits": "^2.0.3", + "pump": "^2.0.0" + }, + "dependencies": { + "pump": { + "version": "2.0.1", + "bundled": true, + "requires": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } + } + } + }, + "stream-each": { + "version": "1.2.2", + "bundled": true, + "requires": { + "end-of-stream": "^1.1.0", + "stream-shift": "^1.0.0" + }, + "dependencies": { + "stream-shift": { + "version": "1.0.0", + "bundled": true + } + } + }, + "through2": { + "version": "2.0.3", + "bundled": true, + "requires": { + "readable-stream": "^2.1.5", + "xtend": "~4.0.1" + }, + "dependencies": { + "xtend": { + "version": "4.0.1", + "bundled": true + } + } + } + } + }, + "mkdirp": { + "version": "0.5.1", + "bundled": true, + "requires": { + "minimist": "0.0.8" + }, + "dependencies": { + "minimist": { + "version": "0.0.8", + "bundled": true + } + } + }, + "move-concurrently": { + "version": "1.0.1", + "bundled": true, + "requires": { + "aproba": "^1.1.1", + "copy-concurrently": "^1.0.0", + "fs-write-stream-atomic": "^1.0.8", + "mkdirp": "^0.5.1", + "rimraf": "^2.5.4", + "run-queue": "^1.0.3" + }, + "dependencies": { + "copy-concurrently": { + "version": "1.0.5", + "bundled": true, + "requires": { + "aproba": "^1.1.1", + "fs-write-stream-atomic": "^1.0.8", + "iferr": "^0.1.5", + "mkdirp": "^0.5.1", + "rimraf": "^2.5.4", + "run-queue": "^1.0.0" + } + }, + "run-queue": { + "version": "1.0.3", + "bundled": true, + "requires": { + "aproba": "^1.1.1" + } + } + } + }, + "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, + "requires": { + "abbrev": "1", + "osenv": "^0.1.4" + } + }, + "normalize-package-data": { + "version": "2.4.0", + "bundled": true, + "requires": { + "hosted-git-info": "^2.1.4", + "is-builtin-module": "^1.0.0", + "semver": "2 || 3 || 4 || 5", + "validate-npm-package-license": "^3.0.1" + }, + "dependencies": { + "is-builtin-module": { + "version": "1.0.0", + "bundled": true, + "requires": { + "builtin-modules": "^1.0.0" + }, + "dependencies": { + "builtin-modules": { + "version": "1.1.1", + "bundled": true + } + } + } + } + }, + "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 + }, + "npm-install-checks": { + "version": "3.0.0", + "bundled": true, + "requires": { + "semver": "^2.3.0 || 3.x || 4 || 5" + } + }, + "npm-lifecycle": { + "version": "2.0.1", + "bundled": true, + "requires": { + "byline": "^5.0.0", + "graceful-fs": "^4.1.11", + "node-gyp": "^3.6.2", + "resolve-from": "^4.0.0", + "slide": "^1.1.6", + "uid-number": "0.0.6", + "umask": "^1.1.0", + "which": "^1.3.0" + }, + "dependencies": { + "byline": { + "version": "5.0.0", + "bundled": true + }, + "resolve-from": { + "version": "4.0.0", + "bundled": true + } + } + }, + "npm-package-arg": { + "version": "6.1.0", + "bundled": true, + "requires": { + "hosted-git-info": "^2.6.0", + "osenv": "^0.1.5", + "semver": "^5.5.0", + "validate-npm-package-name": "^3.0.0" + } + }, + "npm-packlist": { + "version": "1.1.10", + "bundled": true, + "requires": { + "ignore-walk": "^3.0.1", + "npm-bundled": "^1.0.1" + }, + "dependencies": { + "ignore-walk": { + "version": "3.0.1", + "bundled": true, + "requires": { + "minimatch": "^3.0.4" + }, + "dependencies": { + "minimatch": { + "version": "3.0.4", + "bundled": true, + "requires": { + "brace-expansion": "^1.1.7" + }, + "dependencies": { + "brace-expansion": { + "version": "1.1.8", + "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 + } + } + } + } + } + } + }, + "npm-bundled": { + "version": "1.0.3", + "bundled": true + } + } + }, + "npm-profile": { + "version": "3.0.1", + "bundled": true, + "requires": { + "aproba": "^1.1.2", + "make-fetch-happen": "^2.5.0" + }, + "dependencies": { + "make-fetch-happen": { + "version": "2.6.0", + "bundled": true, + "requires": { + "agentkeepalive": "^3.3.0", + "cacache": "^10.0.0", + "http-cache-semantics": "^3.8.0", + "http-proxy-agent": "^2.0.0", + "https-proxy-agent": "^2.1.0", + "lru-cache": "^4.1.1", + "mississippi": "^1.2.0", + "node-fetch-npm": "^2.0.2", + "promise-retry": "^1.1.1", + "socks-proxy-agent": "^3.0.1", + "ssri": "^5.0.0" + }, + "dependencies": { + "agentkeepalive": { + "version": "3.3.0", + "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.0.0", + "bundled": true, + "requires": { + "agent-base": "4", + "debug": "2" + }, + "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": "2.6.9", + "bundled": true, + "requires": { + "ms": "2.0.0" + }, + "dependencies": { + "ms": { + "version": "2.0.0", + "bundled": true + } + } + } + } + }, + "https-proxy-agent": { + "version": "2.1.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 + } + } + } + } + }, + "mississippi": { + "version": "1.3.1", + "bundled": true, + "requires": { + "concat-stream": "^1.5.0", + "duplexify": "^3.4.2", + "end-of-stream": "^1.1.0", + "flush-write-stream": "^1.0.0", + "from2": "^2.1.0", + "parallel-transform": "^1.1.0", + "pump": "^1.0.0", + "pumpify": "^1.3.3", + "stream-each": "^1.1.0", + "through2": "^2.0.0" + }, + "dependencies": { + "concat-stream": { + "version": "1.6.0", + "bundled": true, + "requires": { + "inherits": "^2.0.3", + "readable-stream": "^2.2.2", + "typedarray": "^0.0.6" + }, + "dependencies": { + "typedarray": { + "version": "0.0.6", + "bundled": true + } + } + }, + "duplexify": { + "version": "3.5.3", + "bundled": true, + "requires": { + "end-of-stream": "^1.0.0", + "inherits": "^2.0.1", + "readable-stream": "^2.0.0", + "stream-shift": "^1.0.0" + }, + "dependencies": { + "stream-shift": { + "version": "1.0.0", + "bundled": true + } + } + }, + "end-of-stream": { + "version": "1.4.1", + "bundled": true, + "requires": { + "once": "^1.4.0" + } + }, + "flush-write-stream": { + "version": "1.0.2", + "bundled": true, + "requires": { + "inherits": "^2.0.1", + "readable-stream": "^2.0.4" + } + }, + "from2": { + "version": "2.3.0", + "bundled": true, + "requires": { + "inherits": "^2.0.1", + "readable-stream": "^2.0.0" + } + }, + "parallel-transform": { + "version": "1.1.0", + "bundled": true, + "requires": { + "cyclist": "~0.2.2", + "inherits": "^2.0.3", + "readable-stream": "^2.1.5" + }, + "dependencies": { + "cyclist": { + "version": "0.2.2", + "bundled": true + } + } + }, + "pump": { + "version": "1.0.3", + "bundled": true, + "requires": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } + }, + "pumpify": { + "version": "1.4.0", + "bundled": true, + "requires": { + "duplexify": "^3.5.3", + "inherits": "^2.0.3", + "pump": "^2.0.0" + }, + "dependencies": { + "pump": { + "version": "2.0.1", + "bundled": true, + "requires": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } + } + } + }, + "stream-each": { + "version": "1.2.2", + "bundled": true, + "requires": { + "end-of-stream": "^1.1.0", + "stream-shift": "^1.0.0" + }, + "dependencies": { + "stream-shift": { + "version": "1.0.0", + "bundled": true + } + } + }, + "through2": { + "version": "2.0.3", + "bundled": true, + "requires": { + "readable-stream": "^2.1.5", + "xtend": "~4.0.1" + }, + "dependencies": { + "xtend": { + "version": "4.0.1", + "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.19", + "bundled": true + } + } + }, + "json-parse-better-errors": { + "version": "1.0.1", + "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 + } + } + } + } + } + } + } + } + }, + "npm-registry-client": { + "version": "8.5.1", + "bundled": true, + "requires": { + "concat-stream": "^1.5.2", + "graceful-fs": "^4.1.6", + "normalize-package-data": "~1.0.1 || ^2.0.0", + "npm-package-arg": "^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0", + "npmlog": "2 || ^3.1.0 || ^4.0.0", + "once": "^1.3.3", + "request": "^2.74.0", + "retry": "^0.10.0", + "safe-buffer": "^5.1.1", + "semver": "2 >=2.2.1 || 3.x || 4 || 5", + "slide": "^1.1.3", + "ssri": "^5.2.4" + }, + "dependencies": { + "concat-stream": { + "version": "1.6.1", + "bundled": true, + "requires": { + "inherits": "^2.0.3", + "readable-stream": "^2.2.2", + "typedarray": "^0.0.6" + }, + "dependencies": { + "typedarray": { + "version": "0.0.6", + "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 + } + } + } + } + } + } + } + } + }, + "npm-user-validate": { + "version": "1.0.0", + "bundled": true + }, + "npmlog": { + "version": "4.1.2", + "bundled": true, + "requires": { + "are-we-there-yet": "~1.1.2", + "console-control-strings": "~1.1.0", + "gauge": "~2.7.3", + "set-blocking": "~2.0.0" + }, + "dependencies": { + "are-we-there-yet": { + "version": "1.1.4", + "bundled": true, + "requires": { + "delegates": "^1.0.0", + "readable-stream": "^2.0.6" + }, + "dependencies": { + "delegates": { + "version": "1.0.0", + "bundled": true + } + } + }, + "console-control-strings": { + "version": "1.1.0", + "bundled": true + }, + "gauge": { + "version": "2.7.4", + "bundled": true, + "requires": { + "aproba": "^1.0.3", + "console-control-strings": "^1.0.0", + "has-unicode": "^2.0.0", + "object-assign": "^4.1.0", + "signal-exit": "^3.0.0", + "string-width": "^1.0.1", + "strip-ansi": "^3.0.1", + "wide-align": "^1.1.0" + }, + "dependencies": { + "object-assign": { + "version": "4.1.1", + "bundled": true + }, + "signal-exit": { + "version": "3.0.2", + "bundled": true + }, + "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 + } + } + }, + "wide-align": { + "version": "1.1.2", + "bundled": true, + "requires": { + "string-width": "^1.0.2" + } + } + } + }, + "set-blocking": { + "version": "2.0.0", + "bundled": true + } + } + }, + "once": { + "version": "1.4.0", + "bundled": true, + "requires": { + "wrappy": "1" + } + }, + "opener": { + "version": "1.4.3", + "bundled": true + }, + "osenv": { + "version": "0.1.5", + "bundled": true, + "requires": { + "os-homedir": "^1.0.0", + "os-tmpdir": "^1.0.0" + }, + "dependencies": { + "os-homedir": { + "version": "1.0.2", + "bundled": true + }, + "os-tmpdir": { + "version": "1.0.2", + "bundled": true + } + } + }, + "pacote": { + "version": "7.6.1", + "bundled": true, + "requires": { + "bluebird": "^3.5.1", + "cacache": "^10.0.4", + "get-stream": "^3.0.0", + "glob": "^7.1.2", + "lru-cache": "^4.1.1", + "make-fetch-happen": "^2.6.0", + "minimatch": "^3.0.4", + "mississippi": "^3.0.0", + "mkdirp": "^0.5.1", + "normalize-package-data": "^2.4.0", + "npm-package-arg": "^6.0.0", + "npm-packlist": "^1.1.10", + "npm-pick-manifest": "^2.1.0", + "osenv": "^0.1.5", + "promise-inflight": "^1.0.1", + "promise-retry": "^1.1.1", + "protoduck": "^5.0.0", + "rimraf": "^2.6.2", + "safe-buffer": "^5.1.1", + "semver": "^5.5.0", + "ssri": "^5.2.4", + "tar": "^4.4.0", + "unique-filename": "^1.1.0", + "which": "^1.3.0" + }, + "dependencies": { + "get-stream": { + "version": "3.0.0", + "bundled": true + }, + "make-fetch-happen": { + "version": "2.6.0", + "bundled": true, + "requires": { + "agentkeepalive": "^3.3.0", + "cacache": "^10.0.0", + "http-cache-semantics": "^3.8.0", + "http-proxy-agent": "^2.0.0", + "https-proxy-agent": "^2.1.0", + "lru-cache": "^4.1.1", + "mississippi": "^1.2.0", + "node-fetch-npm": "^2.0.2", + "promise-retry": "^1.1.1", + "socks-proxy-agent": "^3.0.1", + "ssri": "^5.0.0" + }, + "dependencies": { + "agentkeepalive": { + "version": "3.4.0", + "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.0", + "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 + } + } + } + } + }, + "mississippi": { + "version": "1.3.1", + "bundled": true, + "requires": { + "concat-stream": "^1.5.0", + "duplexify": "^3.4.2", + "end-of-stream": "^1.1.0", + "flush-write-stream": "^1.0.0", + "from2": "^2.1.0", + "parallel-transform": "^1.1.0", + "pump": "^1.0.0", + "pumpify": "^1.3.3", + "stream-each": "^1.1.0", + "through2": "^2.0.0" + }, + "dependencies": { + "concat-stream": { + "version": "1.6.1", + "bundled": true, + "requires": { + "inherits": "^2.0.3", + "readable-stream": "^2.2.2", + "typedarray": "^0.0.6" + }, + "dependencies": { + "typedarray": { + "version": "0.0.6", + "bundled": true + } + } + }, + "duplexify": { + "version": "3.5.4", + "bundled": true, + "requires": { + "end-of-stream": "^1.0.0", + "inherits": "^2.0.1", + "readable-stream": "^2.0.0", + "stream-shift": "^1.0.0" + }, + "dependencies": { + "stream-shift": { + "version": "1.0.0", + "bundled": true + } + } + }, + "end-of-stream": { + "version": "1.4.1", + "bundled": true, + "requires": { + "once": "^1.4.0" + } + }, + "flush-write-stream": { + "version": "1.0.2", + "bundled": true, + "requires": { + "inherits": "^2.0.1", + "readable-stream": "^2.0.4" + } + }, + "from2": { + "version": "2.3.0", + "bundled": true, + "requires": { + "inherits": "^2.0.1", + "readable-stream": "^2.0.0" + } + }, + "parallel-transform": { + "version": "1.1.0", + "bundled": true, + "requires": { + "cyclist": "~0.2.2", + "inherits": "^2.0.3", + "readable-stream": "^2.1.5" + }, + "dependencies": { + "cyclist": { + "version": "0.2.2", + "bundled": true + } + } + }, + "pump": { + "version": "1.0.3", + "bundled": true, + "requires": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } + }, + "pumpify": { + "version": "1.4.0", + "bundled": true, + "requires": { + "duplexify": "^3.5.3", + "inherits": "^2.0.3", + "pump": "^2.0.0" + }, + "dependencies": { + "pump": { + "version": "2.0.1", + "bundled": true, + "requires": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } + } + } + }, + "stream-each": { + "version": "1.2.2", + "bundled": true, + "requires": { + "end-of-stream": "^1.1.0", + "stream-shift": "^1.0.0" + }, + "dependencies": { + "stream-shift": { + "version": "1.0.0", + "bundled": true + } + } + }, + "through2": { + "version": "2.0.3", + "bundled": true, + "requires": { + "readable-stream": "^2.1.5", + "xtend": "~4.0.1" + }, + "dependencies": { + "xtend": { + "version": "4.0.1", + "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.19", + "bundled": true + } + } + }, + "json-parse-better-errors": { + "version": "1.0.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 + } + } + } + } + } + } + }, + "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 + } + } + } + } + }, + "npm-pick-manifest": { + "version": "2.1.0", + "bundled": true, + "requires": { + "npm-package-arg": "^6.0.0", + "semver": "^5.4.1" + } + }, + "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 + } + } + }, + "protoduck": { + "version": "5.0.0", + "bundled": true, + "requires": { + "genfun": "^4.0.1" + }, + "dependencies": { + "genfun": { + "version": "4.0.1", + "bundled": true + } + } + } + } + }, + "path-is-inside": { + "version": "1.0.2", + "bundled": true + }, + "promise-inflight": { + "version": "1.0.1", + "bundled": true + }, + "qrcode-terminal": { + "version": "0.12.0", + "bundled": true + }, + "query-string": { + "version": "6.1.0", + "bundled": true, + "requires": { + "decode-uri-component": "^0.2.0", + "strict-uri-encode": "^2.0.0" + }, + "dependencies": { + "decode-uri-component": { + "version": "0.2.0", + "bundled": true + }, + "strict-uri-encode": { + "version": "2.0.0", + "bundled": true + } + } + }, + "qw": { + "version": "1.0.1", + "bundled": true + }, + "read": { + "version": "1.0.7", + "bundled": true, + "requires": { + "mute-stream": "~0.0.4" + }, + "dependencies": { + "mute-stream": { + "version": "0.0.7", + "bundled": true + } + } + }, + "read-cmd-shim": { + "version": "1.0.1", + "bundled": true, + "requires": { + "graceful-fs": "^4.1.2" + } + }, + "read-installed": { + "version": "4.0.3", + "bundled": true, + "requires": { + "debuglog": "^1.0.1", + "graceful-fs": "^4.1.2", + "read-package-json": "^2.0.0", + "readdir-scoped-modules": "^1.0.0", + "semver": "2 || 3 || 4 || 5", + "slide": "~1.1.3", + "util-extend": "^1.0.1" + }, + "dependencies": { + "util-extend": { + "version": "1.0.3", + "bundled": true + } + } + }, + "read-package-json": { + "version": "2.0.13", + "bundled": true, + "requires": { + "glob": "^7.1.1", + "graceful-fs": "^4.1.2", + "json-parse-better-errors": "^1.0.1", + "normalize-package-data": "^2.0.0", + "slash": "^1.0.0" + }, + "dependencies": { + "json-parse-better-errors": { + "version": "1.0.1", + "bundled": true + }, + "slash": { + "version": "1.0.0", + "bundled": true + } + } + }, + "read-package-tree": { + "version": "5.2.1", + "bundled": true, + "requires": { + "debuglog": "^1.0.1", + "dezalgo": "^1.0.0", + "once": "^1.3.0", + "read-package-json": "^2.0.0", + "readdir-scoped-modules": "^1.0.0" + } + }, + "readable-stream": { + "version": "2.3.6", + "bundled": true, + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + }, + "dependencies": { + "core-util-is": { + "version": "1.0.2", + "bundled": true + }, + "isarray": { + "version": "1.0.0", + "bundled": true + }, + "process-nextick-args": { + "version": "2.0.0", + "bundled": true + }, + "string_decoder": { + "version": "1.1.1", + "bundled": true, + "requires": { + "safe-buffer": "~5.1.0" + } + }, + "util-deprecate": { + "version": "1.0.2", + "bundled": true + } + } + }, + "readdir-scoped-modules": { + "version": "1.0.2", + "bundled": true, + "requires": { + "debuglog": "^1.0.1", + "dezalgo": "^1.0.0", + "graceful-fs": "^4.1.2", + "once": "^1.3.0" + } + }, + "request": { + "version": "2.85.0", + "bundled": true, + "requires": { + "aws-sign2": "~0.7.0", + "aws4": "^1.6.0", + "caseless": "~0.12.0", + "combined-stream": "~1.0.5", + "extend": "~3.0.1", + "forever-agent": "~0.6.1", + "form-data": "~2.3.1", + "har-validator": "~5.0.3", + "hawk": "~6.0.2", + "http-signature": "~1.2.0", + "is-typedarray": "~1.0.0", + "isstream": "~0.1.2", + "json-stringify-safe": "~5.0.1", + "mime-types": "~2.1.17", + "oauth-sign": "~0.8.2", + "performance-now": "^2.1.0", + "qs": "~6.5.1", + "safe-buffer": "^5.1.1", + "stringstream": "~0.0.5", + "tough-cookie": "~2.3.3", + "tunnel-agent": "^0.6.0", + "uuid": "^3.1.0" + }, + "dependencies": { + "aws-sign2": { + "version": "0.7.0", + "bundled": true + }, + "aws4": { + "version": "1.6.0", + "bundled": true + }, + "caseless": { + "version": "0.12.0", + "bundled": true + }, + "combined-stream": { + "version": "1.0.6", + "bundled": true, + "requires": { + "delayed-stream": "~1.0.0" + }, + "dependencies": { + "delayed-stream": { + "version": "1.0.0", + "bundled": true + } + } + }, + "extend": { + "version": "3.0.1", + "bundled": true + }, + "forever-agent": { + "version": "0.6.1", + "bundled": true + }, + "form-data": { + "version": "2.3.2", + "bundled": true, + "requires": { + "asynckit": "^0.4.0", + "combined-stream": "1.0.6", + "mime-types": "^2.1.12" + }, + "dependencies": { + "asynckit": { + "version": "0.4.0", + "bundled": true + } + } + }, + "har-validator": { + "version": "5.0.3", + "bundled": true, + "requires": { + "ajv": "^5.1.0", + "har-schema": "^2.0.0" + }, + "dependencies": { + "ajv": { + "version": "5.5.2", + "bundled": true, + "requires": { + "co": "^4.6.0", + "fast-deep-equal": "^1.0.0", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.3.0" + }, + "dependencies": { + "co": { + "version": "4.6.0", + "bundled": true + }, + "fast-deep-equal": { + "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 + } + } + }, + "har-schema": { + "version": "2.0.0", + "bundled": true + } + } + }, + "hawk": { + "version": "6.0.2", + "bundled": true, + "requires": { + "boom": "4.x.x", + "cryptiles": "3.x.x", + "hoek": "4.x.x", + "sntp": "2.x.x" + }, + "dependencies": { + "boom": { + "version": "4.3.1", + "bundled": true, + "requires": { + "hoek": "4.x.x" + } + }, + "cryptiles": { + "version": "3.1.2", + "bundled": true, + "requires": { + "boom": "5.x.x" + }, + "dependencies": { + "boom": { + "version": "5.2.0", + "bundled": true, + "requires": { + "hoek": "4.x.x" + } + } + } + }, + "hoek": { + "version": "4.2.1", + "bundled": true + }, + "sntp": { + "version": "2.1.0", + "bundled": true, + "requires": { + "hoek": "4.x.x" + } + } + } + }, + "http-signature": { + "version": "1.2.0", + "bundled": true, + "requires": { + "assert-plus": "^1.0.0", + "jsprim": "^1.2.2", + "sshpk": "^1.7.0" + }, + "dependencies": { + "assert-plus": { + "version": "1.0.0", + "bundled": true + }, + "jsprim": { + "version": "1.4.1", + "bundled": true, + "requires": { + "assert-plus": "1.0.0", + "extsprintf": "1.3.0", + "json-schema": "0.2.3", + "verror": "1.10.0" + }, + "dependencies": { + "extsprintf": { + "version": "1.3.0", + "bundled": true + }, + "json-schema": { + "version": "0.2.3", + "bundled": true + }, + "verror": { + "version": "1.10.0", + "bundled": true, + "requires": { + "assert-plus": "^1.0.0", + "core-util-is": "1.0.2", + "extsprintf": "^1.2.0" + }, + "dependencies": { + "core-util-is": { + "version": "1.0.2", + "bundled": true + } + } + } + } + }, + "sshpk": { + "version": "1.14.1", + "bundled": true, + "requires": { + "asn1": "~0.2.3", + "assert-plus": "^1.0.0", + "bcrypt-pbkdf": "^1.0.0", + "dashdash": "^1.12.0", + "ecc-jsbn": "~0.1.1", + "getpass": "^0.1.1", + "jsbn": "~0.1.0", + "tweetnacl": "~0.14.0" + }, + "dependencies": { + "asn1": { + "version": "0.2.3", + "bundled": true + }, + "bcrypt-pbkdf": { + "version": "1.0.1", + "bundled": true, + "optional": true, + "requires": { + "tweetnacl": "^0.14.3" + } + }, + "dashdash": { + "version": "1.14.1", + "bundled": true, + "requires": { + "assert-plus": "^1.0.0" + } + }, + "ecc-jsbn": { + "version": "0.1.1", + "bundled": true, + "optional": true, + "requires": { + "jsbn": "~0.1.0" + } + }, + "getpass": { + "version": "0.1.7", + "bundled": true, + "requires": { + "assert-plus": "^1.0.0" + } + }, + "jsbn": { + "version": "0.1.1", + "bundled": true, + "optional": true + }, + "tweetnacl": { + "version": "0.14.5", + "bundled": true, + "optional": true + } + } + } + } + }, + "is-typedarray": { + "version": "1.0.0", + "bundled": true + }, + "isstream": { + "version": "0.1.2", + "bundled": true + }, + "json-stringify-safe": { + "version": "5.0.1", + "bundled": true + }, + "mime-types": { + "version": "2.1.18", + "bundled": true, + "requires": { + "mime-db": "~1.33.0" + }, + "dependencies": { + "mime-db": { + "version": "1.33.0", + "bundled": true + } + } + }, + "oauth-sign": { + "version": "0.8.2", + "bundled": true + }, + "performance-now": { + "version": "2.1.0", + "bundled": true + }, + "qs": { + "version": "6.5.1", + "bundled": true + }, + "stringstream": { + "version": "0.0.5", + "bundled": true + }, + "tough-cookie": { + "version": "2.3.4", + "bundled": true, + "requires": { + "punycode": "^1.4.1" + }, + "dependencies": { + "punycode": { + "version": "1.4.1", + "bundled": true + } + } + }, + "tunnel-agent": { + "version": "0.6.0", + "bundled": true, + "requires": { + "safe-buffer": "^5.0.1" + } + } + } + }, + "retry": { + "version": "0.12.0", + "bundled": true + }, + "rimraf": { + "version": "2.6.2", + "bundled": true, + "requires": { + "glob": "^7.0.5" + } + }, + "safe-buffer": { + "version": "5.1.2", + "bundled": true + }, + "semver": { + "version": "5.5.0", + "bundled": true + }, + "sha": { + "version": "2.0.1", + "bundled": true, + "requires": { + "graceful-fs": "^4.1.2", + "readable-stream": "^2.0.2" + } + }, + "slide": { + "version": "1.1.6", + "bundled": true + }, + "sorted-object": { + "version": "2.0.1", + "bundled": true + }, + "sorted-union-stream": { + "version": "2.1.3", + "bundled": true, + "requires": { + "from2": "^1.3.0", + "stream-iterate": "^1.1.0" + }, + "dependencies": { + "from2": { + "version": "1.3.0", + "bundled": true, + "requires": { + "inherits": "~2.0.1", + "readable-stream": "~1.1.10" + }, + "dependencies": { + "readable-stream": { + "version": "1.1.14", + "bundled": true, + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.1", + "isarray": "0.0.1", + "string_decoder": "~0.10.x" + }, + "dependencies": { + "core-util-is": { + "version": "1.0.2", + "bundled": true + }, + "isarray": { + "version": "0.0.1", + "bundled": true + }, + "string_decoder": { + "version": "0.10.31", + "bundled": true + } + } + } + } + }, + "stream-iterate": { + "version": "1.2.0", + "bundled": true, + "requires": { + "readable-stream": "^2.1.5", + "stream-shift": "^1.0.0" + }, + "dependencies": { + "stream-shift": { + "version": "1.0.0", + "bundled": true + } + } + } + } + }, + "ssri": { + "version": "5.3.0", + "bundled": true, + "requires": { + "safe-buffer": "^5.1.1" + } + }, + "strip-ansi": { + "version": "4.0.0", + "bundled": true, + "requires": { + "ansi-regex": "^3.0.0" + }, + "dependencies": { + "ansi-regex": { + "version": "3.0.0", + "bundled": true + } + } + }, + "tar": { + "version": "4.4.2", + "bundled": true, + "requires": { + "chownr": "^1.0.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": { + "fs-minipass": { + "version": "1.2.5", + "bundled": true, + "requires": { + "minipass": "^2.2.1" + } + }, + "minipass": { + "version": "2.2.4", + "bundled": true, + "requires": { + "safe-buffer": "^5.1.1", + "yallist": "^3.0.0" + } + }, + "minizlib": { + "version": "1.1.0", + "bundled": true, + "requires": { + "minipass": "^2.2.1" + } + }, + "safe-buffer": { + "version": "5.1.2", + "bundled": true + }, + "yallist": { + "version": "3.0.2", + "bundled": true + } + } + }, + "text-table": { + "version": "0.2.0", + "bundled": true + }, + "tiny-relative-date": { + "version": "1.3.0", + "bundled": true + }, + "uid-number": { + "version": "0.0.6", + "bundled": true + }, + "umask": { + "version": "1.1.0", + "bundled": true + }, + "unique-filename": { + "version": "1.1.0", + "bundled": true, + "requires": { + "unique-slug": "^2.0.0" + }, + "dependencies": { + "unique-slug": { + "version": "2.0.0", + "bundled": true, + "requires": { + "imurmurhash": "^0.1.4" + } + } + } + }, + "unpipe": { + "version": "1.0.0", + "bundled": true + }, + "update-notifier": { + "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", + "semver-diff": "^2.0.0", + "xdg-basedir": "^3.0.0" + }, + "dependencies": { + "boxen": { + "version": "1.3.0", + "bundled": true, + "requires": { + "ansi-align": "^2.0.0", + "camelcase": "^4.0.0", + "chalk": "^2.0.1", + "cli-boxes": "^1.0.0", + "string-width": "^2.0.0", + "term-size": "^1.2.0", + "widest-line": "^2.0.0" + }, + "dependencies": { + "ansi-align": { + "version": "2.0.0", + "bundled": true, + "requires": { + "string-width": "^2.0.0" + } + }, + "camelcase": { + "version": "4.1.0", + "bundled": true + }, + "cli-boxes": { + "version": "1.0.0", + "bundled": true + }, + "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 + } + } + }, + "term-size": { + "version": "1.2.0", + "bundled": true, + "requires": { + "execa": "^0.7.0" + }, + "dependencies": { + "execa": { + "version": "0.7.0", + "bundled": true, + "requires": { + "cross-spawn": "^5.0.1", + "get-stream": "^3.0.0", + "is-stream": "^1.1.0", + "npm-run-path": "^2.0.0", + "p-finally": "^1.0.0", + "signal-exit": "^3.0.0", + "strip-eof": "^1.0.0" + }, + "dependencies": { + "cross-spawn": { + "version": "5.1.0", + "bundled": true, + "requires": { + "lru-cache": "^4.0.1", + "shebang-command": "^1.2.0", + "which": "^1.2.9" + }, + "dependencies": { + "shebang-command": { + "version": "1.2.0", + "bundled": true, + "requires": { + "shebang-regex": "^1.0.0" + }, + "dependencies": { + "shebang-regex": { + "version": "1.0.0", + "bundled": true + } + } + } + } + }, + "get-stream": { + "version": "3.0.0", + "bundled": true + }, + "is-stream": { + "version": "1.1.0", + "bundled": true + }, + "npm-run-path": { + "version": "2.0.2", + "bundled": true, + "requires": { + "path-key": "^2.0.0" + }, + "dependencies": { + "path-key": { + "version": "2.0.1", + "bundled": true + } + } + }, + "p-finally": { + "version": "1.0.0", + "bundled": true + }, + "signal-exit": { + "version": "3.0.2", + "bundled": true + }, + "strip-eof": { + "version": "1.0.0", + "bundled": true + } + } + } + } + }, + "widest-line": { + "version": "2.0.0", + "bundled": true, + "requires": { + "string-width": "^2.1.1" + } + } + } + }, + "chalk": { + "version": "2.4.1", + "bundled": true, + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + }, + "dependencies": { + "ansi-styles": { + "version": "3.2.1", + "bundled": true, + "requires": { + "color-convert": "^1.9.0" + }, + "dependencies": { + "color-convert": { + "version": "1.9.1", + "bundled": true, + "requires": { + "color-name": "^1.1.1" + }, + "dependencies": { + "color-name": { + "version": "1.1.3", + "bundled": true + } + } + } + } + }, + "escape-string-regexp": { + "version": "1.0.5", + "bundled": true + }, + "supports-color": { + "version": "5.4.0", + "bundled": true, + "requires": { + "has-flag": "^3.0.0" + }, + "dependencies": { + "has-flag": { + "version": "3.0.0", + "bundled": true + } + } + } + } + }, + "configstore": { + "version": "3.1.2", + "bundled": true, + "requires": { + "dot-prop": "^4.1.0", + "graceful-fs": "^4.1.2", + "make-dir": "^1.0.0", + "unique-string": "^1.0.0", + "write-file-atomic": "^2.0.0", + "xdg-basedir": "^3.0.0" + }, + "dependencies": { + "dot-prop": { + "version": "4.2.0", + "bundled": true, + "requires": { + "is-obj": "^1.0.0" + }, + "dependencies": { + "is-obj": { + "version": "1.0.1", + "bundled": true + } + } + }, + "make-dir": { + "version": "1.2.0", + "bundled": true, + "requires": { + "pify": "^3.0.0" + }, + "dependencies": { + "pify": { + "version": "3.0.0", + "bundled": true + } + } + }, + "unique-string": { + "version": "1.0.0", + "bundled": true, + "requires": { + "crypto-random-string": "^1.0.0" + }, + "dependencies": { + "crypto-random-string": { + "version": "1.0.0", + "bundled": true + } + } + } + } + }, + "import-lazy": { + "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, + "requires": { + "global-dirs": "^0.1.0", + "is-path-inside": "^1.0.0" + }, + "dependencies": { + "global-dirs": { + "version": "0.1.1", + "bundled": true, + "requires": { + "ini": "^1.3.4" + } + }, + "is-path-inside": { + "version": "1.0.1", + "bundled": true, + "requires": { + "path-is-inside": "^1.0.1" + } + } + } + }, + "is-npm": { + "version": "1.0.0", + "bundled": true + }, + "latest-version": { + "version": "3.1.0", + "bundled": true, + "requires": { + "package-json": "^4.0.0" + }, + "dependencies": { + "package-json": { + "version": "4.0.1", + "bundled": true, + "requires": { + "got": "^6.7.1", + "registry-auth-token": "^3.0.1", + "registry-url": "^3.0.3", + "semver": "^5.1.0" + }, + "dependencies": { + "got": { + "version": "6.7.1", + "bundled": true, + "requires": { + "create-error-class": "^3.0.0", + "duplexer3": "^0.1.4", + "get-stream": "^3.0.0", + "is-redirect": "^1.0.0", + "is-retry-allowed": "^1.0.0", + "is-stream": "^1.0.0", + "lowercase-keys": "^1.0.0", + "safe-buffer": "^5.0.1", + "timed-out": "^4.0.0", + "unzip-response": "^2.0.1", + "url-parse-lax": "^1.0.0" + }, + "dependencies": { + "create-error-class": { + "version": "3.0.2", + "bundled": true, + "requires": { + "capture-stack-trace": "^1.0.0" + }, + "dependencies": { + "capture-stack-trace": { + "version": "1.0.0", + "bundled": true + } + } + }, + "duplexer3": { + "version": "0.1.4", + "bundled": true + }, + "get-stream": { + "version": "3.0.0", + "bundled": true + }, + "is-redirect": { + "version": "1.0.0", + "bundled": true + }, + "is-retry-allowed": { + "version": "1.1.0", + "bundled": true + }, + "is-stream": { + "version": "1.1.0", + "bundled": true + }, + "lowercase-keys": { + "version": "1.0.1", + "bundled": true + }, + "timed-out": { + "version": "4.0.1", + "bundled": true + }, + "unzip-response": { + "version": "2.0.1", + "bundled": true + }, + "url-parse-lax": { + "version": "1.0.0", + "bundled": true, + "requires": { + "prepend-http": "^1.0.1" + }, + "dependencies": { + "prepend-http": { + "version": "1.0.4", + "bundled": true + } + } + } + } + }, + "registry-auth-token": { + "version": "3.3.2", + "bundled": true, + "requires": { + "rc": "^1.1.6", + "safe-buffer": "^5.0.1" + }, + "dependencies": { + "rc": { + "version": "1.2.7", + "bundled": true, + "requires": { + "deep-extend": "^0.5.1", + "ini": "~1.3.0", + "minimist": "^1.2.0", + "strip-json-comments": "~2.0.1" + }, + "dependencies": { + "deep-extend": { + "version": "0.5.1", + "bundled": true + }, + "minimist": { + "version": "1.2.0", + "bundled": true + }, + "strip-json-comments": { + "version": "2.0.1", + "bundled": true + } + } + } + } + }, + "registry-url": { + "version": "3.1.0", + "bundled": true, + "requires": { + "rc": "^1.0.1" + }, + "dependencies": { + "rc": { + "version": "1.2.7", + "bundled": true, + "requires": { + "deep-extend": "^0.5.1", + "ini": "~1.3.0", + "minimist": "^1.2.0", + "strip-json-comments": "~2.0.1" + }, + "dependencies": { + "deep-extend": { + "version": "0.5.1", + "bundled": true + }, + "minimist": { + "version": "1.2.0", + "bundled": true + }, + "strip-json-comments": { + "version": "2.0.1", + "bundled": true + } + } + } + } + } + } + } + } + }, + "semver-diff": { + "version": "2.1.0", + "bundled": true, + "requires": { + "semver": "^5.0.3" + } + }, + "xdg-basedir": { + "version": "3.0.0", + "bundled": true + } + } + }, + "uuid": { + "version": "3.2.1", + "bundled": true + }, + "validate-npm-package-license": { + "version": "3.0.3", + "bundled": true, + "requires": { + "spdx-correct": "^3.0.0", + "spdx-expression-parse": "^3.0.0" + }, + "dependencies": { + "spdx-correct": { + "version": "3.0.0", + "bundled": true, + "requires": { + "spdx-expression-parse": "^3.0.0", + "spdx-license-ids": "^3.0.0" + }, + "dependencies": { + "spdx-license-ids": { + "version": "3.0.0", + "bundled": true + } + } + }, + "spdx-expression-parse": { + "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 + } + } + } + } + }, + "validate-npm-package-name": { + "version": "3.0.0", + "bundled": true, + "requires": { + "builtins": "^1.0.3" + }, + "dependencies": { + "builtins": { + "version": "1.0.3", + "bundled": true + } + } + }, + "which": { + "version": "1.3.0", + "bundled": true, + "requires": { + "isexe": "^2.0.0" + }, + "dependencies": { + "isexe": { + "version": "2.0.0", + "bundled": true + } + } + }, + "worker-farm": { + "version": "1.6.0", + "bundled": true, + "requires": { + "errno": "~0.1.7" + }, + "dependencies": { + "errno": { + "version": "0.1.7", + "bundled": true, + "requires": { + "prr": "~1.0.1" + }, + "dependencies": { + "prr": { + "version": "1.0.1", + "bundled": true + } + } + } + } + }, + "wrappy": { + "version": "1.0.2", + "bundled": true + }, + "write-file-atomic": { + "version": "2.3.0", + "bundled": true, + "requires": { + "graceful-fs": "^4.1.11", + "imurmurhash": "^0.1.4", + "signal-exit": "^3.0.2" + }, + "dependencies": { + "signal-exit": { + "version": "3.0.2", + "bundled": true + } + } + } + } + }, "npm-package-arg": { "version": "6.1.0", "resolved": "https://registry.npmjs.org/npm-package-arg/-/npm-package-arg-6.1.0.tgz", @@ -7769,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" @@ -7991,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", @@ -8404,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": { @@ -8919,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", @@ -9015,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", @@ -9833,9 +14213,9 @@ } }, "stream-http": { - "version": "2.8.2", - "resolved": "https://registry.npmjs.org/stream-http/-/stream-http-2.8.2.tgz", - "integrity": "sha512-QllfrBhqF1DPcz46WxKTs6Mz1Bpc+8Qm6vbqOpVav5odAXwbyzwnEczoWqtxrsmlO+cJqtPrp/8gWKWjaKLLlA==", + "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", @@ -10223,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", @@ -10349,9 +14729,9 @@ "dev": true }, "uglify-js": { - "version": "3.3.25", - "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.3.25.tgz", - "integrity": "sha512-hobogryjDV36VrLK3Y69ou4REyrTApzUblVFmdQOYRe8cYaSmFJXMb4dR9McdvYDSbeNdzUgYr2YVukJaErJcA==", + "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", @@ -10589,9 +14969,9 @@ } }, "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", @@ -10618,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": { @@ -10835,9 +15207,9 @@ } }, "webpack-bundle-analyzer": { - "version": "2.11.3", - "resolved": "https://registry.npmjs.org/webpack-bundle-analyzer/-/webpack-bundle-analyzer-2.11.3.tgz", - "integrity": "sha512-MaHZkX9mNGeJLbVT70bNfftSBBdl3w9Q1ThnrH7SESF47SollWm12MwDgjhf8C16R/Ur56PInrLYf0FJIOg24g==", + "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", @@ -11174,12 +15546,12 @@ "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": { diff --git a/package.json b/package.json index 2a19757d..db81e5da 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "fuse", - "version": "6.0.2", + "version": "6.1.0", "license": "https://themeforest.net/licenses/terms/regular", "scripts": { "ng": "ng", @@ -18,56 +18,56 @@ }, "private": true, "dependencies": { - "@agm/core": "1.0.0-beta.2", - "@angular/animations": "6.0.2", - "@angular/cdk": "6.0.2", - "@angular/common": "6.0.2", - "@angular/compiler": "6.0.2", - "@angular/core": "6.0.2", - "@angular/flex-layout": "6.0.0-beta.15", - "@angular/forms": "6.0.2", - "@angular/http": "6.0.2", - "@angular/material": "6.0.2", - "@angular/material-moment-adapter": "6.0.2", - "@angular/platform-browser": "6.0.2", - "@angular/platform-browser-dynamic": "6.0.2", - "@angular/router": "6.0.2", - "@ngrx/effects": "6.0.0-beta.3", - "@ngrx/router-store": "6.0.0-beta.3", - "@ngrx/store": "6.0.0-beta.3", - "@ngrx/store-devtools": "6.0.0-beta.3", - "@ngx-translate/core": "10.0.1", - "@swimlane/ngx-charts": "8.0.0", - "@swimlane/ngx-datatable": "12.0.0", - "@swimlane/ngx-dnd": "4.0.1", + "@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.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", + "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.3", - "ngx-color-picker": "6.1.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.3", - "@angular/compiler-cli": "6.0.2", - "@angular/language-service": "6.0.2", - "@angular-devkit/build-angular": "0.6.3", + "@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.109", "@types/node": "8.9.5", @@ -76,13 +76,13 @@ "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.2", "ts-node": "5.0.1", "tslint": "5.9.1", "typescript": "2.7.2", - "webpack-bundle-analyzer": "2.11.3" + "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 80% rename from src/app/main/toolbar/toolbar.component.html rename to src/app/layout/components/toolbar/toolbar.component.html index e39c26f2..e1eeefc1 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 @@
- +
@@ -92,11 +91,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/content/components/angular-material/angular-material.component.html b/src/app/main/angular-material-elements/angular-material-elements.component.html similarity index 76% rename from src/app/main/content/components/angular-material/angular-material.component.html rename to src/app/main/angular-material-elements/angular-material-elements.component.html index 65a705dd..8a41ed10 100644 --- a/src/app/main/content/components/angular-material/angular-material.component.html +++ b/src/app/main/angular-material-elements/angular-material-elements.component.html @@ -1,11 +1,12 @@ -
+
-
+
- home + home chevron_right Components chevron_right @@ -14,7 +15,8 @@
{{title}}
- + link Reference @@ -24,7 +26,7 @@
- +
diff --git a/src/app/main/content/components/angular-material/angular-material.component.scss b/src/app/main/angular-material-elements/angular-material-elements.component.scss similarity index 70% rename from src/app/main/content/components/angular-material/angular-material.component.scss rename to src/app/main/angular-material-elements/angular-material-elements.component.scss index bf992809..a6a83d1f 100644 --- a/src/app/main/content/components/angular-material/angular-material.component.scss +++ b/src/app/main/angular-material-elements/angular-material-elements.component.scss @@ -1,6 +1,6 @@ :host { - .angular-material-element { + .angular-material-elements { > .content { max-width: 960px; 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/content/components/angular-material/example-components.ts b/src/app/main/angular-material-elements/example-components.ts similarity index 100% rename from src/app/main/content/components/angular-material/example-components.ts rename to src/app/main/angular-material-elements/example-components.ts diff --git a/src/app/main/content/components/angular-material/example-viewer/example-viewer.html b/src/app/main/angular-material-elements/example-viewer/example-viewer.html similarity index 100% rename from src/app/main/content/components/angular-material/example-viewer/example-viewer.html rename to src/app/main/angular-material-elements/example-viewer/example-viewer.html diff --git a/src/app/main/content/components/angular-material/example-viewer/example-viewer.scss b/src/app/main/angular-material-elements/example-viewer/example-viewer.scss similarity index 96% rename from src/app/main/content/components/angular-material/example-viewer/example-viewer.scss rename to src/app/main/angular-material-elements/example-viewer/example-viewer.scss index 90324b70..096de499 100644 --- a/src/app/main/content/components/angular-material/example-viewer/example-viewer.scss +++ b/src/app/main/angular-material-elements/example-viewer/example-viewer.scss @@ -1,6 +1,6 @@ -@import "src/@fuse/scss/fuse"; +@import "../../../../@fuse/scss/fuse"; -fuse-example-viewer { +example-viewer { display: block; padding: 24px 0; 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/content/components/angular-material/material.module.ts b/src/app/main/angular-material-elements/material.module.ts similarity index 100% rename from src/app/main/content/components/angular-material/material.module.ts rename to src/app/main/angular-material-elements/material.module.ts diff --git a/src/app/main/content/apps/academy/academy.module.ts b/src/app/main/apps/academy/academy.module.ts similarity index 56% rename from src/app/main/content/apps/academy/academy.module.ts rename to src/app/main/apps/academy/academy.module.ts index e1935402..7006d992 100644 --- a/src/app/main/content/apps/academy/academy.module.ts +++ b/src/app/main/apps/academy/academy.module.ts @@ -1,26 +1,27 @@ import { NgModule } from '@angular/core'; import { RouterModule } from '@angular/router'; -import { MatButtonModule, MatFormFieldModule, MatIconModule, MatInputModule, MatSelectModule, MatSidenavModule } from '@angular/material'; +import { MatButtonModule, MatFormFieldModule, MatIconModule, MatInputModule, MatSelectModule } from '@angular/material'; import { FuseSharedModule } from '@fuse/shared.module'; -import { FuseAcademyCoursesComponent } from './courses/courses.component'; -import { FuseAcademyCourseComponent } from './course/course.component'; -import { AcademyCoursesService } from './courses.service'; -import { AcademyCourseService } from './course.service'; +import { AcademyCoursesComponent } from 'app/main/apps/academy/courses/courses.component'; +import { AcademyCourseComponent } from 'app/main/apps/academy/course/course.component'; +import { AcademyCoursesService } from 'app/main/apps/academy/courses.service'; +import { AcademyCourseService } from 'app/main/apps/academy/course.service'; +import { FuseSidebarModule } from '@fuse/components'; const routes = [ { path : 'courses', - component: FuseAcademyCoursesComponent, + component: AcademyCoursesComponent, resolve : { academy: AcademyCoursesService } }, { path : 'courses/:courseId/:courseSlug', - component: FuseAcademyCourseComponent, + component: AcademyCourseComponent, resolve : { academy: AcademyCourseService } @@ -33,8 +34,8 @@ const routes = [ @NgModule({ declarations: [ - FuseAcademyCoursesComponent, - FuseAcademyCourseComponent + AcademyCoursesComponent, + AcademyCourseComponent ], imports : [ RouterModule.forChild(routes), @@ -44,15 +45,15 @@ const routes = [ MatIconModule, MatInputModule, MatSelectModule, - MatSidenavModule, - FuseSharedModule + FuseSharedModule, + FuseSidebarModule ], providers : [ AcademyCoursesService, AcademyCourseService ] }) -export class FuseAcademyModule +export class AcademyModule { } diff --git a/src/app/main/content/apps/academy/course.service.ts b/src/app/main/apps/academy/course.service.ts similarity index 62% rename from src/app/main/content/apps/academy/course.service.ts rename to src/app/main/apps/academy/course.service.ts index 1d007e82..4143dd4e 100644 --- a/src/app/main/content/apps/academy/course.service.ts +++ b/src/app/main/apps/academy/course.service.ts @@ -6,14 +6,27 @@ import { BehaviorSubject, Observable } from 'rxjs'; @Injectable() export class AcademyCourseService implements Resolve { - onCourseChanged: BehaviorSubject = new BehaviorSubject({}); - - constructor(private http: HttpClient) - { - } + onCourseChanged: BehaviorSubject; /** - * The Academy App Main Resolver + * Constructor + * + * @param {HttpClient} _httpClient + */ + constructor( + private _httpClient: HttpClient + ) + { + // Set the defaults + this.onCourseChanged = new BehaviorSubject({}); + } + + // ----------------------------------------------------------------------------------------------------- + // @ Public methods + // ----------------------------------------------------------------------------------------------------- + + /** + * Resolver * * @param {ActivatedRouteSnapshot} route * @param {RouterStateSnapshot} state @@ -34,10 +47,17 @@ export class AcademyCourseService implements Resolve }); } + /** + * Get course + * + * @param courseId + * @param courseSlug + * @returns {Promise} + */ getCourse(courseId, courseSlug): Promise { return new Promise((resolve, reject) => { - this.http.get('api/academy-course/' + courseId + '/' + courseSlug) + this._httpClient.get('api/academy-course/' + courseId + '/' + courseSlug) .subscribe((response: any) => { this.onCourseChanged.next(response); resolve(response); 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/content/apps/academy/course/course.component.scss b/src/app/main/apps/academy/course/course.component.scss similarity index 94% rename from src/app/main/content/apps/academy/course/course.component.scss rename to src/app/main/apps/academy/course/course.component.scss index 075503a4..58bc612a 100644 --- a/src/app/main/content/apps/academy/course/course.component.scss +++ b/src/app/main/apps/academy/course/course.component.scss @@ -2,19 +2,7 @@ #academy-course { - .mat-drawer-container { - flex: 1 !important; - - > .mat-drawer-content { - flex: 1 !important; - - @include media-breakpoint-up('lg') { - z-index: 52; - } - } - } - - .sidenav { + .sidebar { .steps { padding: 16px 0; @@ -140,6 +128,7 @@ .center { position: relative; + overflow: hidden; .header { height: 72px; @@ -148,10 +137,8 @@ } .content { - display: flex; position: relative; - overflow: hidden; - height: 100%; + display: flex; background: mat-color($mat-grey, 200); .course-step { @@ -163,6 +150,10 @@ padding: 48px; overflow: auto; + &.ng-animating { + overflow: hidden; + } + @media (max-width: 720px) { padding: 0 0 120px 0; } 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/content/apps/academy/courses.service.ts b/src/app/main/apps/academy/courses.service.ts similarity index 61% rename from src/app/main/content/apps/academy/courses.service.ts rename to src/app/main/apps/academy/courses.service.ts index 59356eca..06613028 100644 --- a/src/app/main/content/apps/academy/courses.service.ts +++ b/src/app/main/apps/academy/courses.service.ts @@ -6,15 +6,29 @@ import { BehaviorSubject, Observable } from 'rxjs'; @Injectable() export class AcademyCoursesService implements Resolve { - onCategoriesChanged: BehaviorSubject = new BehaviorSubject({}); - onCoursesChanged: BehaviorSubject = new BehaviorSubject({}); - - constructor(private http: HttpClient) - { - } + onCategoriesChanged: BehaviorSubject; + onCoursesChanged: BehaviorSubject; /** - * The Academy App Main Resolver + * Constructor + * + * @param {HttpClient} _httpClient + */ + constructor( + private _httpClient: HttpClient + ) + { + // Set the defaults + this.onCategoriesChanged = new BehaviorSubject({}); + this.onCoursesChanged = new BehaviorSubject({}); + } + + // ----------------------------------------------------------------------------------------------------- + // @ Public methods + // ----------------------------------------------------------------------------------------------------- + + /** + * Resolver * * @param {ActivatedRouteSnapshot} route * @param {RouterStateSnapshot} state @@ -36,10 +50,15 @@ export class AcademyCoursesService implements Resolve }); } + /** + * Get categories + * + * @returns {Promise} + */ getCategories(): Promise { return new Promise((resolve, reject) => { - this.http.get('api/academy-categories') + this._httpClient.get('api/academy-categories') .subscribe((response: any) => { this.onCategoriesChanged.next(response); resolve(response); @@ -47,10 +66,15 @@ export class AcademyCoursesService implements Resolve }); } + /** + * Get courses + * + * @returns {Promise} + */ getCourses(): Promise { return new Promise((resolve, reject) => { - this.http.get('api/academy-courses') + this._httpClient.get('api/academy-courses') .subscribe((response: any) => { this.onCoursesChanged.next(response); resolve(response); diff --git a/src/app/main/content/apps/academy/courses/courses.component.html b/src/app/main/apps/academy/courses/courses.component.html similarity index 92% rename from src/app/main/content/apps/academy/courses/courses.component.html rename to src/app/main/apps/academy/courses/courses.component.html index cc10911a..de97258d 100644 --- a/src/app/main/content/apps/academy/courses/courses.component.html +++ b/src/app/main/apps/academy/courses/courses.component.html @@ -1,12 +1,14 @@ -
+
school -

WELCOME TO ACADEMY

-

+

+ WELCOME TO ACADEMY +

+

Our courses will step you through the process of building a small application, or adding a new feature to an existing application.

@@ -46,8 +48,7 @@
-
+
diff --git a/src/app/main/content/apps/academy/courses/courses.component.scss b/src/app/main/apps/academy/courses/courses.component.scss similarity index 99% rename from src/app/main/content/apps/academy/courses/courses.component.scss rename to src/app/main/apps/academy/courses/courses.component.scss index b1af425f..9340c26b 100644 --- a/src/app/main/content/apps/academy/courses/courses.component.scss +++ b/src/app/main/apps/academy/courses/courses.component.scss @@ -112,7 +112,7 @@ min-height: 240px; transition: box-shadow 150ms ease-in-out; - @include mat-elevation(1); + @include mat-elevation(3); .header { color: white; 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/content/apps/calendar/calendar.component.html b/src/app/main/apps/calendar/calendar.component.html similarity index 87% rename from src/app/main/content/apps/calendar/calendar.component.html rename to src/app/main/apps/calendar/calendar.component.html index 2ebf4691..dd8d20dd 100644 --- a/src/app/main/content/apps/calendar/calendar.component.html +++ b/src/app/main/apps/calendar/calendar.component.html @@ -1,4 +1,4 @@ -
+
@@ -8,8 +8,12 @@
@@ -44,7 +48,7 @@
+ [@animate]="{value:'*',params:{delay:'150ms'}}"> @@ -81,7 +85,7 @@ -
+
; + dialogRef: any; + events: CalendarEvent[]; + refresh: Subject = new Subject(); + selectedDay: any; view: string; viewDate: Date; - events: CalendarEvent[]; - public actions: CalendarEventAction[]; - activeDayIsOpen: boolean; - refresh: Subject = new Subject(); - dialogRef: any; - confirmDialogRef: MatDialogRef; - selectedDay: any; constructor( - public dialog: MatDialog, - public calendarService: CalendarService + private _matDialog: MatDialog, + private _calendarService: CalendarService ) { + // Set the defaults this.view = 'month'; this.viewDate = new Date(); this.activeDayIsOpen = true; @@ -62,29 +63,41 @@ export class FuseCalendarComponent implements OnInit this.setEvents(); } - ngOnInit() + // ----------------------------------------------------------------------------------------------------- + // @ Lifecycle hooks + // ----------------------------------------------------------------------------------------------------- + + /** + * On init + */ + ngOnInit(): void { /** * Watch re-render-refresh for updating db */ this.refresh.subscribe(updateDB => { - // console.warn('REFRESH'); if ( updateDB ) { - // console.warn('UPDATE DB'); - this.calendarService.updateEvents(this.events); + this._calendarService.updateEvents(this.events); } }); - this.calendarService.onEventsUpdated.subscribe(events => { + this._calendarService.onEventsUpdated.subscribe(events => { this.setEvents(); this.refresh.next(); }); } - setEvents() + // ----------------------------------------------------------------------------------------------------- + // @ Public methods + // ----------------------------------------------------------------------------------------------------- + + /** + * Set events + */ + setEvents(): void { - this.events = this.calendarService.events.map(item => { + this.events = this._calendarService.events.map(item => { item.actions = this.actions; return new CalendarEventModel(item); }); @@ -92,10 +105,11 @@ export class FuseCalendarComponent implements OnInit /** * Before View Renderer + * * @param {any} header * @param {any} body */ - beforeMonthViewRender({header, body}) + beforeMonthViewRender({header, body}): void { // console.info('beforeMonthViewRender'); /** @@ -118,6 +132,7 @@ export class FuseCalendarComponent implements OnInit /** * Day clicked + * * @param {MonthViewDay} day */ dayClicked(day: CalendarMonthViewDay): void @@ -144,6 +159,7 @@ export class FuseCalendarComponent implements OnInit /** * Event times changed * Event dropped or resized + * * @param {CalendarEvent} event * @param {Date} newStart * @param {Date} newEnd @@ -158,11 +174,12 @@ export class FuseCalendarComponent implements OnInit /** * Delete Event + * * @param event */ - deleteEvent(event) + deleteEvent(event): void { - this.confirmDialogRef = this.dialog.open(FuseConfirmDialogComponent, { + this.confirmDialogRef = this._matDialog.open(FuseConfirmDialogComponent, { disableClose: false }); @@ -182,14 +199,15 @@ export class FuseCalendarComponent implements OnInit /** * Edit Event + * * @param {string} action * @param {CalendarEvent} event */ - editEvent(action: string, event: CalendarEvent) + editEvent(action: string, event: CalendarEvent): void { const eventIndex = this.events.indexOf(event); - this.dialogRef = this.dialog.open(FuseCalendarEventFormDialogComponent, { + this.dialogRef = this._matDialog.open(CalendarEventFormDialogComponent, { panelClass: 'event-form-dialog', data : { event : event, @@ -233,7 +251,7 @@ export class FuseCalendarComponent implements OnInit */ addEvent(): void { - this.dialogRef = this.dialog.open(FuseCalendarEventFormDialogComponent, { + this.dialogRef = this._matDialog.open(CalendarEventFormDialogComponent, { panelClass: 'event-form-dialog', data : { action: 'new', diff --git a/src/app/main/content/apps/calendar/calendar.module.ts b/src/app/main/apps/calendar/calendar.module.ts similarity index 52% rename from src/app/main/content/apps/calendar/calendar.module.ts rename to src/app/main/apps/calendar/calendar.module.ts index 769f78d5..dd9c0c0b 100644 --- a/src/app/main/content/apps/calendar/calendar.module.ts +++ b/src/app/main/apps/calendar/calendar.module.ts @@ -1,22 +1,20 @@ import { NgModule } from '@angular/core'; import { RouterModule, Routes } from '@angular/router'; - -import { MatButtonModule, MatDatepickerModule, MatFormFieldModule, MatIconModule, MatInputModule, MatSlideToggleModule, MatToolbarModule } from '@angular/material'; - -import { CalendarModule } from 'angular-calendar'; +import { MatButtonModule, MatDatepickerModule, MatDialogModule, MatFormFieldModule, MatIconModule, MatInputModule, MatSlideToggleModule, MatToolbarModule } from '@angular/material'; import { ColorPickerModule } from 'ngx-color-picker'; +import { CalendarModule as AngularCalendarModule } from 'angular-calendar'; import { FuseSharedModule } from '@fuse/shared.module'; import { FuseConfirmDialogModule } from '@fuse/components'; -import { CalendarService } from './calendar.service'; -import { FuseCalendarComponent } from './calendar.component'; -import { FuseCalendarEventFormDialogComponent } from './event-form/event-form.component'; +import { CalendarComponent } from 'app/main/apps/calendar/calendar.component'; +import { CalendarService } from 'app/main/apps/calendar/calendar.service'; +import { CalendarEventFormDialogComponent } from 'app/main/apps/calendar/event-form/event-form.component'; const routes: Routes = [ { path : '**', - component: FuseCalendarComponent, + component: CalendarComponent, children : [], resolve : { chat: CalendarService @@ -26,21 +24,22 @@ const routes: Routes = [ @NgModule({ declarations : [ - FuseCalendarComponent, - FuseCalendarEventFormDialogComponent + CalendarComponent, + CalendarEventFormDialogComponent ], imports : [ RouterModule.forChild(routes), MatButtonModule, MatDatepickerModule, + MatDialogModule, MatFormFieldModule, MatIconModule, MatInputModule, MatSlideToggleModule, MatToolbarModule, - CalendarModule.forRoot(), + AngularCalendarModule.forRoot(), ColorPickerModule, FuseSharedModule, @@ -49,8 +48,10 @@ const routes: Routes = [ providers : [ CalendarService ], - entryComponents: [FuseCalendarEventFormDialogComponent] + entryComponents: [ + CalendarEventFormDialogComponent + ] }) -export class FuseCalendarModule +export class CalendarModule { } diff --git a/src/app/main/content/apps/calendar/calendar.service.ts b/src/app/main/apps/calendar/calendar.service.ts similarity index 55% rename from src/app/main/content/apps/calendar/calendar.service.ts rename to src/app/main/apps/calendar/calendar.service.ts index bdd8e4d4..21dc56e9 100644 --- a/src/app/main/content/apps/calendar/calendar.service.ts +++ b/src/app/main/apps/calendar/calendar.service.ts @@ -7,13 +7,32 @@ import { Observable, Subject } from 'rxjs'; export class CalendarService implements Resolve { events: any; - onEventsUpdated = new Subject(); + onEventsUpdated: Subject; - constructor(private http: HttpClient) + /** + * Constructor + * + * @param {HttpClient} _httpClient + */ + constructor( + private _httpClient: HttpClient + ) { - + // Set the defaults + this.onEventsUpdated = new Subject(); } + // ----------------------------------------------------------------------------------------------------- + // @ Public methods + // ----------------------------------------------------------------------------------------------------- + + /** + * Resolver + * + * @param {ActivatedRouteSnapshot} route + * @param {RouterStateSnapshot} state + * @returns {Observable | Promise | any} + */ resolve(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable | Promise | any { return new Promise((resolve, reject) => { @@ -28,11 +47,16 @@ export class CalendarService implements Resolve }); } - getEvents() + /** + * Get events + * + * @returns {Promise} + */ + getEvents(): Promise { return new Promise((resolve, reject) => { - this.http.get('api/calendar/events') + this._httpClient.get('api/calendar/events') .subscribe((response: any) => { this.events = response.data; this.onEventsUpdated.next(this.events); @@ -41,10 +65,16 @@ export class CalendarService implements Resolve }); } - updateEvents(events) + /** + * Update events + * + * @param events + * @returns {Promise} + */ + updateEvents(events): Promise { return new Promise((resolve, reject) => { - this.http.post('api/calendar/events', { + this._httpClient.post('api/calendar/events', { id : 'events', data: [...events] }) diff --git a/src/app/main/content/apps/calendar/event-form/event-form.component.html b/src/app/main/apps/calendar/event-form/event-form.component.html similarity index 95% rename from src/app/main/content/apps/calendar/event-form/event-form.component.html rename to src/app/main/apps/calendar/event-form/event-form.component.html index 32a805f4..2937cf67 100644 --- a/src/app/main/content/apps/calendar/event-form/event-form.component.html +++ b/src/app/main/apps/calendar/event-form/event-form.component.html @@ -2,7 +2,7 @@ {{dialogTitle}} - @@ -117,7 +117,7 @@ + +
diff --git a/src/app/main/content/apps/chat/chat-start/chat-start.component.scss b/src/app/main/apps/chat/chat-start/chat-start.component.scss similarity index 91% rename from src/app/main/content/apps/chat/chat-start/chat-start.component.scss rename to src/app/main/apps/chat/chat-start/chat-start.component.scss index c6f0ad4d..3a6fb4ee 100644 --- a/src/app/main/content/apps/chat/chat-start/chat-start.component.scss +++ b/src/app/main/apps/chat/chat-start/chat-start.component.scss @@ -18,10 +18,6 @@ height: 160px; line-height: 160px; } - - mat-icon { - color: mat-color($accent); - } } .app-title { diff --git a/src/app/main/content/apps/chat/chat-start/chat-start.component.ts b/src/app/main/apps/chat/chat-start/chat-start.component.ts similarity index 79% rename from src/app/main/content/apps/chat/chat-start/chat-start.component.ts rename to src/app/main/apps/chat/chat-start/chat-start.component.ts index 2651c617..adc689ea 100644 --- a/src/app/main/content/apps/chat/chat-start/chat-start.component.ts +++ b/src/app/main/apps/chat/chat-start/chat-start.component.ts @@ -3,12 +3,12 @@ import { Component } from '@angular/core'; import { fuseAnimations } from '@fuse/animations'; @Component({ - selector : 'fuse-chat-start', + selector : 'chat-start', templateUrl: './chat-start.component.html', styleUrls : ['./chat-start.component.scss'], animations : fuseAnimations }) -export class FuseChatStartComponent +export class ChatStartComponent { constructor() { diff --git a/src/app/main/content/apps/chat/chat-view/chat-view.component.html b/src/app/main/apps/chat/chat-view/chat-view.component.html similarity index 92% rename from src/app/main/content/apps/chat/chat-view/chat-view.component.html rename to src/app/main/apps/chat/chat-view/chat-view.component.html index 62e1e32b..d1a72c6d 100644 --- a/src/app/main/content/apps/chat/chat-view/chat-view.component.html +++ b/src/app/main/apps/chat/chat-view/chat-view.component.html @@ -87,28 +87,30 @@ - diff --git a/src/app/main/content/apps/chat/chat-view/chat-view.component.scss b/src/app/main/apps/chat/chat-view/chat-view.component.scss similarity index 99% rename from src/app/main/content/apps/chat/chat-view/chat-view.component.scss rename to src/app/main/apps/chat/chat-view/chat-view.component.scss index 362b701d..3d8efac0 100644 --- a/src/app/main/content/apps/chat/chat-view/chat-view.component.scss +++ b/src/app/main/apps/chat/chat-view/chat-view.component.scss @@ -99,7 +99,7 @@ } .chat-footer { - min-height: 64px; + min-height: 72px; max-height: 96px; background-color: #F3F4F5; color: rgba(0, 0, 0, 0.87); @@ -116,6 +116,7 @@ overflow: auto; max-height: 80px; transition: height 200ms ease; + &.grow { height: 80px; } 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/content/apps/chat/chat.component.html b/src/app/main/apps/chat/chat.component.html similarity index 78% rename from src/app/main/content/apps/chat/chat.component.html rename to src/app/main/apps/chat/chat.component.html index 2a903f8f..6967d337 100644 --- a/src/app/main/content/apps/chat/chat.component.html +++ b/src/app/main/apps/chat/chat.component.html @@ -15,20 +15,20 @@ - + - + - + - + diff --git a/src/app/main/content/apps/chat/chat.component.scss b/src/app/main/apps/chat/chat.component.scss similarity index 100% rename from src/app/main/content/apps/chat/chat.component.scss rename to src/app/main/apps/chat/chat.component.scss 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/content/apps/chat/chat.service.ts b/src/app/main/apps/chat/chat.service.ts similarity index 77% rename from src/app/main/content/apps/chat/chat.service.ts rename to src/app/main/apps/chat/chat.service.ts index 3a80ec78..10643081 100644 --- a/src/app/main/content/apps/chat/chat.service.ts +++ b/src/app/main/apps/chat/chat.service.ts @@ -11,23 +11,64 @@ export class ChatService implements Resolve contacts: any[]; chats: any[]; user: any; - onChatSelected = new BehaviorSubject(null); - onContactSelected = new BehaviorSubject(null); - onChatsUpdated = new Subject(); - onUserUpdated = new Subject(); - onLeftSidenavViewChanged = new Subject(); - onRightSidenavViewChanged = new Subject(); + onChatSelected: BehaviorSubject; + onContactSelected: BehaviorSubject; + onChatsUpdated: Subject; + onUserUpdated: Subject; + onLeftSidenavViewChanged: Subject; + onRightSidenavViewChanged: Subject; - constructor(private http: HttpClient) + /** + * Constructor + * + * @param {HttpClient} _httpClient + */ + constructor( + private _httpClient: HttpClient + ) { + // Set the defaults + this.onChatSelected = new BehaviorSubject(null); + this.onContactSelected = new BehaviorSubject(null); + this.onChatsUpdated = new Subject(); + this.onUserUpdated = new Subject(); + this.onLeftSidenavViewChanged = new Subject(); + this.onRightSidenavViewChanged = new Subject(); + } + + /** + * Resolver + * + * @param {ActivatedRouteSnapshot} route + * @param {RouterStateSnapshot} state + * @returns {Observable | Promise | any} + */ + resolve(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable | Promise | any + { + return new Promise((resolve, reject) => { + Promise.all([ + this.getContacts(), + this.getChats(), + this.getUser() + ]).then( + ([contacts, chats, user]) => { + this.contacts = contacts; + this.chats = chats; + this.user = user; + resolve(); + }, + reject + ); + }); } /** * Get chat + * * @param contactId * @returns {Promise} */ - getChat(contactId) + getChat(contactId): Promise { const chatItem = this.user.chatList.find((item) => { return item.contactId === contactId; @@ -45,7 +86,7 @@ export class ChatService implements Resolve } return new Promise((resolve, reject) => { - this.http.get('api/chat-chats/' + chatItem.id) + this._httpClient.get('api/chat-chats/' + chatItem.id) .subscribe((response: any) => { const chat = response; @@ -68,11 +109,12 @@ export class ChatService implements Resolve } /** - * Create New Chat + * Create new chat + * * @param contactId * @returns {Promise} */ - createNewChat(contactId) + createNewChat(contactId): Promise { return new Promise((resolve, reject) => { @@ -103,13 +145,13 @@ export class ChatService implements Resolve /** * Post the created chat */ - this.http.post('api/chat-chats', {...chat}) + this._httpClient.post('api/chat-chats', {...chat}) .subscribe((response: any) => { /** * Post the new the user data */ - this.http.post('api/chat-user/' + this.user.id, this.user) + this._httpClient.post('api/chat-user/' + this.user.id, this.user) .subscribe(newUserData => { /** @@ -125,30 +167,33 @@ export class ChatService implements Resolve } /** - * Select Contact + * Select contact + * * @param contact */ - selectContact(contact) + selectContact(contact): void { this.onContactSelected.next(contact); } /** * Set user status + * * @param status */ - setUserStatus(status) + setUserStatus(status): void { this.user.status = status; } /** * Update user data + * * @param userData */ - updateUserData(userData) + updateUserData(userData): void { - this.http.post('api/chat-user/' + this.user.id, userData) + this._httpClient.post('api/chat-user/' + this.user.id, userData) .subscribe((response: any) => { this.user = userData; } @@ -157,6 +202,7 @@ export class ChatService implements Resolve /** * Update the chat dialog + * * @param chatId * @param dialog * @returns {Promise} @@ -170,7 +216,7 @@ export class ChatService implements Resolve dialog: dialog }; - this.http.post('api/chat-chats/' + chatId, newData) + this._httpClient.post('api/chat-chats/' + chatId, newData) .subscribe(updatedChat => { resolve(updatedChat); }, reject); @@ -178,38 +224,14 @@ export class ChatService implements Resolve } /** - * The Chat App Main Resolver - * @param {ActivatedRouteSnapshot} route - * @param {RouterStateSnapshot} state - * @returns {Observable | Promise | any} - */ - resolve(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable | Promise | any - { - return new Promise((resolve, reject) => { - Promise.all([ - this.getContacts(), - this.getChats(), - this.getUser() - ]).then( - ([contacts, chats, user]) => { - this.contacts = contacts; - this.chats = chats; - this.user = user; - resolve(); - }, - reject - ); - }); - } - - /** - * Get Contacts + * Get contacts + * * @returns {Promise} */ getContacts(): Promise { return new Promise((resolve, reject) => { - this.http.get('api/chat-contacts') + this._httpClient.get('api/chat-contacts') .subscribe((response: any) => { resolve(response); }, reject); @@ -217,13 +239,14 @@ export class ChatService implements Resolve } /** - * Get Chats + * Get chats + * * @returns {Promise} */ getChats(): Promise { return new Promise((resolve, reject) => { - this.http.get('api/chat-chats') + this._httpClient.get('api/chat-chats') .subscribe((response: any) => { resolve(response); }, reject); @@ -231,13 +254,14 @@ export class ChatService implements Resolve } /** - * Get User + * Get user + * * @returns {Promise} */ getUser(): Promise { return new Promise((resolve, reject) => { - this.http.get('api/chat-user') + this._httpClient.get('api/chat-user') .subscribe((response: any) => { resolve(response[0]); }, reject); diff --git a/src/app/main/content/apps/chat/sidenavs/left/chats/chats.component.html b/src/app/main/apps/chat/sidenavs/left/chats/chats.component.html similarity index 99% rename from src/app/main/content/apps/chat/sidenavs/left/chats/chats.component.html rename to src/app/main/apps/chat/sidenavs/left/chats/chats.component.html index b210bf42..c59c1e21 100644 --- a/src/app/main/content/apps/chat/sidenavs/left/chats/chats.component.html +++ b/src/app/main/apps/chat/sidenavs/left/chats/chats.component.html @@ -136,7 +136,7 @@
{{chat.lastMessageTime | date}}
-
{{chat.unread}}
+
{{chat.unread}}
diff --git a/src/app/main/content/apps/chat/sidenavs/left/chats/chats.component.scss b/src/app/main/apps/chat/sidenavs/left/chats/chats.component.scss similarity index 95% rename from src/app/main/content/apps/chat/sidenavs/left/chats/chats.component.scss rename to src/app/main/apps/chat/sidenavs/left/chats/chats.component.scss index a49f5163..4fa85df8 100644 --- a/src/app/main/content/apps/chat/sidenavs/left/chats/chats.component.scss +++ b/src/app/main/apps/chat/sidenavs/left/chats/chats.component.scss @@ -94,8 +94,6 @@ width: 24px; height: 24px; line-height: 24px; - background-color: mat-color($accent); - color: map-get($accent, default-contrast); } } } 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/content/apps/chat/sidenavs/left/left.component.scss b/src/app/main/apps/chat/sidenavs/left/left.component.scss similarity index 100% rename from src/app/main/content/apps/chat/sidenavs/left/left.component.scss rename to src/app/main/apps/chat/sidenavs/left/left.component.scss 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/content/apps/chat/sidenavs/left/user/user.component.html b/src/app/main/apps/chat/sidenavs/left/user/user.component.html similarity index 97% rename from src/app/main/content/apps/chat/sidenavs/left/user/user.component.html rename to src/app/main/apps/chat/sidenavs/left/user/user.component.html index 59ce9639..919d8058 100644 --- a/src/app/main/content/apps/chat/sidenavs/left/user/user.component.html +++ b/src/app/main/apps/chat/sidenavs/left/user/user.component.html @@ -2,7 +2,7 @@
- + @@ -28,7 +28,7 @@
-
+
diff --git a/src/app/main/content/apps/chat/sidenavs/left/user/user.component.scss b/src/app/main/apps/chat/sidenavs/left/user/user.component.scss similarity index 78% rename from src/app/main/content/apps/chat/sidenavs/left/user/user.component.scss rename to src/app/main/apps/chat/sidenavs/left/user/user.component.scss index 40d65ae3..af7de534 100644 --- a/src/app/main/content/apps/chat/sidenavs/left/user/user.component.scss +++ b/src/app/main/apps/chat/sidenavs/left/user/user.component.scss @@ -4,10 +4,9 @@ display: flex; flex: 1; flex-direction: column; + overflow: auto; mat-toolbar { - background-color: mat-color($accent); - color: map-get($accent, default-contrast); .toolbar-bottom { height: 240px; @@ -16,7 +15,6 @@ height: 180px; } } - } .sidenav-content { 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/content/apps/chat/sidenavs/right/contact/contact.component.html b/src/app/main/apps/chat/sidenavs/right/contact/contact.component.html similarity index 92% rename from src/app/main/content/apps/chat/sidenavs/right/contact/contact.component.html rename to src/app/main/apps/chat/sidenavs/right/contact/contact.component.html index a7dd59f9..a8c904c8 100644 --- a/src/app/main/content/apps/chat/sidenavs/right/contact/contact.component.html +++ b/src/app/main/apps/chat/sidenavs/right/contact/contact.component.html @@ -2,7 +2,7 @@
- + @@ -18,11 +18,8 @@ - {{contact.name}} -
{{contact.name}}
-
@@ -31,7 +28,7 @@
-
+
diff --git a/src/app/main/content/apps/chat/sidenavs/right/contact/contact.component.scss b/src/app/main/apps/chat/sidenavs/right/contact/contact.component.scss similarity index 78% rename from src/app/main/content/apps/chat/sidenavs/right/contact/contact.component.scss rename to src/app/main/apps/chat/sidenavs/right/contact/contact.component.scss index 40d65ae3..af7de534 100644 --- a/src/app/main/content/apps/chat/sidenavs/right/contact/contact.component.scss +++ b/src/app/main/apps/chat/sidenavs/right/contact/contact.component.scss @@ -4,10 +4,9 @@ display: flex; flex: 1; flex-direction: column; + overflow: auto; mat-toolbar { - background-color: mat-color($accent); - color: map-get($accent, default-contrast); .toolbar-bottom { height: 240px; @@ -16,7 +15,6 @@ height: 180px; } } - } .sidenav-content { 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/content/apps/chat/sidenavs/right/right.component.scss b/src/app/main/apps/chat/sidenavs/right/right.component.scss similarity index 100% rename from src/app/main/content/apps/chat/sidenavs/right/right.component.scss rename to src/app/main/apps/chat/sidenavs/right/right.component.scss 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/content/apps/contacts/contact-form/contact-form.component.html b/src/app/main/apps/contacts/contact-form/contact-form.component.html similarity index 94% rename from src/app/main/content/apps/contacts/contact-form/contact-form.component.html rename to src/app/main/apps/contacts/contact-form/contact-form.component.html index 390bc0e8..47985052 100644 --- a/src/app/main/content/apps/contacts/contact-form/contact-form.component.html +++ b/src/app/main/apps/contacts/contact-form/contact-form.component.html @@ -2,7 +2,7 @@ {{dialogTitle}} - @@ -98,7 +98,7 @@
@@ -36,41 +39,44 @@ - + - + +
- - + + - + +
+ +
+ -
- + +
- - - +
- +
+
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/content/apps/contacts/contacts.service.ts b/src/app/main/apps/contacts/contacts.service.ts similarity index 71% rename from src/app/main/content/apps/contacts/contacts.service.ts rename to src/app/main/apps/contacts/contacts.service.ts index 66563638..e43ebcca 100644 --- a/src/app/main/content/apps/contacts/contacts.service.ts +++ b/src/app/main/apps/contacts/contacts.service.ts @@ -5,16 +5,16 @@ import { BehaviorSubject, Observable, Subject } from 'rxjs'; import { FuseUtils } from '@fuse/utils'; -import { Contact } from './contact.model'; +import { Contact } from 'app/main/apps/contacts/contact.model'; @Injectable() export class ContactsService implements Resolve { - onContactsChanged: BehaviorSubject = new BehaviorSubject([]); - onSelectedContactsChanged: BehaviorSubject = new BehaviorSubject([]); - onUserDataChanged: BehaviorSubject = new BehaviorSubject([]); - onSearchTextChanged: Subject = new Subject(); - onFilterChanged: Subject = new Subject(); + onContactsChanged: BehaviorSubject; + onSelectedContactsChanged: BehaviorSubject; + onUserDataChanged: BehaviorSubject; + onSearchTextChanged: Subject; + onFilterChanged: Subject; contacts: Contact[]; user: any; @@ -23,12 +23,30 @@ export class ContactsService implements Resolve searchText: string; filterBy: string; - constructor(private http: HttpClient) + /** + * Constructor + * + * @param {HttpClient} _httpClient + */ + constructor( + private _httpClient: HttpClient + ) { + // Set the defaults + this.onContactsChanged = new BehaviorSubject([]); + this.onSelectedContactsChanged = new BehaviorSubject([]); + this.onUserDataChanged = new BehaviorSubject([]); + this.onSearchTextChanged = new Subject(); + this.onFilterChanged = new Subject(); } + // ----------------------------------------------------------------------------------------------------- + // @ Public methods + // ----------------------------------------------------------------------------------------------------- + /** - * The Contacts App Main Resolver + * Resolver + * * @param {ActivatedRouteSnapshot} route * @param {RouterStateSnapshot} state * @returns {Observable | Promise | any} @@ -61,10 +79,15 @@ export class ContactsService implements Resolve }); } + /** + * Get contacts + * + * @returns {Promise} + */ getContacts(): Promise { return new Promise((resolve, reject) => { - this.http.get('api/contacts-contacts') + this._httpClient.get('api/contacts-contacts') .subscribe((response: any) => { this.contacts = response; @@ -99,10 +122,15 @@ export class ContactsService implements Resolve ); } + /** + * Get user data + * + * @returns {Promise} + */ getUserData(): Promise { return new Promise((resolve, reject) => { - this.http.get('api/contacts-user/5725a6802d10e277a0f35724') + this._httpClient.get('api/contacts-user/5725a6802d10e277a0f35724') .subscribe((response: any) => { this.user = response; this.onUserDataChanged.next(this.user); @@ -114,9 +142,10 @@ export class ContactsService implements Resolve /** * Toggle selected contact by id + * * @param id */ - toggleSelectedContact(id) + toggleSelectedContact(id): void { // First, check if we already have that contact as selected... if ( this.selectedContacts.length > 0 ) @@ -145,7 +174,7 @@ export class ContactsService implements Resolve /** * Toggle select all */ - toggleSelectAll() + toggleSelectAll(): void { if ( this.selectedContacts.length > 0 ) { @@ -157,11 +186,17 @@ export class ContactsService implements Resolve } } - selectContacts(filterParameter?, filterValue?) + /** + * Select contacts + * + * @param filterParameter + * @param filterValue + */ + selectContacts(filterParameter?, filterValue?): void { this.selectedContacts = []; - // If there is no filter, select all todos + // If there is no filter, select all contacts if ( filterParameter === undefined || filterValue === undefined ) { this.selectedContacts = []; @@ -169,24 +204,22 @@ export class ContactsService implements Resolve this.selectedContacts.push(contact.id); }); } - else - { - /* this.selectedContacts.push(... - this.contacts.filter(todo => { - return todo[filterParameter] === filterValue; - }) - );*/ - } // Trigger the next event this.onSelectedContactsChanged.next(this.selectedContacts); } - updateContact(contact) + /** + * Update contact + * + * @param contact + * @returns {Promise} + */ + updateContact(contact): Promise { return new Promise((resolve, reject) => { - this.http.post('api/contacts-contacts/' + contact.id, {...contact}) + this._httpClient.post('api/contacts-contacts/' + contact.id, {...contact}) .subscribe(response => { this.getContacts(); resolve(response); @@ -194,10 +227,16 @@ export class ContactsService implements Resolve }); } - updateUserData(userData) + /** + * Update user data + * + * @param userData + * @returns {Promise} + */ + updateUserData(userData): Promise { return new Promise((resolve, reject) => { - this.http.post('api/contacts-user/' + this.user.id, {...userData}) + this._httpClient.post('api/contacts-user/' + this.user.id, {...userData}) .subscribe(response => { this.getUserData(); this.getContacts(); @@ -206,7 +245,10 @@ export class ContactsService implements Resolve }); } - deselectContacts() + /** + * Deselect contacts + */ + deselectContacts(): void { this.selectedContacts = []; @@ -214,14 +256,22 @@ export class ContactsService implements Resolve this.onSelectedContactsChanged.next(this.selectedContacts); } - deleteContact(contact) + /** + * Delete contact + * + * @param contact + */ + deleteContact(contact): void { const contactIndex = this.contacts.indexOf(contact); this.contacts.splice(contactIndex, 1); this.onContactsChanged.next(this.contacts); } - deleteSelectedContacts() + /** + * Delete selected contacts + */ + deleteSelectedContacts(): void { for ( const contactId of this.selectedContacts ) { diff --git a/src/app/main/content/apps/contacts/selected-bar/selected-bar.component.html b/src/app/main/apps/contacts/selected-bar/selected-bar.component.html similarity index 100% rename from src/app/main/content/apps/contacts/selected-bar/selected-bar.component.html rename to src/app/main/apps/contacts/selected-bar/selected-bar.component.html diff --git a/src/app/main/content/apps/contacts/selected-bar/selected-bar.component.scss b/src/app/main/apps/contacts/selected-bar/selected-bar.component.scss similarity index 100% rename from src/app/main/content/apps/contacts/selected-bar/selected-bar.component.scss rename to src/app/main/apps/contacts/selected-bar/selected-bar.component.scss 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/content/apps/contacts/sidenavs/main/main.component.html b/src/app/main/apps/contacts/sidebars/main/main.component.html similarity index 78% rename from src/app/main/content/apps/contacts/sidenavs/main/main.component.html rename to src/app/main/apps/contacts/sidebars/main/main.component.html index 7d25084c..9455e5b1 100644 --- a/src/app/main/content/apps/contacts/sidenavs/main/main.component.html +++ b/src/app/main/apps/contacts/sidebars/main/main.component.html @@ -1,7 +1,8 @@ -
+ - + diff --git a/src/app/main/content/apps/contacts/sidenavs/main/main.component.scss b/src/app/main/apps/contacts/sidebars/main/main.component.scss similarity index 97% rename from src/app/main/content/apps/contacts/sidenavs/main/main.component.scss rename to src/app/main/apps/contacts/sidebars/main/main.component.scss index 97c837bf..4af9c387 100644 --- a/src/app/main/content/apps/contacts/sidenavs/main/main.component.scss +++ b/src/app/main/apps/contacts/sidebars/main/main.component.scss @@ -6,7 +6,7 @@ flex: 1 0 auto; height: 100%; - .sidenav-content { + .sidebar-content { display: flex; flex-direction: column; padding: 0; 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/content/apps/dashboards/analytics/analytics.component.html b/src/app/main/apps/dashboards/analytics/analytics.component.html similarity index 99% rename from src/app/main/content/apps/dashboards/analytics/analytics.component.html rename to src/app/main/apps/dashboards/analytics/analytics.component.html index fc9efc11..c8373a44 100644 --- a/src/app/main/content/apps/dashboards/analytics/analytics.component.html +++ b/src/app/main/apps/dashboards/analytics/analytics.component.html @@ -1,4 +1,4 @@ -
+
diff --git a/src/app/main/content/apps/dashboards/analytics/analytics.component.scss b/src/app/main/apps/dashboards/analytics/analytics.component.scss similarity index 100% rename from src/app/main/content/apps/dashboards/analytics/analytics.component.scss rename to src/app/main/apps/dashboards/analytics/analytics.component.scss diff --git a/src/app/main/content/apps/dashboards/analytics/analytics.component.ts b/src/app/main/apps/dashboards/analytics/analytics.component.ts similarity index 71% rename from src/app/main/content/apps/dashboards/analytics/analytics.component.ts rename to src/app/main/apps/dashboards/analytics/analytics.component.ts index c1b78979..41829f65 100644 --- a/src/app/main/content/apps/dashboards/analytics/analytics.component.ts +++ b/src/app/main/apps/dashboards/analytics/analytics.component.ts @@ -1,36 +1,56 @@ -import { Component, ViewEncapsulation } from '@angular/core'; +import { Component, OnInit, ViewEncapsulation } from '@angular/core'; -import { AnalyticsDashboardService } from './analytics.service'; import { fuseAnimations } from '@fuse/animations'; +import { AnalyticsDashboardService } from 'app/main/apps/dashboards/analytics/analytics.service'; + @Component({ - selector : 'fuse-analytics-dashboard', + selector : 'analytics-dashboard', templateUrl : './analytics.component.html', styleUrls : ['./analytics.component.scss'], encapsulation: ViewEncapsulation.None, animations : fuseAnimations }) -export class FuseAnalyticsDashboardComponent +export class AnalyticsDashboardComponent implements OnInit { widgets: any; widget1SelectedYear = '2016'; widget5SelectedDay = 'today'; + /** + * Constructor + * + * @param {AnalyticsDashboardService} _analyticsDashboardService + */ constructor( - private analyticsDashboardService: AnalyticsDashboardService + private _analyticsDashboardService: AnalyticsDashboardService ) { - // Get the widgets from the service - this.widgets = this.analyticsDashboardService.widgets; - // Register the custom chart.js plugin - this.registerCustomChartJSPlugin(); + this._registerCustomChartJSPlugin(); } + // ----------------------------------------------------------------------------------------------------- + // @ Lifecycle hooks + // ----------------------------------------------------------------------------------------------------- + + /** + * On init + */ + ngOnInit(): void + { + // Get the widgets from the service + this.widgets = this._analyticsDashboardService.widgets; + } + + // ----------------------------------------------------------------------------------------------------- + // @ Private methods + // ----------------------------------------------------------------------------------------------------- + /** * Register a custom plugin */ - registerCustomChartJSPlugin() + private _registerCustomChartJSPlugin(): void { (window).Chart.plugins.register({ afterDatasetsDraw: function (chart, easing) { diff --git a/src/app/main/content/apps/dashboards/analytics/analytics.module.ts b/src/app/main/apps/dashboards/analytics/analytics.module.ts similarity index 78% rename from src/app/main/content/apps/dashboards/analytics/analytics.module.ts rename to src/app/main/apps/dashboards/analytics/analytics.module.ts index 710521ca..6e4cd406 100644 --- a/src/app/main/content/apps/dashboards/analytics/analytics.module.ts +++ b/src/app/main/apps/dashboards/analytics/analytics.module.ts @@ -1,8 +1,6 @@ import { NgModule } from '@angular/core'; import { RouterModule, Routes } from '@angular/router'; - import { MatButtonModule, MatFormFieldModule, MatIconModule, MatMenuModule, MatSelectModule, MatTabsModule } from '@angular/material'; - import { AgmCoreModule } from '@agm/core'; import { ChartsModule } from 'ng2-charts'; import { NgxChartsModule } from '@swimlane/ngx-charts'; @@ -10,14 +8,13 @@ import { NgxChartsModule } from '@swimlane/ngx-charts'; import { FuseSharedModule } from '@fuse/shared.module'; import { FuseWidgetModule } from '@fuse/components/widget/widget.module'; -import { FuseAnalyticsDashboardComponent } from './analytics.component'; -import { AnalyticsDashboardService } from './analytics.service'; - +import { AnalyticsDashboardComponent } from 'app/main/apps/dashboards/analytics/analytics.component'; +import { AnalyticsDashboardService } from 'app/main/apps/dashboards/analytics/analytics.service'; const routes: Routes = [ { path : '**', - component: FuseAnalyticsDashboardComponent, + component: AnalyticsDashboardComponent, resolve : { data: AnalyticsDashboardService } @@ -26,7 +23,7 @@ const routes: Routes = [ @NgModule({ declarations: [ - FuseAnalyticsDashboardComponent + AnalyticsDashboardComponent ], imports : [ RouterModule.forChild(routes), @@ -51,7 +48,7 @@ const routes: Routes = [ AnalyticsDashboardService ] }) -export class FuseAnalyticsDashboardModule +export class AnalyticsDashboardModule { } diff --git a/src/app/main/content/apps/dashboards/analytics/analytics.service.ts b/src/app/main/apps/dashboards/analytics/analytics.service.ts similarity index 80% rename from src/app/main/content/apps/dashboards/analytics/analytics.service.ts rename to src/app/main/apps/dashboards/analytics/analytics.service.ts index 47d3097c..69f1fddb 100644 --- a/src/app/main/content/apps/dashboards/analytics/analytics.service.ts +++ b/src/app/main/apps/dashboards/analytics/analytics.service.ts @@ -8,14 +8,20 @@ export class AnalyticsDashboardService implements Resolve { widgets: any[]; + /** + * Constructor + * + * @param {HttpClient} _httpClient + */ constructor( - private http: HttpClient + private _httpClient: HttpClient ) { } /** - * Resolve + * Resolver + * * @param {ActivatedRouteSnapshot} route * @param {RouterStateSnapshot} state * @returns {Observable | Promise | any} @@ -35,10 +41,15 @@ export class AnalyticsDashboardService implements Resolve }); } + /** + * Get widgets + * + * @returns {Promise} + */ getWidgets(): Promise { return new Promise((resolve, reject) => { - this.http.get('api/analytics-dashboard-widgets') + this._httpClient.get('api/analytics-dashboard-widgets') .subscribe((response: any) => { this.widgets = response; resolve(response); 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/content/apps/dashboards/project/project.component.ts b/src/app/main/apps/dashboards/project/project.component.ts similarity index 69% rename from src/app/main/content/apps/dashboards/project/project.component.ts rename to src/app/main/apps/dashboards/project/project.component.ts index deeadfff..87069e05 100644 --- a/src/app/main/content/apps/dashboards/project/project.component.ts +++ b/src/app/main/apps/dashboards/project/project.component.ts @@ -1,21 +1,21 @@ import { Component, OnInit, ViewEncapsulation } from '@angular/core'; import { DataSource } from '@angular/cdk/collections'; import { BehaviorSubject, Observable } from 'rxjs'; - import * as shape from 'd3-shape'; import { fuseAnimations } from '@fuse/animations'; -import { ProjectDashboardService } from './project.service'; +import { ProjectDashboardService } from 'app/main/apps/dashboards/project/project.service'; +import { FuseSidebarService } from '@fuse/components/sidebar/sidebar.service'; @Component({ - selector : 'fuse-project-dashboard', + selector : 'project-dashboard', templateUrl : './project.component.html', styleUrls : ['./project.component.scss'], encapsulation: ViewEncapsulation.None, animations : fuseAnimations }) -export class FuseProjectDashboardComponent implements OnInit +export class ProjectDashboardComponent implements OnInit { projects: any[]; selectedProject: any; @@ -30,12 +30,17 @@ export class FuseProjectDashboardComponent implements OnInit dateNow = Date.now(); - constructor(private projectDashboardService: ProjectDashboardService) + /** + * Constructor + * + * @param {FuseSidebarService} _fuseSidebarService + * @param {ProjectDashboardService} _projectDashboardService + */ + constructor( + private _fuseSidebarService: FuseSidebarService, + private _projectDashboardService: ProjectDashboardService + ) { - this.projects = this.projectDashboardService.projects; - this.selectedProject = this.projects[0]; - this.widgets = this.projectDashboardService.widgets; - /** * Widget 5 */ @@ -139,8 +144,19 @@ export class FuseProjectDashboardComponent implements OnInit } - ngOnInit() + // ----------------------------------------------------------------------------------------------------- + // @ Lifecycle hooks + // ----------------------------------------------------------------------------------------------------- + + /** + * On init + */ + ngOnInit(): void { + this.projects = this._projectDashboardService.projects; + this.selectedProject = this.projects[0]; + this.widgets = this._projectDashboardService.widgets; + /** * Widget 11 */ @@ -148,22 +164,48 @@ export class FuseProjectDashboardComponent implements OnInit this.widget11.onContactsChanged.next(this.widgets.widget11.table.rows); this.widget11.dataSource = new FilesDataSource(this.widget11); } + + // ----------------------------------------------------------------------------------------------------- + // @ Public methods + // ----------------------------------------------------------------------------------------------------- + + /** + * Toggle the sidebar + * + * @param name + */ + toggleSidebar(name): void + { + this._fuseSidebarService.getSidebar(name).toggleOpen(); + } } export class FilesDataSource extends DataSource { - constructor(private widget11) + /** + * Constructor + * + * @param _widget11 + */ + constructor(private _widget11) { super(); } - /** Connect function called by the table to retrieve one stream containing the data to render. */ + /** + * Connect function called by the table to retrieve one stream containing the data to render. + * + * @returns {Observable} + */ connect(): Observable { - return this.widget11.onContactsChanged; + return this._widget11.onContactsChanged; } - disconnect() + /** + * Disconnect + */ + disconnect(): void { } } diff --git a/src/app/main/content/apps/dashboards/project/project.module.ts b/src/app/main/apps/dashboards/project/project.module.ts similarity index 67% rename from src/app/main/content/apps/dashboards/project/project.module.ts rename to src/app/main/apps/dashboards/project/project.module.ts index 23dcf8d9..46e2c8f6 100644 --- a/src/app/main/content/apps/dashboards/project/project.module.ts +++ b/src/app/main/apps/dashboards/project/project.module.ts @@ -1,21 +1,20 @@ import { NgModule } from '@angular/core'; import { RouterModule, Routes } from '@angular/router'; import { CdkTableModule } from '@angular/cdk/table'; - -import { MatButtonModule, MatDividerModule, MatFormFieldModule, MatIconModule, MatMenuModule, MatSelectModule, MatSidenavModule, MatTableModule, MatTabsModule } from '@angular/material'; - +import { MatButtonModule, MatDividerModule, MatFormFieldModule, MatIconModule, MatMenuModule, MatSelectModule, MatTableModule, MatTabsModule } from '@angular/material'; import { NgxChartsModule } from '@swimlane/ngx-charts'; import { FuseSharedModule } from '@fuse/shared.module'; +import { FuseSidebarModule } from '@fuse/components'; import { FuseWidgetModule } from '@fuse/components/widget/widget.module'; -import { FuseProjectDashboardComponent } from './project.component'; -import { ProjectDashboardService } from './project.service'; +import { ProjectDashboardComponent } from 'app/main/apps/dashboards/project/project.component'; +import { ProjectDashboardService } from 'app/main/apps/dashboards/project/project.service'; const routes: Routes = [ { path : '**', - component: FuseProjectDashboardComponent, + component: ProjectDashboardComponent, resolve : { data: ProjectDashboardService } @@ -24,7 +23,7 @@ const routes: Routes = [ @NgModule({ declarations: [ - FuseProjectDashboardComponent + ProjectDashboardComponent ], imports : [ RouterModule.forChild(routes), @@ -36,20 +35,20 @@ const routes: Routes = [ MatIconModule, MatMenuModule, MatSelectModule, - MatSidenavModule, MatTableModule, MatTabsModule, NgxChartsModule, FuseSharedModule, + FuseSidebarModule, FuseWidgetModule ], providers : [ ProjectDashboardService ] }) -export class FuseProjectDashboardModule +export class ProjectDashboardModule { } diff --git a/src/app/main/content/apps/dashboards/project/project.service.ts b/src/app/main/apps/dashboards/project/project.service.ts similarity index 77% rename from src/app/main/content/apps/dashboards/project/project.service.ts rename to src/app/main/apps/dashboards/project/project.service.ts index a1ee2128..d697fd32 100644 --- a/src/app/main/content/apps/dashboards/project/project.service.ts +++ b/src/app/main/apps/dashboards/project/project.service.ts @@ -9,14 +9,20 @@ export class ProjectDashboardService implements Resolve projects: any[]; widgets: any[]; + /** + * Constructor + * + * @param {HttpClient} _httpClient + */ constructor( - private http: HttpClient + private _httpClient: HttpClient ) { } /** - * Resolve + * Resolver + * * @param {ActivatedRouteSnapshot} route * @param {RouterStateSnapshot} state * @returns {Observable | Promise | any} @@ -38,10 +44,15 @@ export class ProjectDashboardService implements Resolve }); } + /** + * Get projects + * + * @returns {Promise} + */ getProjects(): Promise { return new Promise((resolve, reject) => { - this.http.get('api/project-dashboard-projects') + this._httpClient.get('api/project-dashboard-projects') .subscribe((response: any) => { this.projects = response; resolve(response); @@ -49,10 +60,15 @@ export class ProjectDashboardService implements Resolve }); } + /** + * Get widgets + * + * @returns {Promise} + */ getWidgets(): Promise { return new Promise((resolve, reject) => { - this.http.get('api/project-dashboard-widgets') + this._httpClient.get('api/project-dashboard-widgets') .subscribe((response: any) => { this.widgets = response; resolve(response); diff --git a/src/app/main/content/apps/e-commerce/dashboard/dashboard.component.html b/src/app/main/apps/e-commerce/dashboard/dashboard.component.html similarity index 91% rename from src/app/main/content/apps/e-commerce/dashboard/dashboard.component.html rename to src/app/main/apps/e-commerce/dashboard/dashboard.component.html index 49164a6b..a3806502 100644 --- a/src/app/main/content/apps/e-commerce/dashboard/dashboard.component.html +++ b/src/app/main/apps/e-commerce/dashboard/dashboard.component.html @@ -1,13 +1,15 @@ -
+
-
+
- +
@@ -57,7 +59,8 @@ - +
@@ -100,7 +103,8 @@ - +
@@ -143,7 +147,8 @@ - +
@@ -228,7 +233,8 @@ - +
@@ -260,13 +266,19 @@
-
- {{widgets.widget6.footerLeft.count[widget6.currentRange]}} +
+ + {{widgets.widget6.footerLeft.count[widget6.currentRange]}} + {{widgets.widget6.footerLeft.title}}
-
- {{widgets.widget6.footerRight.count[widget6.currentRange]}} +
+ + {{widgets.widget6.footerRight.count[widget6.currentRange]}} + {{widgets.widget6.footerRight.title}}
@@ -278,7 +290,8 @@ - +
diff --git a/src/app/main/content/apps/e-commerce/dashboard/dashboard.component.scss b/src/app/main/apps/e-commerce/dashboard/dashboard.component.scss similarity index 100% rename from src/app/main/content/apps/e-commerce/dashboard/dashboard.component.scss rename to src/app/main/apps/e-commerce/dashboard/dashboard.component.scss diff --git a/src/app/main/content/apps/e-commerce/dashboard/dashboard.component.ts b/src/app/main/apps/e-commerce/dashboard/dashboard.component.ts similarity index 67% rename from src/app/main/content/apps/e-commerce/dashboard/dashboard.component.ts rename to src/app/main/apps/e-commerce/dashboard/dashboard.component.ts index 5039c66f..684c021f 100644 --- a/src/app/main/content/apps/e-commerce/dashboard/dashboard.component.ts +++ b/src/app/main/apps/e-commerce/dashboard/dashboard.component.ts @@ -1,17 +1,17 @@ -import { Component, ViewEncapsulation } from '@angular/core'; +import { Component, OnInit, ViewEncapsulation } from '@angular/core'; import { fuseAnimations } from '@fuse/animations'; -import { EcommerceDashboardService } from './dashboard.service'; +import { EcommerceDashboardService } from 'app/main/apps/e-commerce/dashboard/dashboard.service'; @Component({ - selector : 'fuse-e-commerce-dashboard', + selector : 'e-commerce-dashboard', templateUrl : './dashboard.component.html', styleUrls : ['./dashboard.component.scss'], encapsulation: ViewEncapsulation.None, animations : fuseAnimations }) -export class FuseEcommerceDashboardComponent +export class EcommerceDashboardComponent implements OnInit { projects: any[]; selectedProject: any; @@ -21,12 +21,10 @@ export class FuseEcommerceDashboardComponent widget6: any = {}; widget7: any = {}; - constructor(private projectsDashboardService: EcommerceDashboardService) + constructor( + private _eCommerceDashboardService: EcommerceDashboardService + ) { - this.projects = this.projectsDashboardService.projects; - this.selectedProject = this.projects[0]; - this.widgets = this.projectsDashboardService.widgets; - /** * Widget 5 */ @@ -74,4 +72,18 @@ export class FuseEcommerceDashboardComponent }; } + + // ----------------------------------------------------------------------------------------------------- + // @ Lifecycle hooks + // ----------------------------------------------------------------------------------------------------- + + /** + * On init + */ + ngOnInit(): void + { + this.projects = this._eCommerceDashboardService.projects; + this.selectedProject = this.projects[0]; + this.widgets = this._eCommerceDashboardService.widgets; + } } diff --git a/src/app/main/content/apps/e-commerce/dashboard/dashboard.service.ts b/src/app/main/apps/e-commerce/dashboard/dashboard.service.ts similarity index 77% rename from src/app/main/content/apps/e-commerce/dashboard/dashboard.service.ts rename to src/app/main/apps/e-commerce/dashboard/dashboard.service.ts index 8810da76..625a215b 100644 --- a/src/app/main/content/apps/e-commerce/dashboard/dashboard.service.ts +++ b/src/app/main/apps/e-commerce/dashboard/dashboard.service.ts @@ -9,21 +9,26 @@ export class EcommerceDashboardService implements Resolve projects: any[]; widgets: any[]; + /** + * Constructor + * + * @param {HttpClient} _httpClient + */ constructor( - private http: HttpClient + private _httpClient: HttpClient ) { } /** - * Resolve + * Resolver + * * @param {ActivatedRouteSnapshot} route * @param {RouterStateSnapshot} state * @returns {Observable | Promise | any} */ resolve(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable | Promise | any { - return new Promise((resolve, reject) => { Promise.all([ @@ -38,10 +43,15 @@ export class EcommerceDashboardService implements Resolve }); } + /** + * Get projects + * + * @returns {Promise} + */ getProjects(): Promise { return new Promise((resolve, reject) => { - this.http.get('api/project-dashboard-projects') + this._httpClient.get('api/project-dashboard-projects') .subscribe((response: any) => { this.projects = response; resolve(response); @@ -49,10 +59,15 @@ export class EcommerceDashboardService implements Resolve }); } + /** + * Get widgets + * + * @returns {Promise} + */ getWidgets(): Promise { return new Promise((resolve, reject) => { - this.http.get('api/e-commerce-dashboard') + this._httpClient.get('api/e-commerce-dashboard') .subscribe((response: any) => { this.widgets = response; resolve(response); diff --git a/src/app/main/content/apps/e-commerce/e-commerce.module.ts b/src/app/main/apps/e-commerce/e-commerce.module.ts similarity index 56% rename from src/app/main/content/apps/e-commerce/e-commerce.module.ts rename to src/app/main/apps/e-commerce/e-commerce.module.ts index f6a09c35..b01a6ff2 100644 --- a/src/app/main/content/apps/e-commerce/e-commerce.module.ts +++ b/src/app/main/apps/e-commerce/e-commerce.module.ts @@ -1,65 +1,63 @@ import { NgModule } from '@angular/core'; import { RouterModule, Routes } from '@angular/router'; import { CdkTableModule } from '@angular/cdk/table'; - -import { MatButtonModule, MatChipsModule, MatFormFieldModule, MatIconModule, MatInputModule, MatPaginatorModule, MatRippleModule, MatSelectModule, MatSortModule, MatTableModule, MatTabsModule } from '@angular/material'; - +import { MatButtonModule, MatChipsModule, MatFormFieldModule, MatIconModule, MatInputModule, MatPaginatorModule, MatRippleModule, MatSelectModule, MatSnackBarModule, MatSortModule, MatTableModule, MatTabsModule } from '@angular/material'; import { NgxChartsModule } from '@swimlane/ngx-charts'; import { AgmCoreModule } from '@agm/core'; import { FuseSharedModule } from '@fuse/shared.module'; import { FuseWidgetModule } from '@fuse/components/widget/widget.module'; -import { FuseEcommerceDashboardComponent } from './dashboard/dashboard.component'; -import { EcommerceDashboardService } from './dashboard/dashboard.service'; -import { FuseEcommerceProductsComponent } from './products/products.component'; -import { EcommerceProductsService } from './products/products.service'; -import { FuseEcommerceProductComponent } from './product/product.component'; -import { EcommerceProductService } from './product/product.service'; -import { FuseEcommerceOrdersComponent } from './orders/orders.component'; -import { EcommerceOrdersService } from './orders/orders.service'; -import { FuseEcommerceOrderComponent } from './order/order.component'; -import { EcommerceOrderService } from './order/order.service'; +import { EcommerceDashboardComponent } from 'app/main/apps/e-commerce/dashboard/dashboard.component'; +import { EcommerceDashboardService } from 'app/main/apps/e-commerce/dashboard/dashboard.service'; +import { EcommerceProductsComponent } from 'app/main/apps/e-commerce/products/products.component'; +import { EcommerceProductsService } from 'app/main/apps/e-commerce/products/products.service'; +import { EcommerceProductComponent } from 'app/main/apps/e-commerce/product/product.component'; +import { EcommerceProductService } from 'app/main/apps/e-commerce/product/product.service'; +import { EcommerceOrdersComponent } from 'app/main/apps/e-commerce/orders/orders.component'; +import { EcommerceOrdersService } from 'app/main/apps/e-commerce/orders/orders.service'; +import { EcommerceOrderComponent } from 'app/main/apps/e-commerce/order/order.component'; +import { EcommerceOrderService } from 'app/main/apps/e-commerce/order/order.service'; const routes: Routes = [ { path : 'dashboard', - component: FuseEcommerceDashboardComponent, + component: EcommerceDashboardComponent, resolve : { data: EcommerceDashboardService } }, { path : 'products', - component: FuseEcommerceProductsComponent, + component: EcommerceProductsComponent, resolve : { data: EcommerceProductsService } }, { path : 'products/:id', - component: FuseEcommerceProductComponent, + component: EcommerceProductComponent, resolve : { data: EcommerceProductService } }, { path : 'products/:id/:handle', - component: FuseEcommerceProductComponent, + component: EcommerceProductComponent, resolve : { data: EcommerceProductService } }, { path : 'orders', - component: FuseEcommerceOrdersComponent, + component: EcommerceOrdersComponent, resolve : { data: EcommerceOrdersService } }, { path : 'orders/:id', - component: FuseEcommerceOrderComponent, + component: EcommerceOrderComponent, resolve : { data: EcommerceOrderService } @@ -68,11 +66,11 @@ const routes: Routes = [ @NgModule({ declarations: [ - FuseEcommerceDashboardComponent, - FuseEcommerceProductsComponent, - FuseEcommerceProductComponent, - FuseEcommerceOrdersComponent, - FuseEcommerceOrderComponent + EcommerceDashboardComponent, + EcommerceProductsComponent, + EcommerceProductComponent, + EcommerceOrdersComponent, + EcommerceOrderComponent ], imports : [ RouterModule.forChild(routes), @@ -87,6 +85,7 @@ const routes: Routes = [ MatRippleModule, MatSelectModule, MatSortModule, + MatSnackBarModule, MatTableModule, MatTabsModule, @@ -106,6 +105,6 @@ const routes: Routes = [ EcommerceOrderService ] }) -export class FuseEcommerceModule +export class EcommerceModule { } diff --git a/src/app/main/content/apps/e-commerce/order/order-statuses.ts b/src/app/main/apps/e-commerce/order/order-statuses.ts similarity index 100% rename from src/app/main/content/apps/e-commerce/order/order-statuses.ts rename to src/app/main/apps/e-commerce/order/order-statuses.ts diff --git a/src/app/main/content/apps/e-commerce/order/order.component.html b/src/app/main/apps/e-commerce/order/order.component.html similarity index 99% rename from src/app/main/content/apps/e-commerce/order/order.component.html rename to src/app/main/apps/e-commerce/order/order.component.html index 2987e515..4fbdc21b 100644 --- a/src/app/main/content/apps/e-commerce/order/order.component.html +++ b/src/app/main/apps/e-commerce/order/order.component.html @@ -1,4 +1,4 @@ -
+
@@ -8,7 +8,7 @@
-
@@ -19,7 +19,7 @@
+ [@animate]="{value:'*',params:{delay:'100ms',x:'-25px'}}">
Order {{order.reference}}
diff --git a/src/app/main/content/apps/e-commerce/order/order.component.scss b/src/app/main/apps/e-commerce/order/order.component.scss similarity index 100% rename from src/app/main/content/apps/e-commerce/order/order.component.scss rename to src/app/main/apps/e-commerce/order/order.component.scss 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/content/apps/e-commerce/order/order.model.ts b/src/app/main/apps/e-commerce/order/order.model.ts similarity index 93% rename from src/app/main/content/apps/e-commerce/order/order.model.ts rename to src/app/main/apps/e-commerce/order/order.model.ts index 9c2fb68d..dd3d4a39 100644 --- a/src/app/main/content/apps/e-commerce/order/order.model.ts +++ b/src/app/main/apps/e-commerce/order/order.model.ts @@ -15,6 +15,11 @@ export class Order payment: any; shippingDetails: any[]; + /** + * Constructor + * + * @param order + */ constructor(order?) { order = order || {}; diff --git a/src/app/main/content/apps/e-commerce/order/order.service.ts b/src/app/main/apps/e-commerce/order/order.service.ts similarity index 67% rename from src/app/main/content/apps/e-commerce/order/order.service.ts rename to src/app/main/apps/e-commerce/order/order.service.ts index b1f74180..45bcdbc9 100644 --- a/src/app/main/content/apps/e-commerce/order/order.service.ts +++ b/src/app/main/apps/e-commerce/order/order.service.ts @@ -8,23 +8,30 @@ export class EcommerceOrderService implements Resolve { routeParams: any; order: any; - onOrderChanged: BehaviorSubject = new BehaviorSubject({}); + onOrderChanged: BehaviorSubject; + /** + * Constructor + * + * @param {HttpClient} _httpClient + */ constructor( - private http: HttpClient + private _httpClient: HttpClient ) { + // Set the defaults + this.onOrderChanged = new BehaviorSubject({}); } /** - * Resolve + * Resolver + * * @param {ActivatedRouteSnapshot} route * @param {RouterStateSnapshot} state * @returns {Observable | Promise | any} */ resolve(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable | Promise | any { - this.routeParams = route.params; return new Promise((resolve, reject) => { @@ -40,10 +47,15 @@ export class EcommerceOrderService implements Resolve }); } + /** + * Get order + * + * @returns {Promise} + */ getOrder(): Promise { return new Promise((resolve, reject) => { - this.http.get('api/e-commerce-orders/' + this.routeParams.id) + this._httpClient.get('api/e-commerce-orders/' + this.routeParams.id) .subscribe((response: any) => { this.order = response; this.onOrderChanged.next(this.order); @@ -52,20 +64,32 @@ export class EcommerceOrderService implements Resolve }); } - saveOrder(order) + /** + * Save order + * + * @param order + * @returns {Promise} + */ + saveOrder(order): Promise { return new Promise((resolve, reject) => { - this.http.post('api/e-commerce-orders/' + order.id, order) + this._httpClient.post('api/e-commerce-orders/' + order.id, order) .subscribe((response: any) => { resolve(response); }, reject); }); } - addOrder(order) + /** + * Add order + * + * @param order + * @returns {Promise} + */ + addOrder(order): Promise { return new Promise((resolve, reject) => { - this.http.post('api/e-commerce-orders/', order) + this._httpClient.post('api/e-commerce-orders/', order) .subscribe((response: any) => { resolve(response); }, reject); diff --git a/src/app/main/content/apps/e-commerce/orders/orders.component.html b/src/app/main/apps/e-commerce/orders/orders.component.html similarity index 92% rename from src/app/main/content/apps/e-commerce/orders/orders.component.html rename to src/app/main/apps/e-commerce/orders/orders.component.html index 0b4462e6..0ea2bdce 100644 --- a/src/app/main/content/apps/e-commerce/orders/orders.component.html +++ b/src/app/main/apps/e-commerce/orders/orders.component.html @@ -1,4 +1,4 @@ -
+
@@ -8,15 +8,17 @@
-
@@ -92,7 +94,7 @@ - Status + Status

{{order.status[0].name}} diff --git a/src/app/main/content/apps/e-commerce/orders/orders.component.scss b/src/app/main/apps/e-commerce/orders/orders.component.scss similarity index 100% rename from src/app/main/content/apps/e-commerce/orders/orders.component.scss rename to src/app/main/apps/e-commerce/orders/orders.component.scss 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/content/apps/e-commerce/orders/orders.service.ts b/src/app/main/apps/e-commerce/orders/orders.service.ts similarity index 75% rename from src/app/main/content/apps/e-commerce/orders/orders.service.ts rename to src/app/main/apps/e-commerce/orders/orders.service.ts index 4ade65c8..989f5ac4 100644 --- a/src/app/main/content/apps/e-commerce/orders/orders.service.ts +++ b/src/app/main/apps/e-commerce/orders/orders.service.ts @@ -7,23 +7,30 @@ import { BehaviorSubject, Observable } from 'rxjs'; export class EcommerceOrdersService implements Resolve { orders: any[]; - onOrdersChanged: BehaviorSubject = new BehaviorSubject({}); + onOrdersChanged: BehaviorSubject; + /** + * Constructor + * + * @param {HttpClient} _httpClient + */ constructor( - private http: HttpClient + private _httpClient: HttpClient ) { + // Set the defaults + this.onOrdersChanged = new BehaviorSubject({}); } /** - * Resolve + * Resolver + * * @param {ActivatedRouteSnapshot} route * @param {RouterStateSnapshot} state * @returns {Observable | Promise | any} */ resolve(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable | Promise | any { - return new Promise((resolve, reject) => { Promise.all([ @@ -37,10 +44,15 @@ export class EcommerceOrdersService implements Resolve }); } + /** + * Get orders + * + * @returns {Promise} + */ getOrders(): Promise { return new Promise((resolve, reject) => { - this.http.get('api/e-commerce-orders') + this._httpClient.get('api/e-commerce-orders') .subscribe((response: any) => { this.orders = response; this.onOrdersChanged.next(this.orders); diff --git a/src/app/main/content/apps/e-commerce/product/product.component.html b/src/app/main/apps/e-commerce/product/product.component.html similarity index 96% rename from src/app/main/content/apps/e-commerce/product/product.component.html rename to src/app/main/apps/e-commerce/product/product.component.html index d1c683fb..967c1874 100644 --- a/src/app/main/content/apps/e-commerce/product/product.component.html +++ b/src/app/main/apps/e-commerce/product/product.component.html @@ -1,4 +1,4 @@ -

+
@@ -8,7 +8,7 @@
-
+
@@ -17,14 +17,13 @@ arrow_back -
+
+ [@animate]="{value:'*',params:{delay:'100ms',x:'-25px'}}">
{{product.name}}
diff --git a/src/app/main/content/apps/e-commerce/product/product.component.scss b/src/app/main/apps/e-commerce/product/product.component.scss similarity index 100% rename from src/app/main/content/apps/e-commerce/product/product.component.scss rename to src/app/main/apps/e-commerce/product/product.component.scss 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/content/apps/e-commerce/product/product.model.ts b/src/app/main/apps/e-commerce/product/product.model.ts similarity index 86% rename from src/app/main/content/apps/e-commerce/product/product.model.ts rename to src/app/main/apps/e-commerce/product/product.model.ts index a77e2596..3195482e 100644 --- a/src/app/main/content/apps/e-commerce/product/product.model.ts +++ b/src/app/main/apps/e-commerce/product/product.model.ts @@ -29,6 +29,11 @@ export class Product extraShippingFee: number; active: boolean; + /** + * Constructor + * + * @param product + */ constructor(product?) { product = product || {}; @@ -53,6 +58,11 @@ export class Product this.active = product.active || true; } + /** + * Add category + * + * @param {MatChipInputEvent} event + */ addCategory(event: MatChipInputEvent): void { const input = event.input; @@ -71,7 +81,12 @@ export class Product } } - removeCategory(category) + /** + * Remove category + * + * @param category + */ + removeCategory(category): void { const index = this.categories.indexOf(category); @@ -81,6 +96,11 @@ export class Product } } + /** + * Add tag + * + * @param {MatChipInputEvent} event + */ addTag(event: MatChipInputEvent): void { const input = event.input; @@ -99,7 +119,12 @@ export class Product } } - removeTag(tag) + /** + * Remove tag + * + * @param tag + */ + removeTag(tag): void { const index = this.tags.indexOf(tag); diff --git a/src/app/main/content/apps/e-commerce/product/product.service.ts b/src/app/main/apps/e-commerce/product/product.service.ts similarity index 68% rename from src/app/main/content/apps/e-commerce/product/product.service.ts rename to src/app/main/apps/e-commerce/product/product.service.ts index 50f4aa73..59d2eb49 100644 --- a/src/app/main/content/apps/e-commerce/product/product.service.ts +++ b/src/app/main/apps/e-commerce/product/product.service.ts @@ -8,23 +8,30 @@ export class EcommerceProductService implements Resolve { routeParams: any; product: any; - onProductChanged: BehaviorSubject = new BehaviorSubject({}); + onProductChanged: BehaviorSubject; + /** + * Constructor + * + * @param {HttpClient} _httpClient + */ constructor( - private http: HttpClient + private _httpClient: HttpClient ) { + // Set the defaults + this.onProductChanged = new BehaviorSubject({}); } /** - * Resolve + * Resolver + * * @param {ActivatedRouteSnapshot} route * @param {RouterStateSnapshot} state * @returns {Observable | Promise | any} */ resolve(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable | Promise | any { - this.routeParams = route.params; return new Promise((resolve, reject) => { @@ -40,6 +47,11 @@ export class EcommerceProductService implements Resolve }); } + /** + * Get product + * + * @returns {Promise} + */ getProduct(): Promise { return new Promise((resolve, reject) => { @@ -50,7 +62,7 @@ export class EcommerceProductService implements Resolve } else { - this.http.get('api/e-commerce-products/' + this.routeParams.id) + this._httpClient.get('api/e-commerce-products/' + this.routeParams.id) .subscribe((response: any) => { this.product = response; this.onProductChanged.next(this.product); @@ -60,20 +72,32 @@ export class EcommerceProductService implements Resolve }); } - saveProduct(product) + /** + * Save product + * + * @param product + * @returns {Promise} + */ + saveProduct(product): Promise { return new Promise((resolve, reject) => { - this.http.post('api/e-commerce-products/' + product.id, product) + this._httpClient.post('api/e-commerce-products/' + product.id, product) .subscribe((response: any) => { resolve(response); }, reject); }); } - addProduct(product) + /** + * Add product + * + * @param product + * @returns {Promise} + */ + addProduct(product): Promise { return new Promise((resolve, reject) => { - this.http.post('api/e-commerce-products/', product) + this._httpClient.post('api/e-commerce-products/', product) .subscribe((response: any) => { resolve(response); }, reject); diff --git a/src/app/main/content/apps/e-commerce/products/products.component.html b/src/app/main/apps/e-commerce/products/products.component.html similarity index 94% rename from src/app/main/content/apps/e-commerce/products/products.component.html rename to src/app/main/apps/e-commerce/products/products.component.html index cee86b70..3c8ccaed 100644 --- a/src/app/main/content/apps/e-commerce/products/products.component.html +++ b/src/app/main/apps/e-commerce/products/products.component.html @@ -1,4 +1,4 @@ -
+
@@ -8,18 +8,17 @@
-
diff --git a/src/app/main/content/apps/e-commerce/products/products.component.scss b/src/app/main/apps/e-commerce/products/products.component.scss similarity index 100% rename from src/app/main/content/apps/e-commerce/products/products.component.scss rename to src/app/main/apps/e-commerce/products/products.component.scss 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/content/apps/e-commerce/products/products.service.ts b/src/app/main/apps/e-commerce/products/products.service.ts similarity index 75% rename from src/app/main/content/apps/e-commerce/products/products.service.ts rename to src/app/main/apps/e-commerce/products/products.service.ts index 7b48839f..2abef83a 100644 --- a/src/app/main/content/apps/e-commerce/products/products.service.ts +++ b/src/app/main/apps/e-commerce/products/products.service.ts @@ -7,23 +7,30 @@ import { BehaviorSubject, Observable } from 'rxjs'; export class EcommerceProductsService implements Resolve { products: any[]; - onProductsChanged: BehaviorSubject = new BehaviorSubject({}); + onProductsChanged: BehaviorSubject; + /** + * Constructor + * + * @param {HttpClient} _httpClient + */ constructor( - private http: HttpClient + private _httpClient: HttpClient ) { + // Set the defaults + this.onProductsChanged = new BehaviorSubject({}); } /** - * Resolve + * Resolver + * * @param {ActivatedRouteSnapshot} route * @param {RouterStateSnapshot} state * @returns {Observable | Promise | any} */ resolve(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable | Promise | any { - return new Promise((resolve, reject) => { Promise.all([ @@ -37,10 +44,15 @@ export class EcommerceProductsService implements Resolve }); } + /** + * Get products + * + * @returns {Promise} + */ getProducts(): Promise { return new Promise((resolve, reject) => { - this.http.get('api/e-commerce-products') + this._httpClient.get('api/e-commerce-products') .subscribe((response: any) => { this.products = response; this.onProductsChanged.next(this.products); diff --git a/src/app/main/content/apps/file-manager/file-list/file-list.component.html b/src/app/main/apps/file-manager/file-list/file-list.component.html similarity index 85% rename from src/app/main/content/apps/file-manager/file-list/file-list.component.html rename to src/app/main/apps/file-manager/file-list/file-list.component.html index 83aef234..721b781b 100644 --- a/src/app/main/content/apps/file-manager/file-list/file-list.component.html +++ b/src/app/main/apps/file-manager/file-list/file-list.component.html @@ -1,4 +1,4 @@ - + @@ -42,8 +42,8 @@ - @@ -52,9 +52,8 @@ diff --git a/src/app/main/content/apps/file-manager/file-list/file-list.component.scss b/src/app/main/apps/file-manager/file-list/file-list.component.scss similarity index 100% rename from src/app/main/content/apps/file-manager/file-list/file-list.component.scss rename to src/app/main/apps/file-manager/file-list/file-list.component.scss 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/content/apps/file-manager/file-manager.service.ts b/src/app/main/apps/file-manager/file-manager.service.ts similarity index 70% rename from src/app/main/content/apps/file-manager/file-manager.service.ts rename to src/app/main/apps/file-manager/file-manager.service.ts index 0ef8bf8d..755c15cf 100644 --- a/src/app/main/content/apps/file-manager/file-manager.service.ts +++ b/src/app/main/apps/file-manager/file-manager.service.ts @@ -6,23 +6,32 @@ import { Observable, BehaviorSubject } from 'rxjs'; @Injectable() export class FileManagerService implements Resolve { - onFilesChanged: BehaviorSubject = new BehaviorSubject({}); - onFileSelected: BehaviorSubject = new BehaviorSubject({}); + onFilesChanged: BehaviorSubject; + onFileSelected: BehaviorSubject; - constructor(private http: HttpClient) + /** + * Constructor + * + * @param {HttpClient} _httpClient + */ + constructor( + private _httpClient: HttpClient + ) { + // Set the defaults + this.onFilesChanged = new BehaviorSubject({}); + this.onFileSelected = new BehaviorSubject({}); } /** - * The File Manager App Main Resolver - * + * Resolver + * * @param {ActivatedRouteSnapshot} route * @param {RouterStateSnapshot} state * @returns {Observable | Promise | any} */ resolve(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable | Promise | any { - return new Promise((resolve, reject) => { Promise.all([ @@ -36,10 +45,15 @@ export class FileManagerService implements Resolve }); } + /** + * Get files + * + * @returns {Promise} + */ getFiles(): Promise { return new Promise((resolve, reject) => { - this.http.get('api/file-manager') + this._httpClient.get('api/file-manager') .subscribe((response: any) => { this.onFilesChanged.next(response); this.onFileSelected.next(response[0]); diff --git a/src/app/main/content/apps/file-manager/sidenavs/details/details.component.html b/src/app/main/apps/file-manager/sidebars/details/details.component.html similarity index 91% rename from src/app/main/content/apps/file-manager/sidenavs/details/details.component.html rename to src/app/main/apps/file-manager/sidebars/details/details.component.html index 12fc9450..08c29a70 100644 --- a/src/app/main/content/apps/file-manager/sidenavs/details/details.component.html +++ b/src/app/main/apps/file-manager/sidebars/details/details.component.html @@ -1,4 +1,4 @@ - +
@@ -24,13 +24,12 @@
- + - +
-
+
@@ -81,4 +80,4 @@
- + diff --git a/src/app/main/content/apps/file-manager/sidenavs/details/details.component.scss b/src/app/main/apps/file-manager/sidebars/details/details.component.scss similarity index 98% rename from src/app/main/content/apps/file-manager/sidenavs/details/details.component.scss rename to src/app/main/apps/file-manager/sidebars/details/details.component.scss index 26ea45b6..9641f6bf 100644 --- a/src/app/main/content/apps/file-manager/sidenavs/details/details.component.scss +++ b/src/app/main/apps/file-manager/sidebars/details/details.component.scss @@ -1,7 +1,7 @@ :host { display: flex; flex-direction: column; - flex: 1 0 auto; + flex: 1 1 auto; height: 100%; > .header { 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/content/apps/file-manager/sidenavs/main/main.component.html b/src/app/main/apps/file-manager/sidebars/main/main.component.html similarity index 89% rename from src/app/main/content/apps/file-manager/sidenavs/main/main.component.html rename to src/app/main/apps/file-manager/sidebars/main/main.component.html index 0e17eb64..4b1eccb2 100644 --- a/src/app/main/content/apps/file-manager/sidenavs/main/main.component.html +++ b/src/app/main/apps/file-manager/sidebars/main/main.component.html @@ -1,15 +1,15 @@ - +
- + - +
- + diff --git a/src/app/main/content/apps/file-manager/sidenavs/main/main.component.scss b/src/app/main/apps/file-manager/sidebars/main/main.component.scss similarity index 100% rename from src/app/main/content/apps/file-manager/sidenavs/main/main.component.scss rename to src/app/main/apps/file-manager/sidebars/main/main.component.scss diff --git a/src/app/main/content/apps/file-manager/sidenavs/main/main.component.ts b/src/app/main/apps/file-manager/sidebars/main/main.component.ts similarity index 66% rename from src/app/main/content/apps/file-manager/sidenavs/main/main.component.ts rename to src/app/main/apps/file-manager/sidebars/main/main.component.ts index eea05124..0ab0bc90 100644 --- a/src/app/main/content/apps/file-manager/sidenavs/main/main.component.ts +++ b/src/app/main/apps/file-manager/sidebars/main/main.component.ts @@ -1,11 +1,11 @@ import { Component } from '@angular/core'; @Component({ - selector : 'fuse-file-manager-main-sidenav', + selector : 'file-manager-main-sidebar', templateUrl: './main.component.html', styleUrls : ['./main.component.scss'] }) -export class FuseFileManagerMainSidenavComponent +export class FileManagerMainSidebarComponent { selected: any; diff --git a/src/app/main/content/apps/mail-ngrx/dialogs/compose/compose.component.html b/src/app/main/apps/mail-ngrx/dialogs/compose/compose.component.html similarity index 92% rename from src/app/main/content/apps/mail-ngrx/dialogs/compose/compose.component.html rename to src/app/main/apps/mail-ngrx/dialogs/compose/compose.component.html index 1550fcf1..9a82ce7e 100644 --- a/src/app/main/content/apps/mail-ngrx/dialogs/compose/compose.component.html +++ b/src/app/main/apps/mail-ngrx/dialogs/compose/compose.component.html @@ -2,7 +2,7 @@ New Message - @@ -86,7 +86,7 @@
- diff --git a/src/app/main/content/apps/mail-ngrx/dialogs/compose/compose.component.scss b/src/app/main/apps/mail-ngrx/dialogs/compose/compose.component.scss similarity index 96% rename from src/app/main/content/apps/mail-ngrx/dialogs/compose/compose.component.scss rename to src/app/main/apps/mail-ngrx/dialogs/compose/compose.component.scss index 87d41f50..4614e96b 100644 --- a/src/app/main/content/apps/mail-ngrx/dialogs/compose/compose.component.scss +++ b/src/app/main/apps/mail-ngrx/dialogs/compose/compose.component.scss @@ -1,4 +1,5 @@ -.mail-compose-dialog { +.mail-ngrx-compose-dialog { + .mat-dialog-container { padding: 0; width: 720px; 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/content/apps/mail-ngrx/i18n/en.ts b/src/app/main/apps/mail-ngrx/i18n/en.ts similarity index 100% rename from src/app/main/content/apps/mail-ngrx/i18n/en.ts rename to src/app/main/apps/mail-ngrx/i18n/en.ts diff --git a/src/app/main/content/apps/mail-ngrx/i18n/tr.ts b/src/app/main/apps/mail-ngrx/i18n/tr.ts similarity index 100% rename from src/app/main/content/apps/mail-ngrx/i18n/tr.ts rename to src/app/main/apps/mail-ngrx/i18n/tr.ts diff --git a/src/app/main/content/apps/mail-ngrx/mail-details/mail-details.component.html b/src/app/main/apps/mail-ngrx/mail-details/mail-details.component.html similarity index 100% rename from src/app/main/content/apps/mail-ngrx/mail-details/mail-details.component.html rename to src/app/main/apps/mail-ngrx/mail-details/mail-details.component.html diff --git a/src/app/main/content/apps/mail-ngrx/mail-details/mail-details.component.scss b/src/app/main/apps/mail-ngrx/mail-details/mail-details.component.scss similarity index 100% rename from src/app/main/content/apps/mail-ngrx/mail-details/mail-details.component.scss rename to src/app/main/apps/mail-ngrx/mail-details/mail-details.component.scss 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/content/apps/mail-ngrx/mail-list/mail-list-item/mail-list-item.component.html b/src/app/main/apps/mail-ngrx/mail-list/mail-list-item/mail-list-item.component.html similarity index 94% rename from src/app/main/content/apps/mail-ngrx/mail-list/mail-list-item/mail-list-item.component.html rename to src/app/main/apps/mail-ngrx/mail-list/mail-list-item/mail-list-item.component.html index f9224cbc..4df2f5d8 100644 --- a/src/app/main/content/apps/mail-ngrx/mail-list/mail-list-item/mail-list-item.component.html +++ b/src/app/main/apps/mail-ngrx/mail-list/mail-list-item/mail-list-item.component.html @@ -10,7 +10,7 @@
{{mail.from?.name}} -
{{mail.from?.name[0]}}
+
{{mail.from?.name[0]}}
{{mail.from?.name}} attachment
diff --git a/src/app/main/content/apps/mail-ngrx/mail-list/mail-list-item/mail-list-item.component.scss b/src/app/main/apps/mail-ngrx/mail-list/mail-list-item/mail-list-item.component.scss similarity index 83% rename from src/app/main/content/apps/mail-ngrx/mail-list/mail-list-item/mail-list-item.component.scss rename to src/app/main/apps/mail-ngrx/mail-list/mail-list-item/mail-list-item.component.scss index 89566a09..7eb73acf 100644 --- a/src/app/main/content/apps/mail-ngrx/mail-list/mail-list-item/mail-list-item.component.scss +++ b/src/app/main/apps/mail-ngrx/mail-list/mail-list-item/mail-list-item.component.scss @@ -44,20 +44,6 @@ } } - &.current-mail { - background: #E3F2FD; - - .info { - - .row-2 { - - .labels { - background: #E3F2FD; - } - } - } - } - .info { overflow: hidden; width: 0; @@ -76,7 +62,6 @@ width: 32px; height: 32px; line-height: 32px; - background-color: mat-color($accent); } } @@ -104,11 +89,7 @@ } .labels { - position: absolute; - background: #FFFFFF; - bottom: 0; - right: 0; - padding-left: 6px; + margin-top: 8px; .label { font-size: 11px; diff --git a/src/app/main/content/apps/mail-ngrx/mail-list/mail-list-item/mail-list-item.component.ts b/src/app/main/apps/mail-ngrx/mail-list/mail-list-item/mail-list-item.component.ts similarity index 93% rename from src/app/main/content/apps/mail-ngrx/mail-list/mail-list-item/mail-list-item.component.ts rename to src/app/main/apps/mail-ngrx/mail-list/mail-list-item/mail-list-item.component.ts index f4a2d719..09ede37d 100644 --- a/src/app/main/content/apps/mail-ngrx/mail-list/mail-list-item/mail-list-item.component.ts +++ b/src/app/main/apps/mail-ngrx/mail-list/mail-list-item/mail-list-item.component.ts @@ -7,12 +7,12 @@ import { Mail } from '../../mail.model'; import * as fromStore from '../../store'; @Component({ - selector : 'fuse-mail-list-item', + selector : 'mail-ngrx-list-item', templateUrl : './mail-list-item.component.html', styleUrls : ['./mail-list-item.component.scss'], changeDetection: ChangeDetectionStrategy.OnPush }) -export class FuseMailNgrxListItemComponent implements OnInit +export class MailNgrxListItemComponent implements OnInit { @Input() mail: Mail; @HostBinding('class.selected') selected: boolean; diff --git a/src/app/main/content/apps/mail-ngrx/mail-list/mail-list.component.html b/src/app/main/apps/mail-ngrx/mail-list/mail-list.component.html similarity index 58% rename from src/app/main/content/apps/mail-ngrx/mail-list/mail-list.component.html rename to src/app/main/apps/mail-ngrx/mail-list/mail-list.component.html index bb5903db..2f5a9bb1 100644 --- a/src/app/main/content/apps/mail-ngrx/mail-list/mail-list.component.html +++ b/src/app/main/apps/mail-ngrx/mail-list/mail-list.component.html @@ -3,7 +3,7 @@
- - + +
diff --git a/src/app/main/content/apps/mail-ngrx/mail-list/mail-list.component.scss b/src/app/main/apps/mail-ngrx/mail-list/mail-list.component.scss similarity index 100% rename from src/app/main/content/apps/mail-ngrx/mail-list/mail-list.component.scss rename to src/app/main/apps/mail-ngrx/mail-list/mail-list.component.scss 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/content/apps/mail/mail.component.scss b/src/app/main/apps/mail-ngrx/mail.component.scss similarity index 86% rename from src/app/main/content/apps/mail/mail.component.scss rename to src/app/main/apps/mail-ngrx/mail.component.scss index cca33765..79154e90 100644 --- a/src/app/main/content/apps/mail/mail.component.scss +++ b/src/app/main/apps/mail-ngrx/mail.component.scss @@ -10,7 +10,7 @@ .search-wrapper { @include mat-elevation(7); - .sidenav-toggle { + .sidebar-toggle { margin: 0; width: 56px; height: 56px; @@ -40,16 +40,16 @@ @include media-breakpoint(xs) { - fuse-mail-list { + mail-list { border-right: none; } - fuse-mail-list, - fuse-mail-details { + mail-list, + mail-details { flex: 1 0 100%; } - fuse-mail-details { + mail-details { display: none !important; } @@ -65,11 +65,11 @@ .content { - fuse-mail-list { + mail-list { display: none !important; } - fuse-mail-details { + mail-details { display: flex !important; } } 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/content/apps/mail-ngrx/mail.model.ts b/src/app/main/apps/mail-ngrx/mail.model.ts similarity index 79% rename from src/app/main/content/apps/mail-ngrx/mail.model.ts rename to src/app/main/apps/mail-ngrx/mail.model.ts index 725bc915..0c015c30 100644 --- a/src/app/main/content/apps/mail-ngrx/mail.model.ts +++ b/src/app/main/apps/mail-ngrx/mail.model.ts @@ -27,6 +27,11 @@ export class Mail labels: string[]; folder: string; + /** + * Constructor + * + * @param mail + */ constructor(mail) { this.id = mail.id; @@ -44,22 +49,34 @@ export class Mail this.folder = mail.folder; } - toggleStar() + /** + * Toggle star + */ + toggleStar(): void { this.starred = !this.starred; } - toggleImportant() + /** + * Toggle important + */ + toggleImportant(): void { this.important = !this.important; } - markRead() + /** + * Mark as read + */ + markRead(): void { this.read = true; } - markUnRead() + /** + * Mark as unread + */ + markUnread(): void { this.read = false; } 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/content/apps/mail-ngrx/sidenavs/main/main-sidenav.component.html b/src/app/main/apps/mail-ngrx/sidebars/main/main-sidebar.component.html similarity index 86% rename from src/app/main/content/apps/mail-ngrx/sidenavs/main/main-sidenav.component.html rename to src/app/main/apps/mail-ngrx/sidebars/main/main-sidebar.component.html index a3d8f041..952081db 100644 --- a/src/app/main/content/apps/mail-ngrx/sidenavs/main/main-sidenav.component.html +++ b/src/app/main/apps/mail-ngrx/sidebars/main/main-sidebar.component.html @@ -1,6 +1,6 @@ - +
+ class="header mat-accent-bg p-24 pb-4">
- + - +
@@ -39,7 +39,8 @@ + + + +
+ + +
+ +
+ + + + + + + + + + + + + + +
+ + + + + + + + + + + + +
+ +
+ +
+
+ + + +
+ + + + +
+ + +
+ + +
+ + +
diff --git a/src/app/main/content/apps/mail-ngrx/mail.component.scss b/src/app/main/apps/mail/mail.component.scss similarity index 86% rename from src/app/main/content/apps/mail-ngrx/mail.component.scss rename to src/app/main/apps/mail/mail.component.scss index cca33765..79154e90 100644 --- a/src/app/main/content/apps/mail-ngrx/mail.component.scss +++ b/src/app/main/apps/mail/mail.component.scss @@ -10,7 +10,7 @@ .search-wrapper { @include mat-elevation(7); - .sidenav-toggle { + .sidebar-toggle { margin: 0; width: 56px; height: 56px; @@ -40,16 +40,16 @@ @include media-breakpoint(xs) { - fuse-mail-list { + mail-list { border-right: none; } - fuse-mail-list, - fuse-mail-details { + mail-list, + mail-details { flex: 1 0 100%; } - fuse-mail-details { + mail-details { display: none !important; } @@ -65,11 +65,11 @@ .content { - fuse-mail-list { + mail-list { display: none !important; } - fuse-mail-details { + mail-details { display: flex !important; } } 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/content/apps/mail/mail.model.ts b/src/app/main/apps/mail/mail.model.ts similarity index 95% rename from src/app/main/content/apps/mail/mail.model.ts rename to src/app/main/apps/mail/mail.model.ts index 42ff6cf5..7b36a600 100644 --- a/src/app/main/content/apps/mail/mail.model.ts +++ b/src/app/main/apps/mail/mail.model.ts @@ -27,6 +27,11 @@ export class Mail labels: string[]; folder: string; + /** + * Constructor + * + * @param mail + */ constructor(mail) { this.id = mail.id; diff --git a/src/app/main/content/apps/mail/mail.module.ts b/src/app/main/apps/mail/mail.module.ts similarity index 55% rename from src/app/main/content/apps/mail/mail.module.ts rename to src/app/main/apps/mail/mail.module.ts index a9b177f9..cc387f73 100644 --- a/src/app/main/content/apps/mail/mail.module.ts +++ b/src/app/main/apps/mail/mail.module.ts @@ -1,59 +1,58 @@ import { NgModule } from '@angular/core'; import { RouterModule, Routes } from '@angular/router'; - -import { MatButtonModule, MatCheckboxModule, MatDialogModule, MatFormFieldModule, MatIconModule, MatInputModule, MatMenuModule, MatRippleModule, MatSelectModule, MatSidenavModule, MatToolbarModule } from '@angular/material'; - +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 { MailService } from './mail.service'; -import { FuseMailComponent } from './mail.component'; -import { FuseMailMainSidenavComponent } from './sidenavs/main/main-sidenav.component'; -import { FuseMailListItemComponent } from './mail-list/mail-list-item/mail-list-item.component'; -import { FuseMailListComponent } from './mail-list/mail-list.component'; -import { FuseMailDetailsComponent } from './mail-details/mail-details.component'; -import { FuseMailComposeDialogComponent } from './dialogs/compose/compose.component'; +import { MailService } from 'app/main/apps/mail/mail.service'; +import { MailComponent } from 'app/main/apps/mail/mail.component'; +import { MailListComponent } from 'app/main/apps/mail/mail-list/mail-list.component'; +import { MailListItemComponent } from 'app/main/apps/mail/mail-list/mail-list-item/mail-list-item.component'; +import { MailDetailsComponent } from 'app/main/apps/mail/mail-details/mail-details.component'; +import { MailMainSidebarComponent } from 'app/main/apps/mail/sidebars/main/main-sidebar.component'; +import { MailComposeDialogComponent } from 'app/main/apps/mail/dialogs/compose/compose.component'; const routes: Routes = [ { path : 'label/:labelHandle', - component: FuseMailComponent, + component: MailComponent, resolve : { mail: MailService } }, { path : 'label/:labelHandle/:mailId', - component: FuseMailComponent, + component: MailComponent, resolve : { mail: MailService } }, { path : 'filter/:filterHandle', - component: FuseMailComponent, + component: MailComponent, resolve : { mail: MailService } }, { path : 'filter/:filterHandle/:mailId', - component: FuseMailComponent, + component: MailComponent, resolve : { mail: MailService } }, { path : ':folderHandle', - component: FuseMailComponent, + component: MailComponent, resolve : { mail: MailService } }, { path : ':folderHandle/:mailId', - component: FuseMailComponent, + component: MailComponent, resolve : { mail: MailService } @@ -66,12 +65,12 @@ const routes: Routes = [ @NgModule({ declarations : [ - FuseMailComponent, - FuseMailListComponent, - FuseMailListItemComponent, - FuseMailDetailsComponent, - FuseMailMainSidenavComponent, - FuseMailComposeDialogComponent + MailComponent, + MailListComponent, + MailListItemComponent, + MailDetailsComponent, + MailMainSidebarComponent, + MailComposeDialogComponent ], imports : [ RouterModule.forChild(routes), @@ -85,18 +84,20 @@ const routes: Routes = [ MatMenuModule, MatRippleModule, MatSelectModule, - MatSidenavModule, MatToolbarModule, TranslateModule, - FuseSharedModule + FuseSharedModule, + FuseSidebarModule ], providers : [ MailService ], - entryComponents: [FuseMailComposeDialogComponent] + entryComponents: [ + MailComposeDialogComponent + ] }) -export class FuseMailModule +export class MailModule { } diff --git a/src/app/main/content/apps/mail/mail.service.ts b/src/app/main/apps/mail/mail.service.ts similarity index 81% rename from src/app/main/content/apps/mail/mail.service.ts rename to src/app/main/apps/mail/mail.service.ts index de0c7d50..95dcdca8 100644 --- a/src/app/main/content/apps/mail/mail.service.ts +++ b/src/app/main/apps/mail/mail.service.ts @@ -5,7 +5,7 @@ import { BehaviorSubject, Observable } from 'rxjs'; import { FuseUtils } from '@fuse/utils'; -import { Mail } from './mail.model'; +import { Mail } from 'app/main/apps/mail/mail.model'; @Injectable() export class MailService implements Resolve @@ -20,22 +20,37 @@ export class MailService implements Resolve labels: any[]; routeParams: any; - onMailsChanged: BehaviorSubject = new BehaviorSubject([]); - onSelectedMailsChanged: BehaviorSubject = new BehaviorSubject([]); - onCurrentMailChanged: BehaviorSubject = new BehaviorSubject([]); + onMailsChanged: BehaviorSubject; + onSelectedMailsChanged: BehaviorSubject; + onCurrentMailChanged: BehaviorSubject; + onFoldersChanged: BehaviorSubject; + onFiltersChanged: BehaviorSubject; + onLabelsChanged: BehaviorSubject; + onSearchTextChanged: BehaviorSubject; - onFoldersChanged: BehaviorSubject = new BehaviorSubject([]); - onFiltersChanged: BehaviorSubject = new BehaviorSubject([]); - onLabelsChanged: BehaviorSubject = new BehaviorSubject([]); - onSearchTextChanged: BehaviorSubject = new BehaviorSubject(''); - - constructor(private http: HttpClient) + /** + * Constructor + * + * @param {HttpClient} _httpClient + */ + constructor( + private _httpClient: HttpClient + ) { + // Set the defaults this.selectedMails = []; + this.onMailsChanged = new BehaviorSubject([]); + this.onSelectedMailsChanged = new BehaviorSubject([]); + this.onCurrentMailChanged = new BehaviorSubject([]); + this.onFoldersChanged = new BehaviorSubject([]); + this.onFiltersChanged = new BehaviorSubject([]); + this.onLabelsChanged = new BehaviorSubject([]); + this.onSearchTextChanged = new BehaviorSubject(''); } /** - * Resolve + * Resolver + * * @param {ActivatedRouteSnapshot} route * @param {RouterStateSnapshot} state * @returns {Observable | Promise | any} @@ -83,12 +98,13 @@ export class MailService implements Resolve /** * Get all folders + * * @returns {Promise} */ getFolders(): Promise { return new Promise((resolve, reject) => { - this.http.get('api/mail-folders') + this._httpClient.get('api/mail-folders') .subscribe((response: any) => { this.folders = response; this.onFoldersChanged.next(this.folders); @@ -99,12 +115,13 @@ export class MailService implements Resolve /** * Get all filters + * * @returns {Promise} */ getFilters(): Promise { return new Promise((resolve, reject) => { - this.http.get('api/mail-filters') + this._httpClient.get('api/mail-filters') .subscribe((response: any) => { this.filters = response; this.onFiltersChanged.next(this.filters); @@ -115,12 +132,13 @@ export class MailService implements Resolve /** * Get all labels + * * @returns {Promise} */ getLabels(): Promise { return new Promise((resolve, reject) => { - this.http.get('api/mail-labels') + this._httpClient.get('api/mail-labels') .subscribe((response: any) => { this.labels = response; this.onLabelsChanged.next(this.labels); @@ -131,6 +149,7 @@ export class MailService implements Resolve /** * Get all mails + * * @returns {Promise} */ getMails(): Promise @@ -150,6 +169,7 @@ export class MailService implements Resolve /** * Get mails by folder + * * @param handle * @returns {Promise} */ @@ -157,12 +177,12 @@ export class MailService implements Resolve { return new Promise((resolve, reject) => { - this.http.get('api/mail-folders?handle=' + handle) + this._httpClient.get('api/mail-folders?handle=' + handle) .subscribe((folders: any) => { const folderId = folders[0].id; - this.http.get('api/mail-mails?folder=' + folderId) + this._httpClient.get('api/mail-mails?folder=' + folderId) .subscribe((mails: any) => { this.mails = mails.map(mail => { @@ -182,6 +202,7 @@ export class MailService implements Resolve /** * Get mails by filter + * * @param handle * @returns {Promise} */ @@ -189,7 +210,7 @@ export class MailService implements Resolve { return new Promise((resolve, reject) => { - this.http.get('api/mail-mails?' + handle + '=true') + this._httpClient.get('api/mail-mails?' + handle + '=true') .subscribe((mails: any) => { this.mails = mails.map(mail => { @@ -208,18 +229,19 @@ export class MailService implements Resolve /** * Get mails by label + * * @param handle * @returns {Promise} */ getMailsByLabel(handle): Promise { return new Promise((resolve, reject) => { - this.http.get('api/mail-labels?handle=' + handle) + this._httpClient.get('api/mail-labels?handle=' + handle) .subscribe((labels: any) => { const labelId = labels[0].id; - this.http.get('api/mail-mails?labels=' + labelId) + this._httpClient.get('api/mail-mails?labels=' + labelId) .subscribe((mails: any) => { this.mails = mails.map(mail => { @@ -239,9 +261,10 @@ export class MailService implements Resolve /** * Toggle selected mail by id + * * @param id */ - toggleSelectedMail(id) + toggleSelectedMail(id): void { // First, check if we already have that mail as selected... if ( this.selectedMails.length > 0 ) @@ -281,7 +304,7 @@ export class MailService implements Resolve /** * Toggle select all */ - toggleSelectAll() + toggleSelectAll(): void { if ( this.selectedMails.length > 0 ) { @@ -294,7 +317,13 @@ export class MailService implements Resolve } - selectMails(filterParameter?, filterValue?) + /** + * Select mails + * + * @param filterParameter + * @param filterValue + */ + selectMails(filterParameter?, filterValue?): void { this.selectedMails = []; @@ -316,7 +345,10 @@ export class MailService implements Resolve this.onSelectedMailsChanged.next(this.selectedMails); } - deselectMails() + /** + * Deselect mails + */ + deselectMails(): void { this.selectedMails = []; @@ -326,9 +358,10 @@ export class MailService implements Resolve /** * Set current mail by id + * * @param id */ - setCurrentMail(id) + setCurrentMail(id): void { this.currentMail = this.mails.find(mail => { return mail.id === id; @@ -339,9 +372,10 @@ export class MailService implements Resolve /** * Toggle label on selected mails + * * @param labelId */ - toggleLabelOnSelectedMails(labelId) + toggleLabelOnSelectedMails(labelId): void { this.selectedMails.map(mail => { @@ -362,9 +396,10 @@ export class MailService implements Resolve /** * Set folder on selected mails + * * @param folderId */ - setFolderOnSelectedMails(folderId) + setFolderOnSelectedMails(folderId): void { this.selectedMails.map(mail => { mail.folder = folderId; @@ -377,14 +412,15 @@ export class MailService implements Resolve /** * Update the mail + * * @param mail * @returns {Promise} */ - updateMail(mail) + updateMail(mail): Promise { return new Promise((resolve, reject) => { - this.http.post('api/mail-mails/' + mail.id, {...mail}) + this._httpClient.post('api/mail-mails/' + mail.id, {...mail}) .subscribe(response => { this.getMails().then(mails => { @@ -400,5 +436,4 @@ export class MailService implements Resolve }); }); } - } diff --git a/src/app/main/content/apps/mail/sidenavs/main/main-sidenav.component.html b/src/app/main/apps/mail/sidebars/main/main-sidebar.component.html similarity index 71% rename from src/app/main/content/apps/mail/sidenavs/main/main-sidenav.component.html rename to src/app/main/apps/mail/sidebars/main/main-sidebar.component.html index e467ee42..4b9022a7 100644 --- a/src/app/main/content/apps/mail/sidenavs/main/main-sidenav.component.html +++ b/src/app/main/apps/mail/sidebars/main/main-sidebar.component.html @@ -1,13 +1,14 @@ - +
+ class="header mat-accent-bg p-24 pb-4"> - - diff --git a/src/app/main/content/apps/scrumboard/board/dialogs/card/card.component.scss b/src/app/main/apps/scrumboard/board/dialogs/card/card.component.scss similarity index 100% rename from src/app/main/content/apps/scrumboard/board/dialogs/card/card.component.scss rename to src/app/main/apps/scrumboard/board/dialogs/card/card.component.scss diff --git a/src/app/main/content/apps/scrumboard/board/dialogs/card/card.component.ts b/src/app/main/apps/scrumboard/board/dialogs/card/card.component.ts similarity index 57% rename from src/app/main/content/apps/scrumboard/board/dialogs/card/card.component.ts rename to src/app/main/apps/scrumboard/board/dialogs/card/card.component.ts index a8c8dff9..4bc04c73 100644 --- a/src/app/main/content/apps/scrumboard/board/dialogs/card/card.component.ts +++ b/src/app/main/apps/scrumboard/board/dialogs/card/card.component.ts @@ -1,74 +1,108 @@ import { Component, Inject, OnDestroy, OnInit, ViewChild, ViewEncapsulation } from '@angular/core'; import { NgForm } from '@angular/forms/src/forms'; import { MAT_DIALOG_DATA, MatDialog, MatDialogRef, MatMenuTrigger } from '@angular/material'; - -import { Subscription } from 'rxjs'; +import { Subject } from 'rxjs'; import { FuseConfirmDialogComponent } from '@fuse/components/confirm-dialog/confirm-dialog.component'; import { FuseUtils } from '@fuse/utils'; -import { ScrumboardService } from '../../../scrumboard.service'; +import { ScrumboardService } from 'app/main/apps/scrumboard/scrumboard.service'; +import { takeUntil } from 'rxjs/operators'; @Component({ - selector : 'fuse-scrumboard-board-card-dialog', + selector : 'scrumboard-board-card-dialog', templateUrl : './card.component.html', styleUrls : ['./card.component.scss'], encapsulation: ViewEncapsulation.None }) -export class FuseScrumboardCardDialogComponent implements OnInit, OnDestroy +export class ScrumboardCardDialogComponent implements OnInit, OnDestroy { card: any; board: any; list: any; - onBoardChanged: Subscription; toggleInArray = FuseUtils.toggleInArray; - - @ViewChild('checklistMenuTrigger') checklistMenu: MatMenuTrigger; - @ViewChild('newCheckListTitleField') newCheckListTitleField; - confirmDialogRef: MatDialogRef; + @ViewChild('checklistMenuTrigger') + checklistMenu: MatMenuTrigger; + + @ViewChild('newCheckListTitleField') + newCheckListTitleField; + + // Private + private _unsubscribeAll: Subject; + + /** + * Constructor + * + * @param {MatDialogRef} _matDialogRef + * @param _data + * @param {MatDialog} _matDialog + * @param {ScrumboardService} _scrumboardService + */ constructor( - public dialogRef: MatDialogRef, - @Inject(MAT_DIALOG_DATA) private data: any, - public dialog: MatDialog, - private scrumboardService: ScrumboardService + private _matDialogRef: MatDialogRef, + @Inject(MAT_DIALOG_DATA) private _data: any, + private _matDialog: MatDialog, + private _scrumboardService: ScrumboardService ) { - + // Set the private defaults + this._unsubscribeAll = new Subject(); } - ngOnInit() + // ----------------------------------------------------------------------------------------------------- + // @ Lifecycle hooks + // ----------------------------------------------------------------------------------------------------- + + /** + * On init + */ + ngOnInit(): void { - this.onBoardChanged = - this.scrumboardService.onBoardChanged - .subscribe(board => { - this.board = board; + this._scrumboardService.onBoardChanged + .pipe(takeUntil(this._unsubscribeAll)) + .subscribe(board => { + this.board = board; - this.card = this.board.cards.find((_card) => { - return this.data.cardId === _card.id; - }); - - this.list = this.board.lists.find((_list) => { - return this.data.listId === _list.id; - }); + this.card = this.board.cards.find((_card) => { + return this._data.cardId === _card.id; }); + + this.list = this.board.lists.find((_list) => { + return this._data.listId === _list.id; + }); + }); } /** - * Remove Due date + * On destroy */ - removeDueDate() + ngOnDestroy(): void + { + // Unsubscribe from all subscriptions + this._unsubscribeAll.next(); + this._unsubscribeAll.complete(); + } + + // ----------------------------------------------------------------------------------------------------- + // @ Public methods + // ----------------------------------------------------------------------------------------------------- + + /** + * Remove due date + */ + removeDueDate(): void { this.card.due = ''; this.updateCard(); } /** - * Toggle Subscribe + * Toggle subscribe */ - toggleSubscribe() + toggleSubscribe(): void { this.card.subscribed = !this.card.subscribed; @@ -76,10 +110,11 @@ export class FuseScrumboardCardDialogComponent implements OnInit, OnDestroy } /** - * Toggle Cover Image + * Toggle cover image + * * @param attachmentId */ - toggleCoverImage(attachmentId) + toggleCoverImage(attachmentId): void { if ( this.card.idAttachmentCover === attachmentId ) { @@ -94,10 +129,11 @@ export class FuseScrumboardCardDialogComponent implements OnInit, OnDestroy } /** - * Remove Attachment + * Remove attachment + * * @param attachment */ - removeAttachment(attachment) + removeAttachment(attachment): void { if ( attachment.id === this.card.idAttachmentCover ) { @@ -110,10 +146,11 @@ export class FuseScrumboardCardDialogComponent implements OnInit, OnDestroy } /** - * Remove Checklist + * Remove checklist + * * @param checklist */ - removeChecklist(checklist) + removeChecklist(checklist): void { this.card.checklists.splice(this.card.checklists.indexOf(checklist), 1); @@ -121,10 +158,11 @@ export class FuseScrumboardCardDialogComponent implements OnInit, OnDestroy } /** - * Update Checked Count + * Update checked count + * * @param list */ - updateCheckedCount(list) + updateCheckedCount(list): void { const checkItems = list.checkItems; let checkedItems = 0; @@ -154,11 +192,12 @@ export class FuseScrumboardCardDialogComponent implements OnInit, OnDestroy } /** - * Remove Checklist Item + * Remove checklist item + * * @param checkItem * @param checklist */ - removeChecklistItem(checkItem, checklist) + removeChecklistItem(checkItem, checklist): void { checklist.checkItems.splice(checklist.checkItems.indexOf(checkItem), 1); @@ -168,11 +207,12 @@ export class FuseScrumboardCardDialogComponent implements OnInit, OnDestroy } /** - * Add Check Item + * Add check item + * * @param {NgForm} form * @param checkList */ - addCheckItem(form: NgForm, checkList) + addCheckItem(form: NgForm, checkList): void { const checkItemVal = form.value.checkItem; @@ -196,10 +236,11 @@ export class FuseScrumboardCardDialogComponent implements OnInit, OnDestroy } /** - * Add Checklist + * Add checklist + * * @param {NgForm} form */ - addChecklist(form: NgForm) + addChecklist(form: NgForm): void { this.card.checklists.push({ id : FuseUtils.generateGUID(), @@ -215,9 +256,9 @@ export class FuseScrumboardCardDialogComponent implements OnInit, OnDestroy } /** - * On Checklist Menu Open + * On checklist menu open */ - onChecklistMenuOpen() + onChecklistMenuOpen(): void { setTimeout(() => { this.newCheckListTitleField.nativeElement.focus(); @@ -225,10 +266,11 @@ export class FuseScrumboardCardDialogComponent implements OnInit, OnDestroy } /** - * Add New Comment + * Add new comment + * * @param {NgForm} form */ - addNewComment(form: NgForm) + addNewComment(form: NgForm): void { const newCommentText = form.value.newComment; @@ -246,11 +288,11 @@ export class FuseScrumboardCardDialogComponent implements OnInit, OnDestroy } /** - * Remove Card + * Remove card */ - removeCard() + removeCard(): void { - this.confirmDialogRef = this.dialog.open(FuseConfirmDialogComponent, { + this.confirmDialogRef = this._matDialog.open(FuseConfirmDialogComponent, { disableClose: false }); @@ -259,22 +301,17 @@ export class FuseScrumboardCardDialogComponent implements OnInit, OnDestroy this.confirmDialogRef.afterClosed().subscribe(result => { if ( result ) { - this.dialogRef.close(); - this.scrumboardService.removeCard(this.card.id, this.list.id); + this._matDialogRef.close(); + this._scrumboardService.removeCard(this.card.id, this.list.id); } }); } /** - * Update Card + * Update card */ - updateCard() + updateCard(): void { - this.scrumboardService.updateCard(this.card); - } - - ngOnDestroy() - { - this.onBoardChanged.unsubscribe(); + this._scrumboardService.updateCard(this.card); } } diff --git a/src/app/main/content/apps/scrumboard/board/dialogs/card/label-selector/label-selector.component.html b/src/app/main/apps/scrumboard/board/dialogs/card/label-selector/label-selector.component.html similarity index 100% rename from src/app/main/content/apps/scrumboard/board/dialogs/card/label-selector/label-selector.component.html rename to src/app/main/apps/scrumboard/board/dialogs/card/label-selector/label-selector.component.html diff --git a/src/app/main/content/apps/scrumboard/board/dialogs/card/label-selector/label-selector.component.scss b/src/app/main/apps/scrumboard/board/dialogs/card/label-selector/label-selector.component.scss similarity index 100% rename from src/app/main/content/apps/scrumboard/board/dialogs/card/label-selector/label-selector.component.scss rename to src/app/main/apps/scrumboard/board/dialogs/card/label-selector/label-selector.component.scss 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/content/apps/scrumboard/board/edit-board-name/edit-board-name.component.html b/src/app/main/apps/scrumboard/board/edit-board-name/edit-board-name.component.html similarity index 100% rename from src/app/main/content/apps/scrumboard/board/edit-board-name/edit-board-name.component.html rename to src/app/main/apps/scrumboard/board/edit-board-name/edit-board-name.component.html diff --git a/src/app/main/content/apps/scrumboard/board/edit-board-name/edit-board-name.component.scss b/src/app/main/apps/scrumboard/board/edit-board-name/edit-board-name.component.scss similarity index 100% rename from src/app/main/content/apps/scrumboard/board/edit-board-name/edit-board-name.component.scss rename to src/app/main/apps/scrumboard/board/edit-board-name/edit-board-name.component.scss diff --git a/src/app/main/content/apps/scrumboard/board/edit-board-name/edit-board-name.component.ts b/src/app/main/apps/scrumboard/board/edit-board-name/edit-board-name.component.ts similarity index 54% rename from src/app/main/content/apps/scrumboard/board/edit-board-name/edit-board-name.component.ts rename to src/app/main/apps/scrumboard/board/edit-board-name/edit-board-name.component.ts index 68f67b92..66ab3c71 100644 --- a/src/app/main/content/apps/scrumboard/board/edit-board-name/edit-board-name.component.ts +++ b/src/app/main/apps/scrumboard/board/edit-board-name/edit-board-name.component.ts @@ -2,25 +2,41 @@ import { Component, EventEmitter, Input, Output, ViewChild } from '@angular/core import { FormBuilder, FormGroup } from '@angular/forms'; @Component({ - selector : 'fuse-scrumboard-edit-board-name', + selector : 'scrumboard-edit-board-name', templateUrl: './edit-board-name.component.html', styleUrls : ['./edit-board-name.component.scss'] }) -export class FuseScrumboardEditBoardNameComponent +export class ScrumboardEditBoardNameComponent { - formActive = false; + formActive: boolean; form: FormGroup; - @Input() board; - @Output() onNameChanged = new EventEmitter(); - @ViewChild('nameInput') nameInputField; + + @Input() + board; + + @Output() + onNameChanged: EventEmitter; + + @ViewChild('nameInput') + nameInputField; constructor( private formBuilder: FormBuilder ) { + // Set the defaults + this.formActive = false; + this.onNameChanged = new EventEmitter(); } - openForm() + // ----------------------------------------------------------------------------------------------------- + // @ Public methods + // ----------------------------------------------------------------------------------------------------- + + /** + * Open form + */ + openForm(): void { this.form = this.formBuilder.group({ name: [this.board.name] @@ -29,19 +45,28 @@ export class FuseScrumboardEditBoardNameComponent this.focusNameField(); } - closeForm() + /** + * Close form + */ + closeForm(): void { this.formActive = false; } - focusNameField() + /** + * Focus to the name field + */ + focusNameField(): void { setTimeout(() => { this.nameInputField.nativeElement.focus(); }); } - onFormSubmit() + /** + * On form submit + */ + onFormSubmit(): void { if ( this.form.valid ) { @@ -52,5 +77,4 @@ export class FuseScrumboardEditBoardNameComponent this.formActive = false; } } - } diff --git a/src/app/main/content/apps/scrumboard/board/list/add-card/add-card.component.html b/src/app/main/apps/scrumboard/board/list/add-card/add-card.component.html similarity index 100% rename from src/app/main/content/apps/scrumboard/board/list/add-card/add-card.component.html rename to src/app/main/apps/scrumboard/board/list/add-card/add-card.component.html diff --git a/src/app/main/content/apps/scrumboard/board/list/add-card/add-card.component.scss b/src/app/main/apps/scrumboard/board/list/add-card/add-card.component.scss similarity index 100% rename from src/app/main/content/apps/scrumboard/board/list/add-card/add-card.component.scss rename to src/app/main/apps/scrumboard/board/list/add-card/add-card.component.scss 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/content/apps/scrumboard/board/list/card/card.component.html b/src/app/main/apps/scrumboard/board/list/card/card.component.html similarity index 100% rename from src/app/main/content/apps/scrumboard/board/list/card/card.component.html rename to src/app/main/apps/scrumboard/board/list/card/card.component.html diff --git a/src/app/main/content/apps/scrumboard/board/list/card/card.component.scss b/src/app/main/apps/scrumboard/board/list/card/card.component.scss similarity index 100% rename from src/app/main/content/apps/scrumboard/board/list/card/card.component.scss rename to src/app/main/apps/scrumboard/board/list/card/card.component.scss 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/content/apps/scrumboard/board/list/edit-list-name/edit-list-name.component.html b/src/app/main/apps/scrumboard/board/list/edit-list-name/edit-list-name.component.html similarity index 100% rename from src/app/main/content/apps/scrumboard/board/list/edit-list-name/edit-list-name.component.html rename to src/app/main/apps/scrumboard/board/list/edit-list-name/edit-list-name.component.html diff --git a/src/app/main/content/apps/scrumboard/board/list/edit-list-name/edit-list-name.component.scss b/src/app/main/apps/scrumboard/board/list/edit-list-name/edit-list-name.component.scss similarity index 100% rename from src/app/main/content/apps/scrumboard/board/list/edit-list-name/edit-list-name.component.scss rename to src/app/main/apps/scrumboard/board/list/edit-list-name/edit-list-name.component.scss 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/content/apps/scrumboard/board/list/list.component.html b/src/app/main/apps/scrumboard/board/list/list.component.html similarity index 62% rename from src/app/main/content/apps/scrumboard/board/list/list.component.html rename to src/app/main/apps/scrumboard/board/list/list.component.html index 2899c33c..33324778 100644 --- a/src/app/main/content/apps/scrumboard/board/list/list.component.html +++ b/src/app/main/apps/scrumboard/board/list/list.component.html @@ -3,11 +3,11 @@
- - +
diff --git a/src/app/main/content/apps/scrumboard/board/list/list.component.scss b/src/app/main/apps/scrumboard/board/list/list.component.scss similarity index 100% rename from src/app/main/content/apps/scrumboard/board/list/list.component.scss rename to src/app/main/apps/scrumboard/board/list/list.component.scss 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/content/apps/scrumboard/board/sidenavs/settings/board-color-selector/board-color-selector.component.html b/src/app/main/apps/scrumboard/board/sidenavs/settings/board-color-selector/board-color-selector.component.html similarity index 100% rename from src/app/main/content/apps/scrumboard/board/sidenavs/settings/board-color-selector/board-color-selector.component.html rename to src/app/main/apps/scrumboard/board/sidenavs/settings/board-color-selector/board-color-selector.component.html diff --git a/src/app/main/content/apps/scrumboard/board/sidenavs/settings/board-color-selector/board-color-selector.component.scss b/src/app/main/apps/scrumboard/board/sidenavs/settings/board-color-selector/board-color-selector.component.scss similarity index 100% rename from src/app/main/content/apps/scrumboard/board/sidenavs/settings/board-color-selector/board-color-selector.component.scss rename to src/app/main/apps/scrumboard/board/sidenavs/settings/board-color-selector/board-color-selector.component.scss 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/content/apps/scrumboard/board/sidenavs/settings/settings.component.html b/src/app/main/apps/scrumboard/board/sidenavs/settings/settings.component.html similarity index 96% rename from src/app/main/content/apps/scrumboard/board/sidenavs/settings/settings.component.html rename to src/app/main/apps/scrumboard/board/sidenavs/settings/settings.component.html index e407b7ec..effbb249 100644 --- a/src/app/main/content/apps/scrumboard/board/sidenavs/settings/settings.component.html +++ b/src/app/main/apps/scrumboard/board/sidenavs/settings/settings.component.html @@ -28,7 +28,7 @@