aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.eslintrc3
-rw-r--r--.gitignore1
-rw-r--r--package-lock.json322
-rw-r--r--packages/forms/src/input/index.tsx10
-rw-r--r--src/actions/index.js6
-rw-r--r--src/actions/lib/actions.js29
-rw-r--r--src/api/utils/auth.js28
-rw-r--r--src/app.js4
-rw-r--r--src/components/layout/Sidebar.js2
-rw-r--r--src/components/services/tabs/Tabbar.js4
-rw-r--r--src/components/settings/navigation/SettingsNavigation.js12
-rw-r--r--src/config.js2
-rw-r--r--src/environment.js1
-rw-r--r--src/features/delayApp/Component.js2
-rw-r--r--src/features/workspaces/actions.js22
-rw-r--r--src/features/workspaces/api.js39
-rw-r--r--src/features/workspaces/components/CreateWorkspaceForm.js93
-rw-r--r--src/features/workspaces/components/EditWorkspaceForm.js192
-rw-r--r--src/features/workspaces/components/ServiceListItem.js48
-rw-r--r--src/features/workspaces/components/WorkspaceItem.js42
-rw-r--r--src/features/workspaces/components/WorkspacesDashboard.js85
-rw-r--r--src/features/workspaces/containers/EditWorkspaceScreen.js59
-rw-r--r--src/features/workspaces/containers/WorkspacesScreen.js33
-rw-r--r--src/features/workspaces/index.js68
-rw-r--r--src/features/workspaces/models/Workspace.js25
-rw-r--r--src/features/workspaces/state.js15
-rw-r--r--src/features/workspaces/store.js114
-rw-r--r--src/features/workspaces/styles/workspaces-table.scss53
-rw-r--r--src/i18n/locales/de.json12
-rw-r--r--src/i18n/locales/en-US.json14
-rw-r--r--src/lib/Menu.js71
-rw-r--r--src/stores/FeaturesStore.js4
-rw-r--r--src/stores/ServicesStore.js12
-rw-r--r--src/styles/main.scss3
34 files changed, 1247 insertions, 183 deletions
diff --git a/.eslintrc b/.eslintrc
index e15148e96..f1051723d 100644
--- a/.eslintrc
+++ b/.eslintrc
@@ -2,6 +2,7 @@
2 "parser": "babel-eslint", 2 "parser": "babel-eslint",
3 "extends": "eslint-config-airbnb", 3 "extends": "eslint-config-airbnb",
4 "rules": { 4 "rules": {
5 "consistent-return": 0,
5 "import/extensions": 0, 6 "import/extensions": 0,
6 "import/no-extraneous-dependencies": 0, 7 "import/no-extraneous-dependencies": 0,
7 "import/no-unresolved": [2, { 8 "import/no-unresolved": [2, {
@@ -13,7 +14,7 @@
13 "react/jsx-filename-extension": [1, { 14 "react/jsx-filename-extension": [1, {
14 "extensions": [".js", ".jsx"] 15 "extensions": [".js", ".jsx"]
15 }], 16 }],
16 "react/forbid-prop-types": 1, 17 "react/forbid-prop-types": 0,
17 "react/destructuring-assignment": 1, 18 "react/destructuring-assignment": 1,
18 "prefer-destructuring": 1, 19 "prefer-destructuring": 1,
19 "no-underscore-dangle": 0, 20 "no-underscore-dangle": 0,
diff --git a/.gitignore b/.gitignore
index 192a261f0..245057c46 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,3 +1,4 @@
1.idea
1node_modules 2node_modules
2flow-typed 3flow-typed
3out 4out
diff --git a/package-lock.json b/package-lock.json
index 312f4f6be..d7c209cc6 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1442,7 +1442,7 @@
1442 "@lerna/get-packed": { 1442 "@lerna/get-packed": {
1443 "version": "3.7.0", 1443 "version": "3.7.0",
1444 "resolved": "https://registry.npmjs.org/@lerna/get-packed/-/get-packed-3.7.0.tgz", 1444 "resolved": "https://registry.npmjs.org/@lerna/get-packed/-/get-packed-3.7.0.tgz",
1445 "integrity": "sha512-yuFtjsUZIHjeIvIYQ/QuytC+FQcHwo3peB+yGBST2uWCLUCR5rx6knoQcPzbxdFDCuUb5IFccFGd3B1fHFg3RQ==", 1445 "integrity": "sha1-VJx3OPe+XjsUM+gu2c2pEjvNHtU=",
1446 "dev": true, 1446 "dev": true,
1447 "requires": { 1447 "requires": {
1448 "fs-extra": "^7.0.0", 1448 "fs-extra": "^7.0.0",
@@ -1567,7 +1567,7 @@
1567 "@lerna/npm-conf": { 1567 "@lerna/npm-conf": {
1568 "version": "3.7.0", 1568 "version": "3.7.0",
1569 "resolved": "https://registry.npmjs.org/@lerna/npm-conf/-/npm-conf-3.7.0.tgz", 1569 "resolved": "https://registry.npmjs.org/@lerna/npm-conf/-/npm-conf-3.7.0.tgz",
1570 "integrity": "sha512-+WSMDfPKcKzMfqq283ydz9RRpOU6p9wfx0wy4hVSUY/6YUpsyuk8SShjcRtY8zTM5AOrxvFBuuV90H4YpZ5+Ng==", 1570 "integrity": "sha1-8QHU/fB8788RYbz688DxBbQgpFA=",
1571 "dev": true, 1571 "dev": true,
1572 "requires": { 1572 "requires": {
1573 "config-chain": "^1.1.11", 1573 "config-chain": "^1.1.11",
@@ -1823,7 +1823,7 @@
1823 "@lerna/run-parallel-batches": { 1823 "@lerna/run-parallel-batches": {
1824 "version": "3.0.0", 1824 "version": "3.0.0",
1825 "resolved": "https://registry.npmjs.org/@lerna/run-parallel-batches/-/run-parallel-batches-3.0.0.tgz", 1825 "resolved": "https://registry.npmjs.org/@lerna/run-parallel-batches/-/run-parallel-batches-3.0.0.tgz",
1826 "integrity": "sha512-Mj1ravlXF7AkkewKd9YFq9BtVrsStNrvVLedD/b2wIVbNqcxp8lS68vehXVOzoL/VWNEDotvqCQtyDBilCodGw==", 1826 "integrity": "sha1-RocEk0CEx0mR0xJNgGB4V9TfqEA=",
1827 "dev": true, 1827 "dev": true,
1828 "requires": { 1828 "requires": {
1829 "p-map": "^1.2.0", 1829 "p-map": "^1.2.0",
@@ -1948,15 +1948,6 @@
1948 "@meetfranz/theme": "^1.0.7", 1948 "@meetfranz/theme": "^1.0.7",
1949 "react-html-attributes": "^1.4.3", 1949 "react-html-attributes": "^1.4.3",
1950 "react-loader": "^2.4.5" 1950 "react-loader": "^2.4.5"
1951 },
1952 "dependencies": {
1953 "@meetfranz/theme": {
1954 "version": "1.0.9",
1955 "bundled": true,
1956 "requires": {
1957 "color": "^3.1.0"
1958 }
1959 }
1960 } 1951 }
1961 }, 1952 },
1962 "@meetfranz/theme": { 1953 "@meetfranz/theme": {
@@ -1972,21 +1963,12 @@
1972 "@mdi/react": "^1.1.0", 1963 "@mdi/react": "^1.1.0",
1973 "@meetfranz/theme": "^1.0.7", 1964 "@meetfranz/theme": "^1.0.7",
1974 "react-loader": "^2.4.5" 1965 "react-loader": "^2.4.5"
1975 },
1976 "dependencies": {
1977 "@meetfranz/theme": {
1978 "version": "1.0.9",
1979 "bundled": true,
1980 "requires": {
1981 "color": "^3.1.0"
1982 }
1983 }
1984 } 1966 }
1985 }, 1967 },
1986 "@mrmlnc/readdir-enhanced": { 1968 "@mrmlnc/readdir-enhanced": {
1987 "version": "2.2.1", 1969 "version": "2.2.1",
1988 "resolved": "https://registry.npmjs.org/@mrmlnc/readdir-enhanced/-/readdir-enhanced-2.2.1.tgz", 1970 "resolved": "https://registry.npmjs.org/@mrmlnc/readdir-enhanced/-/readdir-enhanced-2.2.1.tgz",
1989 "integrity": "sha512-bPHp6Ji8b41szTOcaP63VlnbbO5Ny6dwAATtY6JTjh5N2OLrb5Qk/Th5cRkRQhkWCt+EJsYrNB0MiL+Gpn6e3g==", 1971 "integrity": "sha1-UkryQNGjYFJ7cwR17PoTRKpUDd4=",
1990 "dev": true, 1972 "dev": true,
1991 "requires": { 1973 "requires": {
1992 "call-me-maybe": "^1.0.1", 1974 "call-me-maybe": "^1.0.1",
@@ -1996,7 +1978,7 @@
1996 "@nodelib/fs.stat": { 1978 "@nodelib/fs.stat": {
1997 "version": "1.1.3", 1979 "version": "1.1.3",
1998 "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-1.1.3.tgz", 1980 "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-1.1.3.tgz",
1999 "integrity": "sha512-shAmDyaQC4H92APFoIaVDHCx5bStIocgvbwQyxPRrbUY20V1EYTbSDchWbuwlMG3V17cprZhA6+78JfB+3DTPw==", 1981 "integrity": "sha1-K1o6s/kYzKSKjHVMCBaOPwPrphs=",
2000 "dev": true 1982 "dev": true
2001 }, 1983 },
2002 "@octokit/endpoint": { 1984 "@octokit/endpoint": {
@@ -2372,7 +2354,7 @@
2372 "dependencies": { 2354 "dependencies": {
2373 "mime-types": { 2355 "mime-types": {
2374 "version": "1.0.2", 2356 "version": "1.0.2",
2375 "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-1.0.2.tgz", 2357 "resolved": "http://registry.npmjs.org/mime-types/-/mime-types-1.0.2.tgz",
2376 "integrity": "sha1-mVrhOSq4r/y/yyZB3QVOlDwNXc4=", 2358 "integrity": "sha1-mVrhOSq4r/y/yyZB3QVOlDwNXc4=",
2377 "dev": true 2359 "dev": true
2378 } 2360 }
@@ -2430,7 +2412,7 @@
2430 "agent-base": { 2412 "agent-base": {
2431 "version": "4.2.1", 2413 "version": "4.2.1",
2432 "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-4.2.1.tgz", 2414 "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-4.2.1.tgz",
2433 "integrity": "sha512-JVwXMr9nHYTUXsBFKUqhJwvlcYU/blreOEUkhNR2eXZIvwd+c+o5V4MgDPKWnMS/56awN3TRzIP+KoPn+roQtg==", 2415 "integrity": "sha1-2J5ZmfeXh1Z0wH2H8mD8Qeg+jKk=",
2434 "dev": true, 2416 "dev": true,
2435 "requires": { 2417 "requires": {
2436 "es6-promisify": "^5.0.0" 2418 "es6-promisify": "^5.0.0"
@@ -2439,7 +2421,7 @@
2439 "agentkeepalive": { 2421 "agentkeepalive": {
2440 "version": "3.5.2", 2422 "version": "3.5.2",
2441 "resolved": "https://registry.npmjs.org/agentkeepalive/-/agentkeepalive-3.5.2.tgz", 2423 "resolved": "https://registry.npmjs.org/agentkeepalive/-/agentkeepalive-3.5.2.tgz",
2442 "integrity": "sha512-e0L/HNe6qkQ7H19kTlRRqUibEAwDK5AFk6y3PtMsuut2VAH6+Q4xZml1tNDJD7kSAyqmbG/K08K5WEJYtUrSlQ==", 2424 "integrity": "sha1-oROSTdP6JKC8O3gQjEUMKr7gD2c=",
2443 "dev": true, 2425 "dev": true,
2444 "requires": { 2426 "requires": {
2445 "humanize-ms": "^1.2.1" 2427 "humanize-ms": "^1.2.1"
@@ -2486,7 +2468,7 @@
2486 }, 2468 },
2487 "ansi-colors": { 2469 "ansi-colors": {
2488 "version": "1.1.0", 2470 "version": "1.1.0",
2489 "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-1.1.0.tgz", 2471 "resolved": "http://registry.npmjs.org/ansi-colors/-/ansi-colors-1.1.0.tgz",
2490 "integrity": "sha512-SFKX67auSNoVR38N3L+nvsPjOE0bybKTYbkf5tRvushrAPQ9V75huw0ZxBkKVeRU9kqH3d6HA4xTckbwZ4ixmA==", 2472 "integrity": "sha512-SFKX67auSNoVR38N3L+nvsPjOE0bybKTYbkf5tRvushrAPQ9V75huw0ZxBkKVeRU9kqH3d6HA4xTckbwZ4ixmA==",
2491 "dev": true, 2473 "dev": true,
2492 "requires": { 2474 "requires": {
@@ -2913,7 +2895,7 @@
2913 }, 2895 },
2914 "util": { 2896 "util": {
2915 "version": "0.10.3", 2897 "version": "0.10.3",
2916 "resolved": "https://registry.npmjs.org/util/-/util-0.10.3.tgz", 2898 "resolved": "http://registry.npmjs.org/util/-/util-0.10.3.tgz",
2917 "integrity": "sha1-evsa/lCAUkZInj23/g7TeTNqwPk=", 2899 "integrity": "sha1-evsa/lCAUkZInj23/g7TeTNqwPk=",
2918 "dev": true, 2900 "dev": true,
2919 "requires": { 2901 "requires": {
@@ -2948,7 +2930,7 @@
2948 }, 2930 },
2949 "async": { 2931 "async": {
2950 "version": "0.1.22", 2932 "version": "0.1.22",
2951 "resolved": "https://registry.npmjs.org/async/-/async-0.1.22.tgz", 2933 "resolved": "http://registry.npmjs.org/async/-/async-0.1.22.tgz",
2952 "integrity": "sha1-D8GqoIig4+8Ovi2IMbqw3PiEUGE=" 2934 "integrity": "sha1-D8GqoIig4+8Ovi2IMbqw3PiEUGE="
2953 }, 2935 },
2954 "async-done": { 2936 "async-done": {
@@ -3760,7 +3742,7 @@
3760 "byte-size": { 3742 "byte-size": {
3761 "version": "4.0.4", 3743 "version": "4.0.4",
3762 "resolved": "https://registry.npmjs.org/byte-size/-/byte-size-4.0.4.tgz", 3744 "resolved": "https://registry.npmjs.org/byte-size/-/byte-size-4.0.4.tgz",
3763 "integrity": "sha512-82RPeneC6nqCdSwCX2hZUz3JPOvN5at/nTEw/CMf05Smu3Hrpo9Psb7LjN+k+XndNArG1EY8L4+BM3aTM4BCvw==", 3745 "integrity": "sha1-KdOBcJ9BquDYnGMfHIGuyIzUCyM=",
3764 "dev": true 3746 "dev": true
3765 }, 3747 },
3766 "bytes": { 3748 "bytes": {
@@ -3772,7 +3754,7 @@
3772 "cacache": { 3754 "cacache": {
3773 "version": "11.3.2", 3755 "version": "11.3.2",
3774 "resolved": "https://registry.npmjs.org/cacache/-/cacache-11.3.2.tgz", 3756 "resolved": "https://registry.npmjs.org/cacache/-/cacache-11.3.2.tgz",
3775 "integrity": "sha512-E0zP4EPGDOaT2chM08Als91eYnf8Z+eH1awwwVsngUmgppfM5jjJ8l3z5vO5p5w/I3LsiXawb1sW0VY65pQABg==", 3757 "integrity": "sha1-LYHjCOPSWMo4Eltna5iyrJzmm/o=",
3776 "dev": true, 3758 "dev": true,
3777 "requires": { 3759 "requires": {
3778 "bluebird": "^3.5.3", 3760 "bluebird": "^3.5.3",
@@ -3794,7 +3776,7 @@
3794 "lru-cache": { 3776 "lru-cache": {
3795 "version": "5.1.1", 3777 "version": "5.1.1",
3796 "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", 3778 "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz",
3797 "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", 3779 "integrity": "sha1-HaJ+ZxAnGUdpXa9oSOhH8B2EuSA=",
3798 "dev": true, 3780 "dev": true,
3799 "requires": { 3781 "requires": {
3800 "yallist": "^3.0.2" 3782 "yallist": "^3.0.2"
@@ -4491,7 +4473,7 @@
4491 "config-chain": { 4473 "config-chain": {
4492 "version": "1.1.12", 4474 "version": "1.1.12",
4493 "resolved": "https://registry.npmjs.org/config-chain/-/config-chain-1.1.12.tgz", 4475 "resolved": "https://registry.npmjs.org/config-chain/-/config-chain-1.1.12.tgz",
4494 "integrity": "sha512-a1eOIcu8+7lUInge4Rpf/n4Krkf3Dd9lqhljRzII1/Zno/kRtUWnznPO3jOKBmTEktkt3fkxisUcivoj0ebzoA==", 4476 "integrity": "sha1-D96NCRIA616AjK8l/mGMAvSOTvo=",
4495 "dev": true, 4477 "dev": true,
4496 "requires": { 4478 "requires": {
4497 "ini": "^1.3.4", 4479 "ini": "^1.3.4",
@@ -4537,7 +4519,7 @@
4537 "dependencies": { 4519 "dependencies": {
4538 "debug": { 4520 "debug": {
4539 "version": "1.0.4", 4521 "version": "1.0.4",
4540 "resolved": "https://registry.npmjs.org/debug/-/debug-1.0.4.tgz", 4522 "resolved": "http://registry.npmjs.org/debug/-/debug-1.0.4.tgz",
4541 "integrity": "sha1-W5wla9VLbsAigxdvqKDt5tFUy/g=", 4523 "integrity": "sha1-W5wla9VLbsAigxdvqKDt5tFUy/g=",
4542 "dev": true, 4524 "dev": true,
4543 "requires": { 4525 "requires": {
@@ -4807,7 +4789,7 @@
4807 "conventional-recommended-bump": { 4789 "conventional-recommended-bump": {
4808 "version": "4.0.4", 4790 "version": "4.0.4",
4809 "resolved": "https://registry.npmjs.org/conventional-recommended-bump/-/conventional-recommended-bump-4.0.4.tgz", 4791 "resolved": "https://registry.npmjs.org/conventional-recommended-bump/-/conventional-recommended-bump-4.0.4.tgz",
4810 "integrity": "sha512-9mY5Yoblq+ZMqJpBzgS+RpSq+SUfP2miOR3H/NR9drGf08WCrY9B6HAGJZEm6+ThsVP917VHAahSOjM6k1vhPg==", 4792 "integrity": "sha1-BVQFhGQdPadYyIY8CXiPyutYaHI=",
4811 "dev": true, 4793 "dev": true,
4812 "requires": { 4794 "requires": {
4813 "concat-stream": "^1.6.0", 4795 "concat-stream": "^1.6.0",
@@ -4898,7 +4880,7 @@
4898 "copy-concurrently": { 4880 "copy-concurrently": {
4899 "version": "1.0.5", 4881 "version": "1.0.5",
4900 "resolved": "https://registry.npmjs.org/copy-concurrently/-/copy-concurrently-1.0.5.tgz", 4882 "resolved": "https://registry.npmjs.org/copy-concurrently/-/copy-concurrently-1.0.5.tgz",
4901 "integrity": "sha512-f2domd9fsVDFtaFcbaRZuYXwtdmnzqbADSwhSWYxYB/Q8zsdUUFMXVRwXGDMWmbEzAn1kdRrtI1T/KTFOL4X2A==", 4883 "integrity": "sha1-kilzmMrjSTf8r9bsgTnBgFHwteA=",
4902 "dev": true, 4884 "dev": true,
4903 "requires": { 4885 "requires": {
4904 "aproba": "^1.1.1", 4886 "aproba": "^1.1.1",
@@ -5478,7 +5460,7 @@
5478 "diff": { 5460 "diff": {
5479 "version": "3.5.0", 5461 "version": "3.5.0",
5480 "resolved": "https://registry.npmjs.org/diff/-/diff-3.5.0.tgz", 5462 "resolved": "https://registry.npmjs.org/diff/-/diff-3.5.0.tgz",
5481 "integrity": "sha512-A46qtFgd+g7pDZinpnwiRJtxbC1hpgf0uzP3iG89scHk0AUC7A1TGxf5OiiOUv/JMZR8GOt8hL900hV0bOy5xA==", 5463 "integrity": "sha1-gAwN0eCov7yVg1wgKtIg/jF+WhI=",
5482 "dev": true 5464 "dev": true
5483 }, 5465 },
5484 "diffie-hellman": { 5466 "diffie-hellman": {
@@ -5495,7 +5477,7 @@
5495 "dir-glob": { 5477 "dir-glob": {
5496 "version": "2.0.0", 5478 "version": "2.0.0",
5497 "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-2.0.0.tgz", 5479 "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-2.0.0.tgz",
5498 "integrity": "sha512-37qirFDz8cA5fimp9feo43fSuRo2gHwaIn6dXL8Ber1dGwUosDrGZeCCXq57WnIqE4aQ+u3eQZzsk1yOzhdwag==", 5480 "integrity": "sha1-CyBdK2rvmCOMooZZioIE0p0KADQ=",
5499 "dev": true, 5481 "dev": true,
5500 "requires": { 5482 "requires": {
5501 "arrify": "^1.0.1", 5483 "arrify": "^1.0.1",
@@ -5580,7 +5562,7 @@
5580 "dependencies": { 5562 "dependencies": {
5581 "domelementtype": { 5563 "domelementtype": {
5582 "version": "1.1.3", 5564 "version": "1.1.3",
5583 "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-1.1.3.tgz", 5565 "resolved": "http://registry.npmjs.org/domelementtype/-/domelementtype-1.1.3.tgz",
5584 "integrity": "sha1-vSh3PiZCiBrsUVRJJCmcXNgiGFs=" 5566 "integrity": "sha1-vSh3PiZCiBrsUVRJJCmcXNgiGFs="
5585 } 5567 }
5586 } 5568 }
@@ -5624,7 +5606,7 @@
5624 }, 5606 },
5625 "dotenv": { 5607 "dotenv": {
5626 "version": "4.0.0", 5608 "version": "4.0.0",
5627 "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-4.0.0.tgz", 5609 "resolved": "http://registry.npmjs.org/dotenv/-/dotenv-4.0.0.tgz",
5628 "integrity": "sha1-hk7xN5rO1Vzm+V3r7NzhefegzR0=", 5610 "integrity": "sha1-hk7xN5rO1Vzm+V3r7NzhefegzR0=",
5629 "dev": true 5611 "dev": true
5630 }, 5612 },
@@ -5644,7 +5626,7 @@
5644 }, 5626 },
5645 "duplexer": { 5627 "duplexer": {
5646 "version": "0.1.1", 5628 "version": "0.1.1",
5647 "resolved": "https://registry.npmjs.org/duplexer/-/duplexer-0.1.1.tgz", 5629 "resolved": "http://registry.npmjs.org/duplexer/-/duplexer-0.1.1.tgz",
5648 "integrity": "sha1-rOb/gIwc5mtX0ev5eXessCM0z8E=", 5630 "integrity": "sha1-rOb/gIwc5mtX0ev5eXessCM0z8E=",
5649 "dev": true 5631 "dev": true
5650 }, 5632 },
@@ -5955,7 +5937,7 @@
5955 }, 5937 },
5956 "readable-stream": { 5938 "readable-stream": {
5957 "version": "1.1.14", 5939 "version": "1.1.14",
5958 "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz", 5940 "resolved": "http://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz",
5959 "integrity": "sha1-fPTFTvZI44EwhMY23SB54WbAgdk=", 5941 "integrity": "sha1-fPTFTvZI44EwhMY23SB54WbAgdk=",
5960 "dev": true, 5942 "dev": true,
5961 "requires": { 5943 "requires": {
@@ -6483,7 +6465,7 @@
6483 }, 6465 },
6484 "debug": { 6466 "debug": {
6485 "version": "2.3.3", 6467 "version": "2.3.3",
6486 "resolved": "https://registry.npmjs.org/debug/-/debug-2.3.3.tgz", 6468 "resolved": "http://registry.npmjs.org/debug/-/debug-2.3.3.tgz",
6487 "integrity": "sha1-QMRT5n5uE8kB3ewxeviYbNqe/4w=", 6469 "integrity": "sha1-QMRT5n5uE8kB3ewxeviYbNqe/4w=",
6488 "dev": true, 6470 "dev": true,
6489 "requires": { 6471 "requires": {
@@ -6492,7 +6474,7 @@
6492 }, 6474 },
6493 "ms": { 6475 "ms": {
6494 "version": "0.7.2", 6476 "version": "0.7.2",
6495 "resolved": "https://registry.npmjs.org/ms/-/ms-0.7.2.tgz", 6477 "resolved": "http://registry.npmjs.org/ms/-/ms-0.7.2.tgz",
6496 "integrity": "sha1-riXPJRKziFodldfwN4aNhDESR2U=", 6478 "integrity": "sha1-riXPJRKziFodldfwN4aNhDESR2U=",
6497 "dev": true 6479 "dev": true
6498 }, 6480 },
@@ -6526,7 +6508,7 @@
6526 "dependencies": { 6508 "dependencies": {
6527 "debug": { 6509 "debug": {
6528 "version": "2.3.3", 6510 "version": "2.3.3",
6529 "resolved": "https://registry.npmjs.org/debug/-/debug-2.3.3.tgz", 6511 "resolved": "http://registry.npmjs.org/debug/-/debug-2.3.3.tgz",
6530 "integrity": "sha1-QMRT5n5uE8kB3ewxeviYbNqe/4w=", 6512 "integrity": "sha1-QMRT5n5uE8kB3ewxeviYbNqe/4w=",
6531 "dev": true, 6513 "dev": true,
6532 "requires": { 6514 "requires": {
@@ -6535,7 +6517,7 @@
6535 }, 6517 },
6536 "ms": { 6518 "ms": {
6537 "version": "0.7.2", 6519 "version": "0.7.2",
6538 "resolved": "https://registry.npmjs.org/ms/-/ms-0.7.2.tgz", 6520 "resolved": "http://registry.npmjs.org/ms/-/ms-0.7.2.tgz",
6539 "integrity": "sha1-riXPJRKziFodldfwN4aNhDESR2U=", 6521 "integrity": "sha1-riXPJRKziFodldfwN4aNhDESR2U=",
6540 "dev": true 6522 "dev": true
6541 } 6523 }
@@ -6659,12 +6641,12 @@
6659 "es6-promise": { 6641 "es6-promise": {
6660 "version": "4.2.5", 6642 "version": "4.2.5",
6661 "resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-4.2.5.tgz", 6643 "resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-4.2.5.tgz",
6662 "integrity": "sha512-n6wvpdE43VFtJq+lUDYDBFUwV8TZbuGXLV4D6wKafg13ldznKsyEvatubnmUe31zcvelSzOHF+XbaT+Bl9ObDg==", 6644 "integrity": "sha1-2m0NVpLvtGHggsFIF/4kJ9j10FQ=",
6663 "dev": true 6645 "dev": true
6664 }, 6646 },
6665 "es6-promisify": { 6647 "es6-promisify": {
6666 "version": "5.0.0", 6648 "version": "5.0.0",
6667 "resolved": "https://registry.npmjs.org/es6-promisify/-/es6-promisify-5.0.0.tgz", 6649 "resolved": "http://registry.npmjs.org/es6-promisify/-/es6-promisify-5.0.0.tgz",
6668 "integrity": "sha1-UQnWLz5W6pZ8S2NQWu8IKRyKUgM=", 6650 "integrity": "sha1-UQnWLz5W6pZ8S2NQWu8IKRyKUgM=",
6669 "dev": true, 6651 "dev": true,
6670 "requires": { 6652 "requires": {
@@ -6871,7 +6853,7 @@
6871 }, 6853 },
6872 "load-json-file": { 6854 "load-json-file": {
6873 "version": "2.0.0", 6855 "version": "2.0.0",
6874 "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-2.0.0.tgz", 6856 "resolved": "http://registry.npmjs.org/load-json-file/-/load-json-file-2.0.0.tgz",
6875 "integrity": "sha1-eUfkIUmvgNaWy/eXvKq8/h/inKg=", 6857 "integrity": "sha1-eUfkIUmvgNaWy/eXvKq8/h/inKg=",
6876 "dev": true, 6858 "dev": true,
6877 "requires": { 6859 "requires": {
@@ -7354,7 +7336,7 @@
7354 }, 7336 },
7355 "finalhandler": { 7337 "finalhandler": {
7356 "version": "1.1.1", 7338 "version": "1.1.1",
7357 "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.1.tgz", 7339 "resolved": "http://registry.npmjs.org/finalhandler/-/finalhandler-1.1.1.tgz",
7358 "integrity": "sha512-Y1GUDo39ez4aHAw7MysnUD5JzYX+WaIj8I57kO3aEPT1fFRL4sr7mjei97FgnwhAyyzRYmQZaTHb2+9uZ1dPtg==", 7340 "integrity": "sha512-Y1GUDo39ez4aHAw7MysnUD5JzYX+WaIj8I57kO3aEPT1fFRL4sr7mjei97FgnwhAyyzRYmQZaTHb2+9uZ1dPtg==",
7359 "dev": true, 7341 "dev": true,
7360 "requires": { 7342 "requires": {
@@ -7682,7 +7664,7 @@
7682 "figgy-pudding": { 7664 "figgy-pudding": {
7683 "version": "3.5.1", 7665 "version": "3.5.1",
7684 "resolved": "https://registry.npmjs.org/figgy-pudding/-/figgy-pudding-3.5.1.tgz", 7666 "resolved": "https://registry.npmjs.org/figgy-pudding/-/figgy-pudding-3.5.1.tgz",
7685 "integrity": "sha512-vNKxJHTEKNThjfrdJwHc7brvM6eVevuO5nTj6ez8ZQ1qbXTvGthucRF7S4vf2cr71QVnT70V34v0S1DyQsti0w==", 7667 "integrity": "sha1-hiRwESkBxyeg5JWoB0S9W6odZ5A=",
7686 "dev": true 7668 "dev": true
7687 }, 7669 },
7688 "figures": { 7670 "figures": {
@@ -7740,7 +7722,7 @@
7740 }, 7722 },
7741 "finalhandler": { 7723 "finalhandler": {
7742 "version": "0.1.0", 7724 "version": "0.1.0",
7743 "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-0.1.0.tgz", 7725 "resolved": "http://registry.npmjs.org/finalhandler/-/finalhandler-0.1.0.tgz",
7744 "integrity": "sha1-2gW7xPX0owyEzh2R88FUAHxOnao=", 7726 "integrity": "sha1-2gW7xPX0owyEzh2R88FUAHxOnao=",
7745 "dev": true, 7727 "dev": true,
7746 "requires": { 7728 "requires": {
@@ -7750,7 +7732,7 @@
7750 "dependencies": { 7732 "dependencies": {
7751 "debug": { 7733 "debug": {
7752 "version": "1.0.4", 7734 "version": "1.0.4",
7753 "resolved": "https://registry.npmjs.org/debug/-/debug-1.0.4.tgz", 7735 "resolved": "http://registry.npmjs.org/debug/-/debug-1.0.4.tgz",
7754 "integrity": "sha1-W5wla9VLbsAigxdvqKDt5tFUy/g=", 7736 "integrity": "sha1-W5wla9VLbsAigxdvqKDt5tFUy/g=",
7755 "dev": true, 7737 "dev": true,
7756 "requires": { 7738 "requires": {
@@ -7759,7 +7741,7 @@
7759 }, 7741 },
7760 "ms": { 7742 "ms": {
7761 "version": "0.6.2", 7743 "version": "0.6.2",
7762 "resolved": "https://registry.npmjs.org/ms/-/ms-0.6.2.tgz", 7744 "resolved": "http://registry.npmjs.org/ms/-/ms-0.6.2.tgz",
7763 "integrity": "sha1-2JwhJMb9wTU9Zai3e/GqxLGTcIw=", 7745 "integrity": "sha1-2JwhJMb9wTU9Zai3e/GqxLGTcIw=",
7764 "dev": true 7746 "dev": true
7765 } 7747 }
@@ -8104,30 +8086,36 @@
8104 "dependencies": { 8086 "dependencies": {
8105 "abbrev": { 8087 "abbrev": {
8106 "version": "1.1.1", 8088 "version": "1.1.1",
8107 "bundled": true 8089 "resolved": false,
8090 "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q=="
8108 }, 8091 },
8109 "ansi-regex": { 8092 "ansi-regex": {
8110 "version": "2.1.1", 8093 "version": "2.1.1",
8111 "bundled": true 8094 "resolved": false,
8095 "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8="
8112 }, 8096 },
8113 "aproba": { 8097 "aproba": {
8114 "version": "1.2.0", 8098 "version": "1.2.0",
8115 "bundled": true 8099 "resolved": false,
8100 "integrity": "sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw=="
8116 }, 8101 },
8117 "are-we-there-yet": { 8102 "are-we-there-yet": {
8118 "version": "1.1.5", 8103 "version": "1.1.5",
8119 "bundled": true, 8104 "resolved": false,
8105 "integrity": "sha512-5hYdAkZlcG8tOLujVDTgCT+uPX0VnpAH28gWsLfzpXYm7wP6mp5Q/gYyR7YQ0cKVJcXJnl3j2kpBan13PtQf6w==",
8120 "requires": { 8106 "requires": {
8121 "delegates": "^1.0.0" 8107 "delegates": "^1.0.0"
8122 } 8108 }
8123 }, 8109 },
8124 "balanced-match": { 8110 "balanced-match": {
8125 "version": "1.0.0", 8111 "version": "1.0.0",
8126 "bundled": true 8112 "resolved": false,
8113 "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c="
8127 }, 8114 },
8128 "brace-expansion": { 8115 "brace-expansion": {
8129 "version": "1.1.11", 8116 "version": "1.1.11",
8130 "bundled": true, 8117 "resolved": false,
8118 "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
8131 "requires": { 8119 "requires": {
8132 "balanced-match": "^1.0.0", 8120 "balanced-match": "^1.0.0",
8133 "concat-map": "0.0.1" 8121 "concat-map": "0.0.1"
@@ -8135,54 +8123,66 @@
8135 }, 8123 },
8136 "chownr": { 8124 "chownr": {
8137 "version": "1.1.1", 8125 "version": "1.1.1",
8138 "bundled": true 8126 "resolved": false,
8127 "integrity": "sha512-j38EvO5+LHX84jlo6h4UzmOwi0UgW61WRyPtJz4qaadK5eY3BTS5TY/S1Stc3Uk2lIM6TPevAlULiEJwie860g=="
8139 }, 8128 },
8140 "code-point-at": { 8129 "code-point-at": {
8141 "version": "1.1.0", 8130 "version": "1.1.0",
8142 "bundled": true 8131 "resolved": false,
8132 "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c="
8143 }, 8133 },
8144 "concat-map": { 8134 "concat-map": {
8145 "version": "0.0.1", 8135 "version": "0.0.1",
8146 "bundled": true 8136 "resolved": false,
8137 "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s="
8147 }, 8138 },
8148 "console-control-strings": { 8139 "console-control-strings": {
8149 "version": "1.1.0", 8140 "version": "1.1.0",
8150 "bundled": true 8141 "resolved": false,
8142 "integrity": "sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4="
8151 }, 8143 },
8152 "core-util-is": { 8144 "core-util-is": {
8153 "version": "1.0.2", 8145 "version": "1.0.2",
8154 "bundled": true 8146 "resolved": false,
8147 "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac="
8155 }, 8148 },
8156 "debug": { 8149 "debug": {
8157 "version": "2.6.9", 8150 "version": "2.6.9",
8158 "bundled": true 8151 "resolved": false,
8152 "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA=="
8159 }, 8153 },
8160 "deep-extend": { 8154 "deep-extend": {
8161 "version": "0.6.0", 8155 "version": "0.6.0",
8162 "bundled": true 8156 "resolved": false,
8157 "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA=="
8163 }, 8158 },
8164 "delegates": { 8159 "delegates": {
8165 "version": "1.0.0", 8160 "version": "1.0.0",
8166 "bundled": true 8161 "resolved": false,
8162 "integrity": "sha1-hMbhWbgZBP3KWaDvRM2HDTElD5o="
8167 }, 8163 },
8168 "detect-libc": { 8164 "detect-libc": {
8169 "version": "1.0.3", 8165 "version": "1.0.3",
8170 "bundled": true 8166 "resolved": false,
8167 "integrity": "sha1-+hN8S9aY7fVc1c0CrFWfkaTEups="
8171 }, 8168 },
8172 "fs-minipass": { 8169 "fs-minipass": {
8173 "version": "1.2.5", 8170 "version": "1.2.5",
8174 "bundled": true, 8171 "resolved": false,
8172 "integrity": "sha512-JhBl0skXjUPCFH7x6x61gQxrKyXsxB5gcgePLZCwfyCGGsTISMoIeObbrvVeP6Xmyaudw4TT43qV2Gz+iyd2oQ==",
8175 "requires": { 8173 "requires": {
8176 "minipass": "^2.2.1" 8174 "minipass": "^2.2.1"
8177 } 8175 }
8178 }, 8176 },
8179 "fs.realpath": { 8177 "fs.realpath": {
8180 "version": "1.0.0", 8178 "version": "1.0.0",
8181 "bundled": true 8179 "resolved": false,
8180 "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8="
8182 }, 8181 },
8183 "gauge": { 8182 "gauge": {
8184 "version": "2.7.4", 8183 "version": "2.7.4",
8185 "bundled": true, 8184 "resolved": false,
8185 "integrity": "sha1-LANAXHU4w51+s3sxcCLjJfsBi/c=",
8186 "requires": { 8186 "requires": {
8187 "aproba": "^1.0.3", 8187 "aproba": "^1.0.3",
8188 "console-control-strings": "^1.0.0", 8188 "console-control-strings": "^1.0.0",
@@ -8194,7 +8194,8 @@
8194 }, 8194 },
8195 "glob": { 8195 "glob": {
8196 "version": "7.1.3", 8196 "version": "7.1.3",
8197 "bundled": true, 8197 "resolved": false,
8198 "integrity": "sha512-vcfuiIxogLV4DlGBHIUOwI0IbrJ8HWPc4MU7HzviGeNho/UJDfi6B5p3sHeWIQ0KGIU0Jpxi5ZHxemQfLkkAwQ==",
8198 "requires": { 8199 "requires": {
8199 "fs.realpath": "^1.0.0", 8200 "fs.realpath": "^1.0.0",
8200 "inflight": "^1.0.4", 8201 "inflight": "^1.0.4",
@@ -8206,25 +8207,29 @@
8206 }, 8207 },
8207 "has-unicode": { 8208 "has-unicode": {
8208 "version": "2.0.1", 8209 "version": "2.0.1",
8209 "bundled": true 8210 "resolved": false,
8211 "integrity": "sha1-4Ob+aijPUROIVeCG0Wkedx3iqLk="
8210 }, 8212 },
8211 "iconv-lite": { 8213 "iconv-lite": {
8212 "version": "0.4.24", 8214 "version": "0.4.24",
8213 "bundled": true, 8215 "resolved": false,
8216 "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==",
8214 "requires": { 8217 "requires": {
8215 "safer-buffer": ">= 2.1.2 < 3" 8218 "safer-buffer": ">= 2.1.2 < 3"
8216 } 8219 }
8217 }, 8220 },
8218 "ignore-walk": { 8221 "ignore-walk": {
8219 "version": "3.0.1", 8222 "version": "3.0.1",
8220 "bundled": true, 8223 "resolved": false,
8224 "integrity": "sha512-DTVlMx3IYPe0/JJcYP7Gxg7ttZZu3IInhuEhbchuqneY9wWe5Ojy2mXLBaQFUQmo0AW2r3qG7m1mg86js+gnlQ==",
8221 "requires": { 8225 "requires": {
8222 "minimatch": "^3.0.4" 8226 "minimatch": "^3.0.4"
8223 } 8227 }
8224 }, 8228 },
8225 "inflight": { 8229 "inflight": {
8226 "version": "1.0.6", 8230 "version": "1.0.6",
8227 "bundled": true, 8231 "resolved": false,
8232 "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=",
8228 "requires": { 8233 "requires": {
8229 "once": "^1.3.0", 8234 "once": "^1.3.0",
8230 "wrappy": "1" 8235 "wrappy": "1"
@@ -8232,15 +8237,18 @@
8232 }, 8237 },
8233 "inherits": { 8238 "inherits": {
8234 "version": "2.0.3", 8239 "version": "2.0.3",
8235 "bundled": true 8240 "resolved": false,
8241 "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4="
8236 }, 8242 },
8237 "ini": { 8243 "ini": {
8238 "version": "1.3.5", 8244 "version": "1.3.5",
8239 "bundled": true 8245 "resolved": false,
8246 "integrity": "sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw=="
8240 }, 8247 },
8241 "is-fullwidth-code-point": { 8248 "is-fullwidth-code-point": {
8242 "version": "1.0.0", 8249 "version": "1.0.0",
8243 "bundled": true, 8250 "resolved": false,
8251 "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=",
8244 "requires": { 8252 "requires": {
8245 "number-is-nan": "^1.0.0" 8253 "number-is-nan": "^1.0.0"
8246 } 8254 }
@@ -8336,7 +8344,7 @@
8336 "genfun": { 8344 "genfun": {
8337 "version": "5.0.0", 8345 "version": "5.0.0",
8338 "resolved": "https://registry.npmjs.org/genfun/-/genfun-5.0.0.tgz", 8346 "resolved": "https://registry.npmjs.org/genfun/-/genfun-5.0.0.tgz",
8339 "integrity": "sha512-KGDOARWVga7+rnB3z9Sd2Letx515owfk0hSxHGuqjANb1M+x2bGZGqHLiozPsYMdM2OubeMni/Hpwmjq6qIUhA==", 8347 "integrity": "sha1-ndlxCgaQClxKW/V6yl2k5S/nZTc=",
8340 "dev": true 8348 "dev": true
8341 }, 8349 },
8342 "get-caller-file": { 8350 "get-caller-file": {
@@ -8875,7 +8883,7 @@
8875 }, 8883 },
8876 "got": { 8884 "got": {
8877 "version": "6.7.1", 8885 "version": "6.7.1",
8878 "resolved": "https://registry.npmjs.org/got/-/got-6.7.1.tgz", 8886 "resolved": "http://registry.npmjs.org/got/-/got-6.7.1.tgz",
8879 "integrity": "sha1-JAzQV4WpoY5WHcG0S0HHY+8ejbA=", 8887 "integrity": "sha1-JAzQV4WpoY5WHcG0S0HHY+8ejbA=",
8880 "dev": true, 8888 "dev": true,
8881 "requires": { 8889 "requires": {
@@ -9457,7 +9465,7 @@
9457 }, 9465 },
9458 "yargs": { 9466 "yargs": {
9459 "version": "3.32.0", 9467 "version": "3.32.0",
9460 "resolved": "https://registry.npmjs.org/yargs/-/yargs-3.32.0.tgz", 9468 "resolved": "http://registry.npmjs.org/yargs/-/yargs-3.32.0.tgz",
9461 "integrity": "sha1-AwiOnr+edWtpdRYR0qXvWRSCyZU=", 9469 "integrity": "sha1-AwiOnr+edWtpdRYR0qXvWRSCyZU=",
9462 "dev": true, 9470 "dev": true,
9463 "requires": { 9471 "requires": {
@@ -9632,7 +9640,7 @@
9632 }, 9640 },
9633 "lodash": { 9641 "lodash": {
9634 "version": "1.0.2", 9642 "version": "1.0.2",
9635 "resolved": "https://registry.npmjs.org/lodash/-/lodash-1.0.2.tgz", 9643 "resolved": "http://registry.npmjs.org/lodash/-/lodash-1.0.2.tgz",
9636 "integrity": "sha1-j1dWDIO1n8JwvT1WG2kAQ0MOJVE=", 9644 "integrity": "sha1-j1dWDIO1n8JwvT1WG2kAQ0MOJVE=",
9637 "dev": true 9645 "dev": true
9638 }, 9646 },
@@ -9692,7 +9700,7 @@
9692 }, 9700 },
9693 "readable-stream": { 9701 "readable-stream": {
9694 "version": "1.0.34", 9702 "version": "1.0.34",
9695 "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.0.34.tgz", 9703 "resolved": "http://registry.npmjs.org/readable-stream/-/readable-stream-1.0.34.tgz",
9696 "integrity": "sha1-Elgg40vIQtLyqq+v5MKRbuMsFXw=", 9704 "integrity": "sha1-Elgg40vIQtLyqq+v5MKRbuMsFXw=",
9697 "dev": true, 9705 "dev": true,
9698 "requires": { 9706 "requires": {
@@ -10273,7 +10281,7 @@
10273 "http-cache-semantics": { 10281 "http-cache-semantics": {
10274 "version": "3.8.1", 10282 "version": "3.8.1",
10275 "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-3.8.1.tgz", 10283 "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-3.8.1.tgz",
10276 "integrity": "sha512-5ai2iksyV8ZXmnZhHH4rWPoxxistEexSi5936zIQ1bnNTW5VnA85B6P/VpXiRM017IgRvb2kKo1a//y+0wSp3w==", 10284 "integrity": "sha1-ObDhat2bYFvwqe89nar0hDtMrNI=",
10277 "dev": true 10285 "dev": true
10278 }, 10286 },
10279 "http-deceiver": { 10287 "http-deceiver": {
@@ -10284,7 +10292,7 @@
10284 }, 10292 },
10285 "http-errors": { 10293 "http-errors": {
10286 "version": "1.6.3", 10294 "version": "1.6.3",
10287 "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.6.3.tgz", 10295 "resolved": "http://registry.npmjs.org/http-errors/-/http-errors-1.6.3.tgz",
10288 "integrity": "sha1-i1VoC7S+KDoLW/TqLjhYC+HZMg0=", 10296 "integrity": "sha1-i1VoC7S+KDoLW/TqLjhYC+HZMg0=",
10289 "dev": true, 10297 "dev": true,
10290 "requires": { 10298 "requires": {
@@ -10322,7 +10330,7 @@
10322 "http-proxy-agent": { 10330 "http-proxy-agent": {
10323 "version": "2.1.0", 10331 "version": "2.1.0",
10324 "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-2.1.0.tgz", 10332 "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-2.1.0.tgz",
10325 "integrity": "sha512-qwHbBLV7WviBl0rQsOzH6o5lwyOIvwp/BdFnvVxXORldu5TmjFfjzBcWUWS5kWAZhmv+JtiDhSuQCp4sBfbIgg==", 10333 "integrity": "sha1-5IIb7vWyFCogJr1zkm/lN2McVAU=",
10326 "dev": true, 10334 "dev": true,
10327 "requires": { 10335 "requires": {
10328 "agent-base": "4", 10336 "agent-base": "4",
@@ -10332,7 +10340,7 @@
10332 "debug": { 10340 "debug": {
10333 "version": "3.1.0", 10341 "version": "3.1.0",
10334 "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", 10342 "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz",
10335 "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", 10343 "integrity": "sha1-W7WgZyYotkFJVmuhaBnmFRjGcmE=",
10336 "dev": true, 10344 "dev": true,
10337 "requires": { 10345 "requires": {
10338 "ms": "2.0.0" 10346 "ms": "2.0.0"
@@ -10380,7 +10388,7 @@
10380 "https-proxy-agent": { 10388 "https-proxy-agent": {
10381 "version": "2.2.1", 10389 "version": "2.2.1",
10382 "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-2.2.1.tgz", 10390 "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-2.2.1.tgz",
10383 "integrity": "sha512-HPCTS1LW51bcyMYbxUIOO4HEOlQ1/1qRaFWcyxvwaqUS9TY88aoEuHUY33kuAh1YhVVaDQhLZsnPd+XNARWZlQ==", 10391 "integrity": "sha1-UVUpcPoE1yPgTFbQQXjD+SWSu8A=",
10384 "dev": true, 10392 "dev": true,
10385 "requires": { 10393 "requires": {
10386 "agent-base": "^4.1.0", 10394 "agent-base": "^4.1.0",
@@ -10390,7 +10398,7 @@
10390 "debug": { 10398 "debug": {
10391 "version": "3.2.6", 10399 "version": "3.2.6",
10392 "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz", 10400 "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz",
10393 "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==", 10401 "integrity": "sha1-6D0X3hbYp++3cX7b5fsQE17uYps=",
10394 "dev": true, 10402 "dev": true,
10395 "requires": { 10403 "requires": {
10396 "ms": "^2.1.1" 10404 "ms": "^2.1.1"
@@ -10399,7 +10407,7 @@
10399 "ms": { 10407 "ms": {
10400 "version": "2.1.1", 10408 "version": "2.1.1",
10401 "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz", 10409 "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz",
10402 "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==", 10410 "integrity": "sha1-MKWGTrPrsKZvLr5tcnrwagnYbgo=",
10403 "dev": true 10411 "dev": true
10404 } 10412 }
10405 } 10413 }
@@ -10415,7 +10423,7 @@
10415 }, 10423 },
10416 "hunspell-asm": { 10424 "hunspell-asm": {
10417 "version": "1.0.2", 10425 "version": "1.0.2",
10418 "resolved": "https://registry.npmjs.org/hunspell-asm/-/hunspell-asm-1.0.2.tgz", 10426 "resolved": "http://registry.npmjs.org/hunspell-asm/-/hunspell-asm-1.0.2.tgz",
10419 "integrity": "sha512-UTLBvc0yZiIcHl9qrgxnFTZbX3zF4CprzEY+u+N0iXlUKZnUJRIgvgppTdgiQTsucm5b0aN/rHsgXz2q/0kBRA==", 10427 "integrity": "sha512-UTLBvc0yZiIcHl9qrgxnFTZbX3zF4CprzEY+u+N0iXlUKZnUJRIgvgppTdgiQTsucm5b0aN/rHsgXz2q/0kBRA==",
10420 "requires": { 10428 "requires": {
10421 "emscripten-wasm-loader": "^1.0.0", 10429 "emscripten-wasm-loader": "^1.0.0",
@@ -10493,7 +10501,7 @@
10493 "ignore-walk": { 10501 "ignore-walk": {
10494 "version": "3.0.1", 10502 "version": "3.0.1",
10495 "resolved": "https://registry.npmjs.org/ignore-walk/-/ignore-walk-3.0.1.tgz", 10503 "resolved": "https://registry.npmjs.org/ignore-walk/-/ignore-walk-3.0.1.tgz",
10496 "integrity": "sha512-DTVlMx3IYPe0/JJcYP7Gxg7ttZZu3IInhuEhbchuqneY9wWe5Ojy2mXLBaQFUQmo0AW2r3qG7m1mg86js+gnlQ==", 10504 "integrity": "sha1-qD5i59JyrA47VRqqgoMaGbafgvg=",
10497 "dev": true, 10505 "dev": true,
10498 "requires": { 10506 "requires": {
10499 "minimatch": "^3.0.4" 10507 "minimatch": "^3.0.4"
@@ -10535,7 +10543,7 @@
10535 "import-local": { 10543 "import-local": {
10536 "version": "1.0.0", 10544 "version": "1.0.0",
10537 "resolved": "https://registry.npmjs.org/import-local/-/import-local-1.0.0.tgz", 10545 "resolved": "https://registry.npmjs.org/import-local/-/import-local-1.0.0.tgz",
10538 "integrity": "sha512-vAaZHieK9qjGo58agRBg+bhHX3hoTZU/Oa3GESWLz7t1U62fk63aHuDJJEteXoDeTCcPmUT+z38gkHPZkkmpmQ==", 10546 "integrity": "sha1-Xk/9wD9P5sAJxnKb6yljHC+CJ7w=",
10539 "dev": true, 10547 "dev": true,
10540 "requires": { 10548 "requires": {
10541 "pkg-dir": "^2.0.0", 10549 "pkg-dir": "^2.0.0",
@@ -10599,7 +10607,7 @@
10599 "init-package-json": { 10607 "init-package-json": {
10600 "version": "1.10.3", 10608 "version": "1.10.3",
10601 "resolved": "https://registry.npmjs.org/init-package-json/-/init-package-json-1.10.3.tgz", 10609 "resolved": "https://registry.npmjs.org/init-package-json/-/init-package-json-1.10.3.tgz",
10602 "integrity": "sha512-zKSiXKhQveNteyhcj1CoOP8tqp1QuxPIPBl8Bid99DGLFqA1p87M6lNgfjJHSBoWJJlidGOv5rWjyYKEB3g2Jw==", 10610 "integrity": "sha1-Rf/i9hCoyhNPK9HbVjeyNQcPbL4=",
10603 "dev": true, 10611 "dev": true,
10604 "requires": { 10612 "requires": {
10605 "glob": "^7.1.1", 10613 "glob": "^7.1.1",
@@ -10703,7 +10711,7 @@
10703 "inversify": { 10711 "inversify": {
10704 "version": "5.0.1", 10712 "version": "5.0.1",
10705 "resolved": "https://registry.npmjs.org/inversify/-/inversify-5.0.1.tgz", 10713 "resolved": "https://registry.npmjs.org/inversify/-/inversify-5.0.1.tgz",
10706 "integrity": "sha512-Ieh06s48WnEYGcqHepdsJUIJUXpwH5o5vodAX+DK2JA/gjy4EbEcQZxw+uFfzysmKjiLXGYwNG3qDZsKVMcINQ==", 10714 "integrity": "sha1-UA1wmxQ0iWzloNWJFcSkIQ40+24=",
10707 "dev": true 10715 "dev": true
10708 }, 10716 },
10709 "invert-kv": { 10717 "invert-kv": {
@@ -10732,7 +10740,7 @@
10732 }, 10740 },
10733 "is": { 10741 "is": {
10734 "version": "0.3.0", 10742 "version": "0.3.0",
10735 "resolved": "https://registry.npmjs.org/is/-/is-0.3.0.tgz", 10743 "resolved": "http://registry.npmjs.org/is/-/is-0.3.0.tgz",
10736 "integrity": "sha1-qPcd/IpuKDcWJ/JskpCYxvTV1dc=", 10744 "integrity": "sha1-qPcd/IpuKDcWJ/JskpCYxvTV1dc=",
10737 "dev": true 10745 "dev": true
10738 }, 10746 },
@@ -10956,7 +10964,7 @@
10956 }, 10964 },
10957 "is-obj": { 10965 "is-obj": {
10958 "version": "1.0.1", 10966 "version": "1.0.1",
10959 "resolved": "https://registry.npmjs.org/is-obj/-/is-obj-1.0.1.tgz", 10967 "resolved": "http://registry.npmjs.org/is-obj/-/is-obj-1.0.1.tgz",
10960 "integrity": "sha1-PkcprB9f3gJc19g6iW2rn09n2w8=", 10968 "integrity": "sha1-PkcprB9f3gJc19g6iW2rn09n2w8=",
10961 "dev": true 10969 "dev": true
10962 }, 10970 },
@@ -11138,7 +11146,7 @@
11138 }, 11146 },
11139 "isemail": { 11147 "isemail": {
11140 "version": "1.2.0", 11148 "version": "1.2.0",
11141 "resolved": "https://registry.npmjs.org/isemail/-/isemail-1.2.0.tgz", 11149 "resolved": "http://registry.npmjs.org/isemail/-/isemail-1.2.0.tgz",
11142 "integrity": "sha1-vgPfjMPineTSxd9lASY/H6RZXpo=" 11150 "integrity": "sha1-vgPfjMPineTSxd9lASY/H6RZXpo="
11143 }, 11151 },
11144 "isexe": { 11152 "isexe": {
@@ -11169,7 +11177,7 @@
11169 }, 11177 },
11170 "joi": { 11178 "joi": {
11171 "version": "6.10.1", 11179 "version": "6.10.1",
11172 "resolved": "https://registry.npmjs.org/joi/-/joi-6.10.1.tgz", 11180 "resolved": "http://registry.npmjs.org/joi/-/joi-6.10.1.tgz",
11173 "integrity": "sha1-TVDDGAeRIgAP5fFq8f+OGRe3fgY=", 11181 "integrity": "sha1-TVDDGAeRIgAP5fFq8f+OGRe3fgY=",
11174 "requires": { 11182 "requires": {
11175 "hoek": "2.x.x", 11183 "hoek": "2.x.x",
@@ -11566,7 +11574,7 @@
11566 "libnpmaccess": { 11574 "libnpmaccess": {
11567 "version": "3.0.1", 11575 "version": "3.0.1",
11568 "resolved": "https://registry.npmjs.org/libnpmaccess/-/libnpmaccess-3.0.1.tgz", 11576 "resolved": "https://registry.npmjs.org/libnpmaccess/-/libnpmaccess-3.0.1.tgz",
11569 "integrity": "sha512-RlZ7PNarCBt+XbnP7R6PoVgOq9t+kou5rvhaInoNibhPO7eMlRfS0B8yjatgn2yaHIwWNyoJDolC/6Lc5L/IQA==", 11577 "integrity": "sha1-Wzqd5iHyk9QlGRqi53kQL4QWf6g=",
11570 "dev": true, 11578 "dev": true,
11571 "requires": { 11579 "requires": {
11572 "aproba": "^2.0.0", 11580 "aproba": "^2.0.0",
@@ -11578,7 +11586,7 @@
11578 "aproba": { 11586 "aproba": {
11579 "version": "2.0.0", 11587 "version": "2.0.0",
11580 "resolved": "https://registry.npmjs.org/aproba/-/aproba-2.0.0.tgz", 11588 "resolved": "https://registry.npmjs.org/aproba/-/aproba-2.0.0.tgz",
11581 "integrity": "sha512-lYe4Gx7QT+MKGbDsA+Z+he/Wtef0BiwDOlK/XkBrdfsh9J/jPPXbX0tE9x9cl27Tmu5gg3QUbUrQYa/y+KOHPQ==", 11589 "integrity": "sha1-UlILiuW1aSFbNU78DKo/4eRaitw=",
11582 "dev": true 11590 "dev": true
11583 } 11591 }
11584 } 11592 }
@@ -12024,7 +12032,7 @@
12024 "make-fetch-happen": { 12032 "make-fetch-happen": {
12025 "version": "4.0.1", 12033 "version": "4.0.1",
12026 "resolved": "https://registry.npmjs.org/make-fetch-happen/-/make-fetch-happen-4.0.1.tgz", 12034 "resolved": "https://registry.npmjs.org/make-fetch-happen/-/make-fetch-happen-4.0.1.tgz",
12027 "integrity": "sha512-7R5ivfy9ilRJ1EMKIOziwrns9fGeAD4bAha8EB7BIiBBLHm2KeTUGCrICFt2rbHfzheTLynv50GnNTK1zDTrcQ==", 12035 "integrity": "sha1-FBSXy4ePJDupMTbIPYq6EsIWwIM=",
12028 "dev": true, 12036 "dev": true,
12029 "requires": { 12037 "requires": {
12030 "agentkeepalive": "^3.4.1", 12038 "agentkeepalive": "^3.4.1",
@@ -12115,7 +12123,7 @@
12115 }, 12123 },
12116 "media-typer": { 12124 "media-typer": {
12117 "version": "0.3.0", 12125 "version": "0.3.0",
12118 "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", 12126 "resolved": "http://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz",
12119 "integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g=", 12127 "integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g=",
12120 "dev": true 12128 "dev": true
12121 }, 12129 },
@@ -12206,7 +12214,7 @@
12206 }, 12214 },
12207 "readable-stream": { 12215 "readable-stream": {
12208 "version": "1.0.34", 12216 "version": "1.0.34",
12209 "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.0.34.tgz", 12217 "resolved": "http://registry.npmjs.org/readable-stream/-/readable-stream-1.0.34.tgz",
12210 "integrity": "sha1-Elgg40vIQtLyqq+v5MKRbuMsFXw=", 12218 "integrity": "sha1-Elgg40vIQtLyqq+v5MKRbuMsFXw=",
12211 "dev": true, 12219 "dev": true,
12212 "requires": { 12220 "requires": {
@@ -12237,7 +12245,7 @@
12237 "merge2": { 12245 "merge2": {
12238 "version": "1.2.3", 12246 "version": "1.2.3",
12239 "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.2.3.tgz", 12247 "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.2.3.tgz",
12240 "integrity": "sha512-gdUU1Fwj5ep4kplwcmftruWofEFt6lfpkkr3h860CXbAB9c3hGb55EOL2ali0Td5oebvW0E1+3Sr+Ur7XfKpRA==", 12248 "integrity": "sha1-fumdvWm7ZIFoklPwGEiKG5ArDtU=",
12241 "dev": true 12249 "dev": true
12242 }, 12250 },
12243 "methods": { 12251 "methods": {
@@ -12331,7 +12339,7 @@
12331 }, 12339 },
12332 "minimist": { 12340 "minimist": {
12333 "version": "1.2.0", 12341 "version": "1.2.0",
12334 "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", 12342 "resolved": "http://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz",
12335 "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", 12343 "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=",
12336 "dev": true 12344 "dev": true
12337 }, 12345 },
@@ -12365,7 +12373,7 @@
12365 "mississippi": { 12373 "mississippi": {
12366 "version": "3.0.0", 12374 "version": "3.0.0",
12367 "resolved": "https://registry.npmjs.org/mississippi/-/mississippi-3.0.0.tgz", 12375 "resolved": "https://registry.npmjs.org/mississippi/-/mississippi-3.0.0.tgz",
12368 "integrity": "sha512-x471SsVjUtBRtcvd4BzKE9kFC+/2TeWgKCgw0bZcw1b9l2X3QX5vCWgF+KaZaYm87Ss//rHnWryupDrgLvmSkA==", 12376 "integrity": "sha1-6goykfl+C16HdrNj1fChLZTGcCI=",
12369 "dev": true, 12377 "dev": true,
12370 "requires": { 12378 "requires": {
12371 "concat-stream": "^1.5.0", 12379 "concat-stream": "^1.5.0",
@@ -12403,7 +12411,7 @@
12403 }, 12411 },
12404 "mkdirp": { 12412 "mkdirp": {
12405 "version": "0.5.1", 12413 "version": "0.5.1",
12406 "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", 12414 "resolved": "http://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz",
12407 "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", 12415 "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=",
12408 "requires": { 12416 "requires": {
12409 "minimist": "0.0.8" 12417 "minimist": "0.0.8"
@@ -12411,7 +12419,7 @@
12411 "dependencies": { 12419 "dependencies": {
12412 "minimist": { 12420 "minimist": {
12413 "version": "0.0.8", 12421 "version": "0.0.8",
12414 "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", 12422 "resolved": "http://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz",
12415 "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=" 12423 "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0="
12416 } 12424 }
12417 } 12425 }
@@ -12583,7 +12591,7 @@
12583 }, 12591 },
12584 "multimatch": { 12592 "multimatch": {
12585 "version": "2.1.0", 12593 "version": "2.1.0",
12586 "resolved": "https://registry.npmjs.org/multimatch/-/multimatch-2.1.0.tgz", 12594 "resolved": "http://registry.npmjs.org/multimatch/-/multimatch-2.1.0.tgz",
12587 "integrity": "sha1-nHkGoi+0wCkZ4vX3UWG0zb1LKis=", 12595 "integrity": "sha1-nHkGoi+0wCkZ4vX3UWG0zb1LKis=",
12588 "dev": true, 12596 "dev": true,
12589 "requires": { 12597 "requires": {
@@ -12721,7 +12729,7 @@
12721 "node-fetch-npm": { 12729 "node-fetch-npm": {
12722 "version": "2.0.2", 12730 "version": "2.0.2",
12723 "resolved": "https://registry.npmjs.org/node-fetch-npm/-/node-fetch-npm-2.0.2.tgz", 12731 "resolved": "https://registry.npmjs.org/node-fetch-npm/-/node-fetch-npm-2.0.2.tgz",
12724 "integrity": "sha512-nJIxm1QmAj4v3nfCvEeCrYSoVwXyxLnaPBK5W1W5DGEJwjlKuC2VEUycGw5oxk+4zZahRrB84PUJJgEmhFTDFw==", 12732 "integrity": "sha1-cljJBGGC3KNFtCCO2pGNrzNpf/c=",
12725 "dev": true, 12733 "dev": true,
12726 "requires": { 12734 "requires": {
12727 "encoding": "^0.1.11", 12735 "encoding": "^0.1.11",
@@ -12757,7 +12765,7 @@
12757 "dependencies": { 12765 "dependencies": {
12758 "semver": { 12766 "semver": {
12759 "version": "5.3.0", 12767 "version": "5.3.0",
12760 "resolved": "https://registry.npmjs.org/semver/-/semver-5.3.0.tgz", 12768 "resolved": "http://registry.npmjs.org/semver/-/semver-5.3.0.tgz",
12761 "integrity": "sha1-myzl094C0XxgEq0yaqa00M9U+U8=", 12769 "integrity": "sha1-myzl094C0XxgEq0yaqa00M9U+U8=",
12762 "dev": true 12770 "dev": true
12763 }, 12771 },
@@ -13935,7 +13943,7 @@
13935 "p-map": { 13943 "p-map": {
13936 "version": "1.2.0", 13944 "version": "1.2.0",
13937 "resolved": "https://registry.npmjs.org/p-map/-/p-map-1.2.0.tgz", 13945 "resolved": "https://registry.npmjs.org/p-map/-/p-map-1.2.0.tgz",
13938 "integrity": "sha512-r6zKACMNhjPJMTl8KcFH4li//gkrXWfbD6feV8l6doRHlzljFWGJ2AP6iKaCJXyZmAUMOPtvbW7EXkbWO/pLEA==", 13946 "integrity": "sha1-5OlPMR6rvIYzoeeZCBZfyiYkG2s=",
13939 "dev": true 13947 "dev": true
13940 }, 13948 },
13941 "p-map-series": { 13949 "p-map-series": {
@@ -14108,7 +14116,7 @@
14108 "dependencies": { 14116 "dependencies": {
14109 "color-convert": { 14117 "color-convert": {
14110 "version": "0.5.3", 14118 "version": "0.5.3",
14111 "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-0.5.3.tgz", 14119 "resolved": "http://registry.npmjs.org/color-convert/-/color-convert-0.5.3.tgz",
14112 "integrity": "sha1-vbbGnOZg+t/+CwAHzER+G59ygr0=", 14120 "integrity": "sha1-vbbGnOZg+t/+CwAHzER+G59ygr0=",
14113 "dev": true 14121 "dev": true
14114 } 14122 }
@@ -14253,7 +14261,7 @@
14253 }, 14261 },
14254 "path-browserify": { 14262 "path-browserify": {
14255 "version": "0.0.0", 14263 "version": "0.0.0",
14256 "resolved": "https://registry.npmjs.org/path-browserify/-/path-browserify-0.0.0.tgz", 14264 "resolved": "http://registry.npmjs.org/path-browserify/-/path-browserify-0.0.0.tgz",
14257 "integrity": "sha1-oLhwcpquIUAFt9UDLsLLuw+0RRo=", 14265 "integrity": "sha1-oLhwcpquIUAFt9UDLsLLuw+0RRo=",
14258 "dev": true 14266 "dev": true
14259 }, 14267 },
@@ -14532,7 +14540,7 @@
14532 }, 14540 },
14533 "pretty-hrtime": { 14541 "pretty-hrtime": {
14534 "version": "1.0.3", 14542 "version": "1.0.3",
14535 "resolved": "https://registry.npmjs.org/pretty-hrtime/-/pretty-hrtime-1.0.3.tgz", 14543 "resolved": "http://registry.npmjs.org/pretty-hrtime/-/pretty-hrtime-1.0.3.tgz",
14536 "integrity": "sha1-t+PqQkNaTJsnWdmeDyAesZWALuE=", 14544 "integrity": "sha1-t+PqQkNaTJsnWdmeDyAesZWALuE=",
14537 "dev": true 14545 "dev": true
14538 }, 14546 },
@@ -14677,7 +14685,7 @@
14677 "protoduck": { 14685 "protoduck": {
14678 "version": "5.0.1", 14686 "version": "5.0.1",
14679 "resolved": "https://registry.npmjs.org/protoduck/-/protoduck-5.0.1.tgz", 14687 "resolved": "https://registry.npmjs.org/protoduck/-/protoduck-5.0.1.tgz",
14680 "integrity": "sha512-WxoCeDCoCBY55BMvj4cAEjdVUFGRWed9ZxPlqTKYyw1nDDTQ4pqmnIMAGfJlg7Dx35uB/M+PHJPTmGOvaCaPTg==", 14688 "integrity": "sha1-A8NlnKGAB7aaUP2Cp+vMUWJhFR8=",
14681 "dev": true, 14689 "dev": true,
14682 "requires": { 14690 "requires": {
14683 "genfun": "^5.0.0" 14691 "genfun": "^5.0.0"
@@ -15025,7 +15033,7 @@
15025 }, 15033 },
15026 "react-router": { 15034 "react-router": {
15027 "version": "3.2.1", 15035 "version": "3.2.1",
15028 "resolved": "https://registry.npmjs.org/react-router/-/react-router-3.2.1.tgz", 15036 "resolved": "http://registry.npmjs.org/react-router/-/react-router-3.2.1.tgz",
15029 "integrity": "sha512-SXkhC0nr3G0ltzVU07IN8jYl0bB6FsrDIqlLC9dK3SITXqyTJyM7yhXlUqs89w3Nqi5OkXsfRUeHX+P874HQrg==", 15037 "integrity": "sha512-SXkhC0nr3G0ltzVU07IN8jYl0bB6FsrDIqlLC9dK3SITXqyTJyM7yhXlUqs89w3Nqi5OkXsfRUeHX+P874HQrg==",
15030 "requires": { 15038 "requires": {
15031 "create-react-class": "^15.5.1", 15039 "create-react-class": "^15.5.1",
@@ -15140,7 +15148,7 @@
15140 "read-package-json": { 15148 "read-package-json": {
15141 "version": "2.0.13", 15149 "version": "2.0.13",
15142 "resolved": "https://registry.npmjs.org/read-package-json/-/read-package-json-2.0.13.tgz", 15150 "resolved": "https://registry.npmjs.org/read-package-json/-/read-package-json-2.0.13.tgz",
15143 "integrity": "sha512-/1dZ7TRZvGrYqE0UAfN6qQb5GYBsNcqS1C0tNK601CFOJmtHI7NIGXwetEPU/OtoFHZL3hDxm4rolFFVE9Bnmg==", 15151 "integrity": "sha1-LoLr2fYTuqbS6+Oqcs7+P2jkH0o=",
15144 "dev": true, 15152 "dev": true,
15145 "requires": { 15153 "requires": {
15146 "glob": "^7.1.1", 15154 "glob": "^7.1.1",
@@ -15161,7 +15169,7 @@
15161 "read-package-tree": { 15169 "read-package-tree": {
15162 "version": "5.2.1", 15170 "version": "5.2.1",
15163 "resolved": "https://registry.npmjs.org/read-package-tree/-/read-package-tree-5.2.1.tgz", 15171 "resolved": "https://registry.npmjs.org/read-package-tree/-/read-package-tree-5.2.1.tgz",
15164 "integrity": "sha512-2CNoRoh95LxY47LvqrehIAfUVda2JbuFE/HaGYs42bNrGG+ojbw1h3zOcPcQ+1GQ3+rkzNndZn85u1XyZ3UsIA==", 15172 "integrity": "sha1-Yhixh9b6yCKJzkOHu7r47vU2rWM=",
15165 "dev": true, 15173 "dev": true,
15166 "requires": { 15174 "requires": {
15167 "debuglog": "^1.0.1", 15175 "debuglog": "^1.0.1",
@@ -15529,7 +15537,7 @@
15529 }, 15537 },
15530 "htmlparser2": { 15538 "htmlparser2": {
15531 "version": "3.3.0", 15539 "version": "3.3.0",
15532 "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-3.3.0.tgz", 15540 "resolved": "http://registry.npmjs.org/htmlparser2/-/htmlparser2-3.3.0.tgz",
15533 "integrity": "sha1-zHDQWln2VC5D8OaFyYLhTJJKnv4=", 15541 "integrity": "sha1-zHDQWln2VC5D8OaFyYLhTJJKnv4=",
15534 "dev": true, 15542 "dev": true,
15535 "requires": { 15543 "requires": {
@@ -15547,7 +15555,7 @@
15547 }, 15555 },
15548 "readable-stream": { 15556 "readable-stream": {
15549 "version": "1.0.34", 15557 "version": "1.0.34",
15550 "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.0.34.tgz", 15558 "resolved": "http://registry.npmjs.org/readable-stream/-/readable-stream-1.0.34.tgz",
15551 "integrity": "sha1-Elgg40vIQtLyqq+v5MKRbuMsFXw=", 15559 "integrity": "sha1-Elgg40vIQtLyqq+v5MKRbuMsFXw=",
15552 "dev": true, 15560 "dev": true,
15553 "requires": { 15561 "requires": {
@@ -15559,7 +15567,7 @@
15559 }, 15567 },
15560 "string_decoder": { 15568 "string_decoder": {
15561 "version": "0.10.31", 15569 "version": "0.10.31",
15562 "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", 15570 "resolved": "http://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz",
15563 "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=", 15571 "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=",
15564 "dev": true 15572 "dev": true
15565 }, 15573 },
@@ -16182,7 +16190,7 @@
16182 "dependencies": { 16190 "dependencies": {
16183 "debug": { 16191 "debug": {
16184 "version": "1.0.4", 16192 "version": "1.0.4",
16185 "resolved": "https://registry.npmjs.org/debug/-/debug-1.0.4.tgz", 16193 "resolved": "http://registry.npmjs.org/debug/-/debug-1.0.4.tgz",
16186 "integrity": "sha1-W5wla9VLbsAigxdvqKDt5tFUy/g=", 16194 "integrity": "sha1-W5wla9VLbsAigxdvqKDt5tFUy/g=",
16187 "dev": true, 16195 "dev": true,
16188 "requires": { 16196 "requires": {
@@ -16197,7 +16205,7 @@
16197 }, 16205 },
16198 "ms": { 16206 "ms": {
16199 "version": "0.6.2", 16207 "version": "0.6.2",
16200 "resolved": "https://registry.npmjs.org/ms/-/ms-0.6.2.tgz", 16208 "resolved": "http://registry.npmjs.org/ms/-/ms-0.6.2.tgz",
16201 "integrity": "sha1-2JwhJMb9wTU9Zai3e/GqxLGTcIw=", 16209 "integrity": "sha1-2JwhJMb9wTU9Zai3e/GqxLGTcIw=",
16202 "dev": true 16210 "dev": true
16203 } 16211 }
@@ -16274,7 +16282,7 @@
16274 }, 16282 },
16275 "sha.js": { 16283 "sha.js": {
16276 "version": "2.4.11", 16284 "version": "2.4.11",
16277 "resolved": "https://registry.npmjs.org/sha.js/-/sha.js-2.4.11.tgz", 16285 "resolved": "http://registry.npmjs.org/sha.js/-/sha.js-2.4.11.tgz",
16278 "integrity": "sha512-QMEp5B7cftE7APOjk5Y6xgrbWu+WkLVQwk8JNjZ8nKRciZaByEW6MubieAiToS7+dwvrjGhH8jRXz3MVd0AYqQ==", 16286 "integrity": "sha512-QMEp5B7cftE7APOjk5Y6xgrbWu+WkLVQwk8JNjZ8nKRciZaByEW6MubieAiToS7+dwvrjGhH8jRXz3MVd0AYqQ==",
16279 "dev": true, 16287 "dev": true,
16280 "requires": { 16288 "requires": {
@@ -16525,7 +16533,7 @@
16525 "dependencies": { 16533 "dependencies": {
16526 "debug": { 16534 "debug": {
16527 "version": "2.3.3", 16535 "version": "2.3.3",
16528 "resolved": "https://registry.npmjs.org/debug/-/debug-2.3.3.tgz", 16536 "resolved": "http://registry.npmjs.org/debug/-/debug-2.3.3.tgz",
16529 "integrity": "sha1-QMRT5n5uE8kB3ewxeviYbNqe/4w=", 16537 "integrity": "sha1-QMRT5n5uE8kB3ewxeviYbNqe/4w=",
16530 "dev": true, 16538 "dev": true,
16531 "requires": { 16539 "requires": {
@@ -16534,7 +16542,7 @@
16534 }, 16542 },
16535 "ms": { 16543 "ms": {
16536 "version": "0.7.2", 16544 "version": "0.7.2",
16537 "resolved": "https://registry.npmjs.org/ms/-/ms-0.7.2.tgz", 16545 "resolved": "http://registry.npmjs.org/ms/-/ms-0.7.2.tgz",
16538 "integrity": "sha1-riXPJRKziFodldfwN4aNhDESR2U=", 16546 "integrity": "sha1-riXPJRKziFodldfwN4aNhDESR2U=",
16539 "dev": true 16547 "dev": true
16540 }, 16548 },
@@ -16558,7 +16566,7 @@
16558 "dependencies": { 16566 "dependencies": {
16559 "debug": { 16567 "debug": {
16560 "version": "2.3.3", 16568 "version": "2.3.3",
16561 "resolved": "https://registry.npmjs.org/debug/-/debug-2.3.3.tgz", 16569 "resolved": "http://registry.npmjs.org/debug/-/debug-2.3.3.tgz",
16562 "integrity": "sha1-QMRT5n5uE8kB3ewxeviYbNqe/4w=", 16570 "integrity": "sha1-QMRT5n5uE8kB3ewxeviYbNqe/4w=",
16563 "dev": true, 16571 "dev": true,
16564 "requires": { 16572 "requires": {
@@ -16567,7 +16575,7 @@
16567 }, 16575 },
16568 "ms": { 16576 "ms": {
16569 "version": "0.7.2", 16577 "version": "0.7.2",
16570 "resolved": "https://registry.npmjs.org/ms/-/ms-0.7.2.tgz", 16578 "resolved": "http://registry.npmjs.org/ms/-/ms-0.7.2.tgz",
16571 "integrity": "sha1-riXPJRKziFodldfwN4aNhDESR2U=", 16579 "integrity": "sha1-riXPJRKziFodldfwN4aNhDESR2U=",
16572 "dev": true 16580 "dev": true
16573 } 16581 }
@@ -16594,7 +16602,7 @@
16594 "dependencies": { 16602 "dependencies": {
16595 "debug": { 16603 "debug": {
16596 "version": "2.3.3", 16604 "version": "2.3.3",
16597 "resolved": "https://registry.npmjs.org/debug/-/debug-2.3.3.tgz", 16605 "resolved": "http://registry.npmjs.org/debug/-/debug-2.3.3.tgz",
16598 "integrity": "sha1-QMRT5n5uE8kB3ewxeviYbNqe/4w=", 16606 "integrity": "sha1-QMRT5n5uE8kB3ewxeviYbNqe/4w=",
16599 "dev": true, 16607 "dev": true,
16600 "requires": { 16608 "requires": {
@@ -16603,7 +16611,7 @@
16603 }, 16611 },
16604 "ms": { 16612 "ms": {
16605 "version": "0.7.2", 16613 "version": "0.7.2",
16606 "resolved": "https://registry.npmjs.org/ms/-/ms-0.7.2.tgz", 16614 "resolved": "http://registry.npmjs.org/ms/-/ms-0.7.2.tgz",
16607 "integrity": "sha1-riXPJRKziFodldfwN4aNhDESR2U=", 16615 "integrity": "sha1-riXPJRKziFodldfwN4aNhDESR2U=",
16608 "dev": true 16616 "dev": true
16609 } 16617 }
@@ -16629,7 +16637,7 @@
16629 }, 16637 },
16630 "debug": { 16638 "debug": {
16631 "version": "2.2.0", 16639 "version": "2.2.0",
16632 "resolved": "https://registry.npmjs.org/debug/-/debug-2.2.0.tgz", 16640 "resolved": "http://registry.npmjs.org/debug/-/debug-2.2.0.tgz",
16633 "integrity": "sha1-+HBX6ZWxofauaklgZkE3vFbwOdo=", 16641 "integrity": "sha1-+HBX6ZWxofauaklgZkE3vFbwOdo=",
16634 "dev": true, 16642 "dev": true,
16635 "requires": { 16643 "requires": {
@@ -16644,7 +16652,7 @@
16644 }, 16652 },
16645 "ms": { 16653 "ms": {
16646 "version": "0.7.1", 16654 "version": "0.7.1",
16647 "resolved": "https://registry.npmjs.org/ms/-/ms-0.7.1.tgz", 16655 "resolved": "http://registry.npmjs.org/ms/-/ms-0.7.1.tgz",
16648 "integrity": "sha1-nNE8A62/8ltl7/3nzoZO6VIBcJg=", 16656 "integrity": "sha1-nNE8A62/8ltl7/3nzoZO6VIBcJg=",
16649 "dev": true 16657 "dev": true
16650 } 16658 }
@@ -16720,7 +16728,7 @@
16720 "socks-proxy-agent": { 16728 "socks-proxy-agent": {
16721 "version": "4.0.1", 16729 "version": "4.0.1",
16722 "resolved": "https://registry.npmjs.org/socks-proxy-agent/-/socks-proxy-agent-4.0.1.tgz", 16730 "resolved": "https://registry.npmjs.org/socks-proxy-agent/-/socks-proxy-agent-4.0.1.tgz",
16723 "integrity": "sha512-Kezx6/VBguXOsEe5oU3lXYyKMi4+gva72TwJ7pQY5JfqUx2nMk7NXA6z/mpNqIlfQjWYVfeuNvQjexiTaTn6Nw==", 16731 "integrity": "sha1-WTa/i3B6mTB5xvN9sgkYIb/6ZHM=",
16724 "dev": true, 16732 "dev": true,
16725 "requires": { 16733 "requires": {
16726 "agent-base": "~4.2.0", 16734 "agent-base": "~4.2.0",
@@ -16957,7 +16965,7 @@
16957 "ssri": { 16965 "ssri": {
16958 "version": "6.0.1", 16966 "version": "6.0.1",
16959 "resolved": "https://registry.npmjs.org/ssri/-/ssri-6.0.1.tgz", 16967 "resolved": "https://registry.npmjs.org/ssri/-/ssri-6.0.1.tgz",
16960 "integrity": "sha512-3Wge10hNcT1Kur4PDFwEieXSCMCJs/7WvSACcrMYrNp+b8kDL1/0wJch5Ni2WrtwEa2IO8OsVfeKIciKCDx/QA==", 16968 "integrity": "sha1-KjxBso3UW2K2Nnbst0ABJlrp7dg=",
16961 "dev": true, 16969 "dev": true,
16962 "requires": { 16970 "requires": {
16963 "figgy-pudding": "^3.5.1" 16971 "figgy-pudding": "^3.5.1"
@@ -17076,7 +17084,7 @@
17076 "stream-each": { 17084 "stream-each": {
17077 "version": "1.2.3", 17085 "version": "1.2.3",
17078 "resolved": "https://registry.npmjs.org/stream-each/-/stream-each-1.2.3.tgz", 17086 "resolved": "https://registry.npmjs.org/stream-each/-/stream-each-1.2.3.tgz",
17079 "integrity": "sha512-vlMC2f8I2u/bZGqkdfLQW/13Zihpej/7PmSiMQsbYddxuTsJp8vRe2x2FvVExZg7FaOds43ROAuFJwPR4MTZLw==", 17087 "integrity": "sha1-6+J6DDibBPvMIzZClS4Qcxr6m64=",
17080 "dev": true, 17088 "dev": true,
17081 "requires": { 17089 "requires": {
17082 "end-of-stream": "^1.1.0", 17090 "end-of-stream": "^1.1.0",
@@ -17472,7 +17480,7 @@
17472 }, 17480 },
17473 "through": { 17481 "through": {
17474 "version": "2.3.8", 17482 "version": "2.3.8",
17475 "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", 17483 "resolved": "http://registry.npmjs.org/through/-/through-2.3.8.tgz",
17476 "integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=", 17484 "integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=",
17477 "dev": true 17485 "dev": true
17478 }, 17486 },
@@ -17744,7 +17752,7 @@
17744 "tslint": { 17752 "tslint": {
17745 "version": "5.12.0", 17753 "version": "5.12.0",
17746 "resolved": "https://registry.npmjs.org/tslint/-/tslint-5.12.0.tgz", 17754 "resolved": "https://registry.npmjs.org/tslint/-/tslint-5.12.0.tgz",
17747 "integrity": "sha512-CKEcH1MHUBhoV43SA/Jmy1l24HJJgI0eyLbBNSRyFlsQvb9v6Zdq+Nz2vEOH00nC5SUx4SneJ59PZUS/ARcokQ==", 17755 "integrity": "sha1-R/LbopHtPVgHUtEJhm+2QHaPyjY=",
17748 "dev": true, 17756 "dev": true,
17749 "requires": { 17757 "requires": {
17750 "babel-code-frame": "^6.22.0", 17758 "babel-code-frame": "^6.22.0",
@@ -17764,7 +17772,7 @@
17764 "tslint-config-airbnb": { 17772 "tslint-config-airbnb": {
17765 "version": "5.11.1", 17773 "version": "5.11.1",
17766 "resolved": "https://registry.npmjs.org/tslint-config-airbnb/-/tslint-config-airbnb-5.11.1.tgz", 17774 "resolved": "https://registry.npmjs.org/tslint-config-airbnb/-/tslint-config-airbnb-5.11.1.tgz",
17767 "integrity": "sha512-hkaittm2607vVMe8eotANGN1CimD5tor7uoY3ypg2VTtEcDB/KGWYbJOz58t8LI4cWSyWtgqYQ5F0HwKxxhlkQ==", 17775 "integrity": "sha1-UaJ/u4vyTBRNBkonSnHaR+fs5hc=",
17768 "dev": true, 17776 "dev": true,
17769 "requires": { 17777 "requires": {
17770 "tslint-consistent-codestyle": "^1.14.1", 17778 "tslint-consistent-codestyle": "^1.14.1",
@@ -17786,7 +17794,7 @@
17786 "tslint-eslint-rules": { 17794 "tslint-eslint-rules": {
17787 "version": "5.4.0", 17795 "version": "5.4.0",
17788 "resolved": "https://registry.npmjs.org/tslint-eslint-rules/-/tslint-eslint-rules-5.4.0.tgz", 17796 "resolved": "https://registry.npmjs.org/tslint-eslint-rules/-/tslint-eslint-rules-5.4.0.tgz",
17789 "integrity": "sha512-WlSXE+J2vY/VPgIcqQuijMQiel+UtmXS+4nvK4ZzlDiqBfXse8FAvkNnTcYhnQyOTW5KFM+uRRGXxYhFpuBc6w==", 17797 "integrity": "sha1-5IjMkYG/GT/lzXv8ohOnaV8XN7U=",
17790 "dev": true, 17798 "dev": true,
17791 "requires": { 17799 "requires": {
17792 "doctrine": "0.7.2", 17800 "doctrine": "0.7.2",
@@ -17796,7 +17804,7 @@
17796 "dependencies": { 17804 "dependencies": {
17797 "doctrine": { 17805 "doctrine": {
17798 "version": "0.7.2", 17806 "version": "0.7.2",
17799 "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-0.7.2.tgz", 17807 "resolved": "http://registry.npmjs.org/doctrine/-/doctrine-0.7.2.tgz",
17800 "integrity": "sha1-fLhgNZujvpDgQLJrcpzkv6ZUxSM=", 17808 "integrity": "sha1-fLhgNZujvpDgQLJrcpzkv6ZUxSM=",
17801 "dev": true, 17809 "dev": true,
17802 "requires": { 17810 "requires": {
@@ -17819,7 +17827,7 @@
17819 "tslib": { 17827 "tslib": {
17820 "version": "1.9.0", 17828 "version": "1.9.0",
17821 "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.9.0.tgz", 17829 "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.9.0.tgz",
17822 "integrity": "sha512-f/qGG2tUkrISBlQZEjEqoZ3B2+npJjIf04H1wuAv9iA8i04Icp+61KRXxFdha22670NJopsZCIjhC3SnjPRKrQ==", 17830 "integrity": "sha1-43qG/ajLuvI6BX9HPJ9Nxk5fwug=",
17823 "dev": true 17831 "dev": true
17824 }, 17832 },
17825 "tsutils": { 17833 "tsutils": {
@@ -17836,7 +17844,7 @@
17836 "tslint-microsoft-contrib": { 17844 "tslint-microsoft-contrib": {
17837 "version": "5.2.1", 17845 "version": "5.2.1",
17838 "resolved": "https://registry.npmjs.org/tslint-microsoft-contrib/-/tslint-microsoft-contrib-5.2.1.tgz", 17846 "resolved": "https://registry.npmjs.org/tslint-microsoft-contrib/-/tslint-microsoft-contrib-5.2.1.tgz",
17839 "integrity": "sha512-PDYjvpo0gN9IfMULwKk0KpVOPMhU6cNoT9VwCOLeDl/QS8v8W2yspRpFFuUS7/c5EIH/n8ApMi8TxJAz1tfFUA==", 17847 "integrity": "sha1-pihoOfgA4lkdBB6igAx3SHhErYE=",
17840 "dev": true, 17848 "dev": true,
17841 "requires": { 17849 "requires": {
17842 "tsutils": "^2.27.2 <2.29.0" 17850 "tsutils": "^2.27.2 <2.29.0"
@@ -17845,7 +17853,7 @@
17845 "tsutils": { 17853 "tsutils": {
17846 "version": "2.28.0", 17854 "version": "2.28.0",
17847 "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-2.28.0.tgz", 17855 "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-2.28.0.tgz",
17848 "integrity": "sha512-bh5nAtW0tuhvOJnx1GLRn5ScraRLICGyJV5wJhtRWOLsxW70Kk5tZtpK3O/hW6LDnqKS9mlUMPZj9fEMJ0gxqA==", 17856 "integrity": "sha1-a9ceFggo+dAZtvToRHQiKPhRaaE=",
17849 "dev": true, 17857 "dev": true,
17850 "requires": { 17858 "requires": {
17851 "tslib": "^1.8.1" 17859 "tslib": "^1.8.1"
@@ -17856,7 +17864,7 @@
17856 "tsutils": { 17864 "tsutils": {
17857 "version": "2.29.0", 17865 "version": "2.29.0",
17858 "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-2.29.0.tgz", 17866 "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-2.29.0.tgz",
17859 "integrity": "sha512-g5JVHCIJwzfISaXpXE1qvNalca5Jwob6FjI4AoPlqMusJ6ftFE7IkkFoMhVLRgK+4Kx3gkzb8UZK5t5yTTvEmA==", 17867 "integrity": "sha1-MrSIUBRnrL7dS4VJhnOggSrKC5k=",
17860 "dev": true, 17868 "dev": true,
17861 "requires": { 17869 "requires": {
17862 "tslib": "^1.8.1" 17870 "tslib": "^1.8.1"
@@ -17864,7 +17872,7 @@
17864 }, 17872 },
17865 "tty-browserify": { 17873 "tty-browserify": {
17866 "version": "0.0.0", 17874 "version": "0.0.0",
17867 "resolved": "https://registry.npmjs.org/tty-browserify/-/tty-browserify-0.0.0.tgz", 17875 "resolved": "http://registry.npmjs.org/tty-browserify/-/tty-browserify-0.0.0.tgz",
17868 "integrity": "sha1-oVe6QC2iTpv5V/mqadUk7tQpAaY=", 17876 "integrity": "sha1-oVe6QC2iTpv5V/mqadUk7tQpAaY=",
17869 "dev": true 17877 "dev": true
17870 }, 17878 },
@@ -17911,7 +17919,7 @@
17911 "typescript": { 17919 "typescript": {
17912 "version": "3.2.2", 17920 "version": "3.2.2",
17913 "resolved": "https://registry.npmjs.org/typescript/-/typescript-3.2.2.tgz", 17921 "resolved": "https://registry.npmjs.org/typescript/-/typescript-3.2.2.tgz",
17914 "integrity": "sha512-VCj5UiSyHBjwfYacmDuc/NOk4QQixbE+Wn7MFJuS0nRuPQbof132Pw4u53dm264O8LPc2MVsc7RJNml5szurkg==", 17922 "integrity": "sha1-/oEBxGqhI/g1NSPr3PVzDCrkk+U=",
17915 "dev": true 17923 "dev": true
17916 }, 17924 },
17917 "ua-parser-js": { 17925 "ua-parser-js": {
@@ -18050,7 +18058,7 @@
18050 "unique-filename": { 18058 "unique-filename": {
18051 "version": "1.1.1", 18059 "version": "1.1.1",
18052 "resolved": "https://registry.npmjs.org/unique-filename/-/unique-filename-1.1.1.tgz", 18060 "resolved": "https://registry.npmjs.org/unique-filename/-/unique-filename-1.1.1.tgz",
18053 "integrity": "sha512-Vmp0jIp2ln35UTXuryvjzkjGdRyf9b2lTXuSYUiPmzRcl3FDtYqAwOnTJkAngD9SWhnoJzDbTKwaOrZ+STtxNQ==", 18061 "integrity": "sha1-HWl2k2mtoFgxA6HmrodoG1ZXMjA=",
18054 "dev": true, 18062 "dev": true,
18055 "requires": { 18063 "requires": {
18056 "unique-slug": "^2.0.0" 18064 "unique-slug": "^2.0.0"
@@ -18059,7 +18067,7 @@
18059 "unique-slug": { 18067 "unique-slug": {
18060 "version": "2.0.1", 18068 "version": "2.0.1",
18061 "resolved": "https://registry.npmjs.org/unique-slug/-/unique-slug-2.0.1.tgz", 18069 "resolved": "https://registry.npmjs.org/unique-slug/-/unique-slug-2.0.1.tgz",
18062 "integrity": "sha512-n9cU6+gITaVu7VGj1Z8feKMmfAjEAQGhwD9fE3zvpRRa0wEIx8ODYkVGfSc94M2OX00tUFV8wH3zYbm1I8mxFg==", 18070 "integrity": "sha1-Xp7cbRzo+yZNsYpQfvm9hURFHKY=",
18063 "dev": true, 18071 "dev": true,
18064 "requires": { 18072 "requires": {
18065 "imurmurhash": "^0.1.4" 18073 "imurmurhash": "^0.1.4"
@@ -18504,7 +18512,7 @@
18504 }, 18512 },
18505 "vm-browserify": { 18513 "vm-browserify": {
18506 "version": "0.0.4", 18514 "version": "0.0.4",
18507 "resolved": "https://registry.npmjs.org/vm-browserify/-/vm-browserify-0.0.4.tgz", 18515 "resolved": "http://registry.npmjs.org/vm-browserify/-/vm-browserify-0.0.4.tgz",
18508 "integrity": "sha1-XX6kW7755Kb/ZflUOOCofDV9WnM=", 18516 "integrity": "sha1-XX6kW7755Kb/ZflUOOCofDV9WnM=",
18509 "dev": true, 18517 "dev": true,
18510 "requires": { 18518 "requires": {
@@ -18609,7 +18617,7 @@
18609 "webidl-conversions": { 18617 "webidl-conversions": {
18610 "version": "4.0.2", 18618 "version": "4.0.2",
18611 "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-4.0.2.tgz", 18619 "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-4.0.2.tgz",
18612 "integrity": "sha512-YQ+BmxuTgd6UXZW3+ICGfyqRyHXVlD5GtQr5+qjiNW7bF0cqrzX500HVXPBOvgXb5YnzDd+h0zqyv61KUD7+Sg==", 18620 "integrity": "sha1-qFWYCx8LazWbodXZ+zmulB+qY60=",
18613 "dev": true 18621 "dev": true
18614 }, 18622 },
18615 "webpack": { 18623 "webpack": {
@@ -19100,7 +19108,7 @@
19100 }, 19108 },
19101 "wrap-ansi": { 19109 "wrap-ansi": {
19102 "version": "2.1.0", 19110 "version": "2.1.0",
19103 "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-2.1.0.tgz", 19111 "resolved": "http://registry.npmjs.org/wrap-ansi/-/wrap-ansi-2.1.0.tgz",
19104 "integrity": "sha1-2Pw9KE3QV5T+hJc8rs3Rz4JP3YU=", 19112 "integrity": "sha1-2Pw9KE3QV5T+hJc8rs3Rz4JP3YU=",
19105 "dev": true, 19113 "dev": true,
19106 "requires": { 19114 "requires": {
@@ -19208,7 +19216,7 @@
19208 "write-pkg": { 19216 "write-pkg": {
19209 "version": "3.2.0", 19217 "version": "3.2.0",
19210 "resolved": "https://registry.npmjs.org/write-pkg/-/write-pkg-3.2.0.tgz", 19218 "resolved": "https://registry.npmjs.org/write-pkg/-/write-pkg-3.2.0.tgz",
19211 "integrity": "sha512-tX2ifZ0YqEFOF1wjRW2Pk93NLsj02+n1UP5RvO6rCs0K6R2g1padvf006cY74PQJKMGS2r42NK7FD0dG6Y6paw==", 19219 "integrity": "sha1-DheP6Xgg04mokovHlTXb5ows/yE=",
19212 "dev": true, 19220 "dev": true,
19213 "requires": { 19221 "requires": {
19214 "sort-keys": "^2.0.0", 19222 "sort-keys": "^2.0.0",
@@ -19250,7 +19258,7 @@
19250 }, 19258 },
19251 "xmlbuilder": { 19259 "xmlbuilder": {
19252 "version": "9.0.7", 19260 "version": "9.0.7",
19253 "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-9.0.7.tgz", 19261 "resolved": "http://registry.npmjs.org/xmlbuilder/-/xmlbuilder-9.0.7.tgz",
19254 "integrity": "sha1-Ey7mPS7FVlxVfiD0wi35rKaGsQ0=", 19262 "integrity": "sha1-Ey7mPS7FVlxVfiD0wi35rKaGsQ0=",
19255 "dev": true 19263 "dev": true
19256 }, 19264 },
diff --git a/packages/forms/src/input/index.tsx b/packages/forms/src/input/index.tsx
index 478738cad..cc3709b1a 100644
--- a/packages/forms/src/input/index.tsx
+++ b/packages/forms/src/input/index.tsx
@@ -25,6 +25,7 @@ interface IProps extends React.InputHTMLAttributes<HTMLInputElement>, IFormField
25 showPasswordToggle?: boolean; 25 showPasswordToggle?: boolean;
26 data: IData; 26 data: IData;
27 inputClassName?: string; 27 inputClassName?: string;
28 onEnterKey?: Function;
28} 29}
29 30
30interface IState { 31interface IState {
@@ -81,6 +82,13 @@ class InputComponent extends Component<IProps, IState> {
81 } 82 }
82 } 83 }
83 84
85 onInputKeyPress(e: React.KeyboardEvent) {
86 if (e.key === "Enter") {
87 const { onEnterKey } = this.props;
88 onEnterKey && onEnterKey();
89 }
90 }
91
84 render() { 92 render() {
85 const { 93 const {
86 classes, 94 classes,
@@ -101,6 +109,7 @@ class InputComponent extends Component<IProps, IState> {
101 placeholder, 109 placeholder,
102 spellCheck, 110 spellCheck,
103 onBlur, 111 onBlur,
112 onEnterKey,
104 onFocus, 113 onFocus,
105 } = this.props; 114 } = this.props;
106 115
@@ -147,6 +156,7 @@ class InputComponent extends Component<IProps, IState> {
147 onFocus={onFocus} 156 onFocus={onFocus}
148 onBlur={onBlur} 157 onBlur={onBlur}
149 disabled={disabled} 158 disabled={disabled}
159 onKeyPress={this.onInputKeyPress.bind(this)}
150 /> 160 />
151 {suffix && ( 161 {suffix && (
152 <span className={classes.suffix}> 162 <span className={classes.suffix}>
diff --git a/src/actions/index.js b/src/actions/index.js
index 59acabb0b..00f843cd6 100644
--- a/src/actions/index.js
+++ b/src/actions/index.js
@@ -11,6 +11,7 @@ import payment from './payment';
11import news from './news'; 11import news from './news';
12import settings from './settings'; 12import settings from './settings';
13import requests from './requests'; 13import requests from './requests';
14import workspaces from '../features/workspaces/actions';
14 15
15const actions = Object.assign({}, { 16const actions = Object.assign({}, {
16 service, 17 service,
@@ -25,4 +26,7 @@ const actions = Object.assign({}, {
25 requests, 26 requests,
26}); 27});
27 28
28export default defineActions(actions, PropTypes.checkPropTypes); 29export default Object.assign(
30 defineActions(actions, PropTypes.checkPropTypes),
31 { workspaces },
32);
diff --git a/src/actions/lib/actions.js b/src/actions/lib/actions.js
index 499018d70..6571e9441 100644
--- a/src/actions/lib/actions.js
+++ b/src/actions/lib/actions.js
@@ -1,18 +1,23 @@
1export const createActionsFromDefinitions = (actionDefinitions, validate) => {
2 const actions = {};
3 Object.keys(actionDefinitions).forEach((actionName) => {
4 const action = (params) => {
5 const schema = actionDefinitions[actionName];
6 validate(schema, params, actionName);
7 action.notify(params);
8 };
9 actions[actionName] = action;
10 action.listeners = [];
11 action.listen = listener => action.listeners.push(listener);
12 action.notify = params => action.listeners.forEach(listener => listener(params));
13 });
14 return actions;
15};
16
1export default (definitions, validate) => { 17export default (definitions, validate) => {
2 const newActions = {}; 18 const newActions = {};
3 Object.keys(definitions).forEach((scopeName) => { 19 Object.keys(definitions).forEach((scopeName) => {
4 newActions[scopeName] = {}; 20 newActions[scopeName] = createActionsFromDefinitions(definitions[scopeName], validate);
5 Object.keys(definitions[scopeName]).forEach((actionName) => {
6 const action = (params) => {
7 const schema = definitions[scopeName][actionName];
8 validate(schema, params, actionName);
9 action.notify(params);
10 };
11 newActions[scopeName][actionName] = action;
12 action.listeners = [];
13 action.listen = listener => action.listeners.push(listener);
14 action.notify = params => action.listeners.forEach(listener => listener(params));
15 });
16 }); 21 });
17 return newActions; 22 return newActions;
18}; 23};
diff --git a/src/api/utils/auth.js b/src/api/utils/auth.js
new file mode 100644
index 000000000..d469853a5
--- /dev/null
+++ b/src/api/utils/auth.js
@@ -0,0 +1,28 @@
1import { remote } from 'electron';
2import localStorage from 'mobx-localstorage';
3
4const { app } = remote;
5
6export const prepareAuthRequest = (options, auth = true) => {
7 const request = Object.assign(options, {
8 mode: 'cors',
9 headers: Object.assign({
10 'Content-Type': 'application/json',
11 'X-Franz-Source': 'desktop',
12 'X-Franz-Version': app.getVersion(),
13 'X-Franz-platform': process.platform,
14 'X-Franz-Timezone-Offset': new Date().getTimezoneOffset(),
15 'X-Franz-System-Locale': app.getLocale(),
16 }, options.headers),
17 });
18
19 if (auth) {
20 request.headers.Authorization = `Bearer ${localStorage.getItem('authToken')}`;
21 }
22
23 return request;
24};
25
26export const sendAuthRequest = (url, options) => (
27 window.fetch(url, prepareAuthRequest(options))
28);
diff --git a/src/app.js b/src/app.js
index 6660feb46..d3b540f62 100644
--- a/src/app.js
+++ b/src/app.js
@@ -39,6 +39,8 @@ import PricingScreen from './containers/auth/PricingScreen';
39import InviteScreen from './containers/auth/InviteScreen'; 39import InviteScreen from './containers/auth/InviteScreen';
40import AuthLayoutContainer from './containers/auth/AuthLayoutContainer'; 40import AuthLayoutContainer from './containers/auth/AuthLayoutContainer';
41import SubscriptionPopupScreen from './containers/subscription/SubscriptionPopupScreen'; 41import SubscriptionPopupScreen from './containers/subscription/SubscriptionPopupScreen';
42import WorkspacesScreen from './features/workspaces/containers/WorkspacesScreen';
43import EditWorkspaceScreen from './features/workspaces/containers/EditWorkspaceScreen';
42 44
43// Add Polyfills 45// Add Polyfills
44smoothScroll.polyfill(); 46smoothScroll.polyfill();
@@ -75,6 +77,8 @@ window.addEventListener('load', () => {
75 <Route path="/settings/recipes/:filter" component={RecipesScreen} /> 77 <Route path="/settings/recipes/:filter" component={RecipesScreen} />
76 <Route path="/settings/services" component={ServicesScreen} /> 78 <Route path="/settings/services" component={ServicesScreen} />
77 <Route path="/settings/services/:action/:id" component={EditServiceScreen} /> 79 <Route path="/settings/services/:action/:id" component={EditServiceScreen} />
80 <Route path="/settings/workspaces" component={WorkspacesScreen} />
81 <Route path="/settings/workspaces/:action/:id" component={EditWorkspaceScreen} />
78 <Route path="/settings/user" component={AccountScreen} /> 82 <Route path="/settings/user" component={AccountScreen} />
79 <Route path="/settings/user/edit" component={EditUserScreen} /> 83 <Route path="/settings/user/edit" component={EditUserScreen} />
80 <Route path="/settings/app" component={EditSettingsScreen} /> 84 <Route path="/settings/app" component={EditSettingsScreen} />
diff --git a/src/components/layout/Sidebar.js b/src/components/layout/Sidebar.js
index 609a3b604..fcc5b0001 100644
--- a/src/components/layout/Sidebar.js
+++ b/src/components/layout/Sidebar.js
@@ -31,7 +31,7 @@ export default @observer class Sidebar extends Component {
31 openSettings: PropTypes.func.isRequired, 31 openSettings: PropTypes.func.isRequired,
32 toggleMuteApp: PropTypes.func.isRequired, 32 toggleMuteApp: PropTypes.func.isRequired,
33 isAppMuted: PropTypes.bool.isRequired, 33 isAppMuted: PropTypes.bool.isRequired,
34 } 34 };
35 35
36 static contextTypes = { 36 static contextTypes = {
37 intl: intlShape, 37 intl: intlShape,
diff --git a/src/components/services/tabs/Tabbar.js b/src/components/services/tabs/Tabbar.js
index dd5c2140f..5e8260ad0 100644
--- a/src/components/services/tabs/Tabbar.js
+++ b/src/components/services/tabs/Tabbar.js
@@ -19,7 +19,7 @@ export default @observer class TabBar extends Component {
19 updateService: PropTypes.func.isRequired, 19 updateService: PropTypes.func.isRequired,
20 showMessageBadgeWhenMutedSetting: PropTypes.bool.isRequired, 20 showMessageBadgeWhenMutedSetting: PropTypes.bool.isRequired,
21 showMessageBadgesEvenWhenMuted: PropTypes.bool.isRequired, 21 showMessageBadgesEvenWhenMuted: PropTypes.bool.isRequired,
22 } 22 };
23 23
24 onSortEnd = ({ oldIndex, newIndex }) => { 24 onSortEnd = ({ oldIndex, newIndex }) => {
25 const { 25 const {
@@ -45,7 +45,7 @@ export default @observer class TabBar extends Component {
45 redirect: false, 45 redirect: false,
46 }); 46 });
47 } 47 }
48 } 48 };
49 49
50 disableService({ serviceId }) { 50 disableService({ serviceId }) {
51 this.toggleService({ serviceId, isEnabled: false }); 51 this.toggleService({ serviceId, isEnabled: false });
diff --git a/src/components/settings/navigation/SettingsNavigation.js b/src/components/settings/navigation/SettingsNavigation.js
index 953f702f8..4a80bb126 100644
--- a/src/components/settings/navigation/SettingsNavigation.js
+++ b/src/components/settings/navigation/SettingsNavigation.js
@@ -14,6 +14,10 @@ const messages = defineMessages({
14 id: 'settings.navigation.yourServices', 14 id: 'settings.navigation.yourServices',
15 defaultMessage: '!!!Your services', 15 defaultMessage: '!!!Your services',
16 }, 16 },
17 yourWorkspaces: {
18 id: 'settings.navigation.yourWorkspaces',
19 defaultMessage: '!!!Your workspaces',
20 },
17 account: { 21 account: {
18 id: 'settings.navigation.account', 22 id: 'settings.navigation.account',
19 defaultMessage: '!!!Account', 23 defaultMessage: '!!!Account',
@@ -64,6 +68,14 @@ export default @inject('stores') @observer class SettingsNavigation extends Comp
64 <span className="badge">{serviceCount}</span> 68 <span className="badge">{serviceCount}</span>
65 </Link> 69 </Link>
66 <Link 70 <Link
71 to="/settings/workspaces"
72 className="settings-navigation__link"
73 activeClassName="is-active"
74 >
75 {intl.formatMessage(messages.yourWorkspaces)}
76 {' '}
77 </Link>
78 <Link
67 to="/settings/user" 79 to="/settings/user"
68 className="settings-navigation__link" 80 className="settings-navigation__link"
69 activeClassName="is-active" 81 activeClassName="is-active"
diff --git a/src/config.js b/src/config.js
index a782ad667..30a5a5cc0 100644
--- a/src/config.js
+++ b/src/config.js
@@ -41,6 +41,8 @@ export const DEFAULT_FEATURES_CONFIG = {
41 }, 41 },
42 isServiceProxyEnabled: false, 42 isServiceProxyEnabled: false,
43 isServiceProxyPremiumFeature: true, 43 isServiceProxyPremiumFeature: true,
44 isWorkspacePremiumFeature: true,
45 isWorkspaceEnabled: true,
44}; 46};
45 47
46export const DEFAULT_WINDOW_OPTIONS = { 48export const DEFAULT_WINDOW_OPTIONS = {
diff --git a/src/environment.js b/src/environment.js
index 73b1c7ab2..d67fd6adb 100644
--- a/src/environment.js
+++ b/src/environment.js
@@ -28,3 +28,4 @@ if (!isDevMode || (isDevMode && useLiveAPI)) {
28} 28}
29 29
30export const API = api; 30export const API = api;
31export const API_VERSION = 'v1';
diff --git a/src/features/delayApp/Component.js b/src/features/delayApp/Component.js
index ff84510e8..ff0f1f2f8 100644
--- a/src/features/delayApp/Component.js
+++ b/src/features/delayApp/Component.js
@@ -38,7 +38,7 @@ export default @inject('actions') @injectSheet(styles) @observer class DelayApp
38 38
39 state = { 39 state = {
40 countdown: config.delayDuration, 40 countdown: config.delayDuration,
41 } 41 };
42 42
43 countdownInterval = null; 43 countdownInterval = null;
44 44
diff --git a/src/features/workspaces/actions.js b/src/features/workspaces/actions.js
new file mode 100644
index 000000000..25246de09
--- /dev/null
+++ b/src/features/workspaces/actions.js
@@ -0,0 +1,22 @@
1import PropTypes from 'prop-types';
2import Workspace from './models/Workspace';
3import { createActionsFromDefinitions } from '../../actions/lib/actions';
4
5export default createActionsFromDefinitions({
6 edit: {
7 workspace: PropTypes.instanceOf(Workspace).isRequired,
8 },
9 create: {
10 name: PropTypes.string.isRequired,
11 },
12 delete: {
13 workspace: PropTypes.instanceOf(Workspace).isRequired,
14 },
15 update: {
16 workspace: PropTypes.instanceOf(Workspace).isRequired,
17 },
18 activate: {
19 workspace: PropTypes.instanceOf(Workspace).isRequired,
20 },
21 deactivate: {},
22}, PropTypes.checkPropTypes);
diff --git a/src/features/workspaces/api.js b/src/features/workspaces/api.js
new file mode 100644
index 000000000..733cb5593
--- /dev/null
+++ b/src/features/workspaces/api.js
@@ -0,0 +1,39 @@
1import { pick } from 'lodash';
2import { sendAuthRequest } from '../../api/utils/auth';
3import { API, API_VERSION } from '../../environment';
4
5export default {
6 getUserWorkspaces: async () => {
7 const url = `${API}/${API_VERSION}/workspace`;
8 const request = await sendAuthRequest(url, { method: 'GET' });
9 if (!request.ok) throw request;
10 return request.json();
11 },
12
13 createWorkspace: async (name) => {
14 const url = `${API}/${API_VERSION}/workspace`;
15 const request = await sendAuthRequest(url, {
16 method: 'POST',
17 body: JSON.stringify({ name }),
18 });
19 if (!request.ok) throw request;
20 return request.json();
21 },
22
23 deleteWorkspace: async (workspace) => {
24 const url = `${API}/${API_VERSION}/workspace/${workspace.id}`;
25 const request = await sendAuthRequest(url, { method: 'DELETE' });
26 if (!request.ok) throw request;
27 return request.json();
28 },
29
30 updateWorkspace: async (workspace) => {
31 const url = `${API}/${API_VERSION}/workspace/${workspace.id}`;
32 const request = await sendAuthRequest(url, {
33 method: 'PUT',
34 body: JSON.stringify(pick(workspace, ['name', 'services'])),
35 });
36 if (!request.ok) throw request;
37 return request.json();
38 },
39};
diff --git a/src/features/workspaces/components/CreateWorkspaceForm.js b/src/features/workspaces/components/CreateWorkspaceForm.js
new file mode 100644
index 000000000..83f6e07f7
--- /dev/null
+++ b/src/features/workspaces/components/CreateWorkspaceForm.js
@@ -0,0 +1,93 @@
1import React, { Component } from 'react';
2import PropTypes from 'prop-types';
3import { observer } from 'mobx-react';
4import { defineMessages, intlShape } from 'react-intl';
5import { Input, Button } from '@meetfranz/forms';
6import injectSheet from 'react-jss';
7import Form from '../../../lib/Form';
8import { required } from '../../../helpers/validation-helpers';
9
10const messages = defineMessages({
11 submitButton: {
12 id: 'settings.workspace.add.form.submitButton',
13 defaultMessage: '!!!Save workspace',
14 },
15 name: {
16 id: 'settings.workspace.add.form.name',
17 defaultMessage: '!!!Name',
18 },
19});
20
21const styles = () => ({
22 form: {
23 display: 'flex',
24 },
25 input: {
26 flexGrow: 1,
27 marginRight: '10px',
28 },
29 submitButton: {
30 height: 'inherit',
31 marginTop: '3px',
32 },
33});
34
35@injectSheet(styles) @observer
36class CreateWorkspaceForm extends Component {
37 static contextTypes = {
38 intl: intlShape,
39 };
40
41 static propTypes = {
42 classes: PropTypes.object.isRequired,
43 onSubmit: PropTypes.func.isRequired,
44 };
45
46 form = (() => {
47 const { intl } = this.context;
48 return new Form({
49 fields: {
50 name: {
51 label: intl.formatMessage(messages.name),
52 placeholder: intl.formatMessage(messages.name),
53 value: '',
54 validators: [required],
55 },
56 },
57 });
58 })();
59
60 submitForm() {
61 const { form } = this;
62 form.submit({
63 onSuccess: async (f) => {
64 const { onSubmit } = this.props;
65 onSubmit(f.values());
66 },
67 });
68 }
69
70 render() {
71 const { intl } = this.context;
72 const { classes } = this.props;
73 const { form } = this;
74 return (
75 <div className={classes.form}>
76 <Input
77 className={classes.input}
78 {...form.$('name').bind()}
79 showLabel={false}
80 onEnterKey={this.submitForm.bind(this, form)}
81 />
82 <Button
83 className={classes.submitButton}
84 type="submit"
85 label={intl.formatMessage(messages.submitButton)}
86 onClick={this.submitForm.bind(this, form)}
87 />
88 </div>
89 );
90 }
91}
92
93export default CreateWorkspaceForm;
diff --git a/src/features/workspaces/components/EditWorkspaceForm.js b/src/features/workspaces/components/EditWorkspaceForm.js
new file mode 100644
index 000000000..48090f608
--- /dev/null
+++ b/src/features/workspaces/components/EditWorkspaceForm.js
@@ -0,0 +1,192 @@
1import React, { Component } from 'react';
2import PropTypes from 'prop-types';
3import { observer } from 'mobx-react';
4import { defineMessages, intlShape } from 'react-intl';
5import { Link } from 'react-router';
6import { Input, Button } from '@meetfranz/forms';
7import injectSheet from 'react-jss';
8
9import Workspace from '../models/Workspace';
10import Service from '../../../models/Service';
11import Form from '../../../lib/Form';
12import { required } from '../../../helpers/validation-helpers';
13import ServiceListItem from './ServiceListItem';
14
15const messages = defineMessages({
16 buttonDelete: {
17 id: 'settings.workspace.form.buttonDelete',
18 defaultMessage: '!!!Delete workspace',
19 },
20 buttonSave: {
21 id: 'settings.workspace.form.buttonSave',
22 defaultMessage: '!!!Save workspace',
23 },
24 name: {
25 id: 'settings.workspace.form.name',
26 defaultMessage: '!!!Name',
27 },
28 yourWorkspaces: {
29 id: 'settings.workspace.form.yourWorkspaces',
30 defaultMessage: '!!!Your workspaces',
31 },
32 servicesInWorkspaceHeadline: {
33 id: 'settings.workspace.form.servicesInWorkspaceHeadline',
34 defaultMessage: '!!!Services in this Workspace',
35 },
36});
37
38const styles = () => ({
39 nameInput: {
40 height: 'auto',
41 },
42 serviceList: {
43 height: 'auto',
44 },
45});
46
47@injectSheet(styles) @observer
48class EditWorkspaceForm extends Component {
49 static contextTypes = {
50 intl: intlShape,
51 };
52
53 static propTypes = {
54 classes: PropTypes.object.isRequired,
55 isDeleting: PropTypes.bool.isRequired,
56 isSaving: PropTypes.bool.isRequired,
57 onDelete: PropTypes.func.isRequired,
58 onSave: PropTypes.func.isRequired,
59 services: PropTypes.arrayOf(PropTypes.instanceOf(Service)).isRequired,
60 workspace: PropTypes.instanceOf(Workspace).isRequired,
61 };
62
63 form = this.prepareWorkspaceForm(this.props.workspace);
64
65 componentWillReceiveProps(nextProps) {
66 const { workspace } = this.props;
67 if (workspace.id !== nextProps.workspace.id) {
68 this.form = this.prepareWorkspaceForm(nextProps.workspace);
69 }
70 }
71
72 prepareWorkspaceForm(workspace) {
73 const { intl } = this.context;
74 return new Form({
75 fields: {
76 name: {
77 label: intl.formatMessage(messages.name),
78 placeholder: intl.formatMessage(messages.name),
79 value: workspace.name,
80 validators: [required],
81 },
82 services: {
83 value: workspace.services.slice(),
84 },
85 },
86 });
87 }
88
89 submitForm(form) {
90 form.submit({
91 onSuccess: async (f) => {
92 const { onSave } = this.props;
93 const values = f.values();
94 onSave(values);
95 },
96 onError: async () => {},
97 });
98 }
99
100 toggleService(service) {
101 const servicesField = this.form.$('services');
102 const serviceIds = servicesField.value;
103 if (serviceIds.includes(service.id)) {
104 serviceIds.splice(serviceIds.indexOf(service.id), 1);
105 } else {
106 serviceIds.push(service.id);
107 }
108 servicesField.set(serviceIds);
109 }
110
111 render() {
112 const { intl } = this.context;
113 const {
114 classes,
115 isDeleting,
116 isSaving,
117 onDelete,
118 workspace,
119 services,
120 } = this.props;
121 const { form } = this;
122 const workspaceServices = form.$('services').value;
123 return (
124 <div className="settings__main">
125 <div className="settings__header">
126 <span className="settings__header-item">
127 <Link to="/settings/workspaces">
128 {intl.formatMessage(messages.yourWorkspaces)}
129 </Link>
130 </span>
131 <span className="separator" />
132 <span className="settings__header-item">
133 {workspace.name}
134 </span>
135 </div>
136 <div className="settings__body">
137 <div className={classes.nameInput}>
138 <Input {...form.$('name').bind()} />
139 </div>
140 <h2>{intl.formatMessage(messages.servicesInWorkspaceHeadline)}</h2>
141 <div className={classes.serviceList}>
142 {services.map(s => (
143 <ServiceListItem
144 key={s.id}
145 service={s}
146 isInWorkspace={workspaceServices.includes(s.id)}
147 onToggle={() => this.toggleService(s)}
148 />
149 ))}
150 </div>
151 </div>
152 <div className="settings__controls">
153 {/* ===== Delete Button ===== */}
154 {isDeleting ? (
155 <Button
156 label={intl.formatMessage(messages.buttonDelete)}
157 loaded={false}
158 buttonType="secondary"
159 className="settings__delete-button"
160 disabled
161 />
162 ) : (
163 <Button
164 buttonType="danger"
165 label={intl.formatMessage(messages.buttonDelete)}
166 className="settings__delete-button"
167 onClick={onDelete}
168 />
169 )}
170 {/* ===== Save Button ===== */}
171 {isSaving ? (
172 <Button
173 type="submit"
174 label={intl.formatMessage(messages.buttonSave)}
175 loaded={!isSaving}
176 buttonType="secondary"
177 disabled
178 />
179 ) : (
180 <Button
181 type="submit"
182 label={intl.formatMessage(messages.buttonSave)}
183 onClick={this.submitForm.bind(this, form)}
184 />
185 )}
186 </div>
187 </div>
188 );
189 }
190}
191
192export default EditWorkspaceForm;
diff --git a/src/features/workspaces/components/ServiceListItem.js b/src/features/workspaces/components/ServiceListItem.js
new file mode 100644
index 000000000..146cc5a36
--- /dev/null
+++ b/src/features/workspaces/components/ServiceListItem.js
@@ -0,0 +1,48 @@
1import React, { Component } from 'react';
2import PropTypes from 'prop-types';
3import { observer } from 'mobx-react';
4import injectSheet from 'react-jss';
5import { Toggle } from '@meetfranz/forms';
6
7import Service from '../../../models/Service';
8
9const styles = () => ({
10 service: {
11 height: 'auto',
12 display: 'flex',
13 },
14 name: {
15 marginTop: '4px',
16 },
17});
18
19@injectSheet(styles) @observer
20class ServiceListItem extends Component {
21 static propTypes = {
22 classes: PropTypes.object.isRequired,
23 isInWorkspace: PropTypes.bool.isRequired,
24 onToggle: PropTypes.func.isRequired,
25 service: PropTypes.instanceOf(Service).isRequired,
26 };
27
28 render() {
29 const {
30 classes,
31 isInWorkspace,
32 onToggle,
33 service,
34 } = this.props;
35
36 return (
37 <div className={classes.service}>
38 <Toggle
39 checked={isInWorkspace}
40 onChange={onToggle}
41 label={service.name}
42 />
43 </div>
44 );
45 }
46}
47
48export default ServiceListItem;
diff --git a/src/features/workspaces/components/WorkspaceItem.js b/src/features/workspaces/components/WorkspaceItem.js
new file mode 100644
index 000000000..b2c2a4830
--- /dev/null
+++ b/src/features/workspaces/components/WorkspaceItem.js
@@ -0,0 +1,42 @@
1import React, { Component } from 'react';
2import PropTypes from 'prop-types';
3import { intlShape } from 'react-intl';
4import { observer } from 'mobx-react';
5import classnames from 'classnames';
6import Workspace from '../models/Workspace';
7
8// const messages = defineMessages({});
9
10@observer
11class WorkspaceItem extends Component {
12 static propTypes = {
13 workspace: PropTypes.instanceOf(Workspace).isRequired,
14 onItemClick: PropTypes.func.isRequired,
15 };
16
17 static contextTypes = {
18 intl: intlShape,
19 };
20
21 render() {
22 const { workspace, onItemClick } = this.props;
23 // const { intl } = this.context;
24
25 return (
26 <tr
27 className={classnames({
28 'workspace-table__row': true,
29 })}
30 >
31 <td
32 className="workspace-table__column-name"
33 onClick={() => onItemClick(workspace)}
34 >
35 {workspace.name}
36 </td>
37 </tr>
38 );
39 }
40}
41
42export default WorkspaceItem;
diff --git a/src/features/workspaces/components/WorkspacesDashboard.js b/src/features/workspaces/components/WorkspacesDashboard.js
new file mode 100644
index 000000000..917807302
--- /dev/null
+++ b/src/features/workspaces/components/WorkspacesDashboard.js
@@ -0,0 +1,85 @@
1import React, { Component } from 'react';
2import PropTypes from 'prop-types';
3import { observer, PropTypes as MobxPropTypes } from 'mobx-react';
4import { defineMessages, intlShape } from 'react-intl';
5import injectSheet from 'react-jss';
6
7import Loader from '../../../components/ui/Loader';
8import WorkspaceItem from './WorkspaceItem';
9import CreateWorkspaceForm from './CreateWorkspaceForm';
10
11const messages = defineMessages({
12 headline: {
13 id: 'settings.workspaces.headline',
14 defaultMessage: '!!!Your workspaces',
15 },
16 noServicesAdded: {
17 id: 'settings.workspaces.noWorkspacesAdded',
18 defaultMessage: '!!!You haven\'t added any workspaces yet.',
19 },
20});
21
22const styles = () => ({
23 createForm: {
24 height: 'auto',
25 marginBottom: '20px',
26 },
27});
28
29@observer @injectSheet(styles)
30class WorkspacesDashboard extends Component {
31 static propTypes = {
32 classes: PropTypes.object.isRequired,
33 isLoading: PropTypes.bool.isRequired,
34 onCreateWorkspaceSubmit: PropTypes.func.isRequired,
35 onWorkspaceClick: PropTypes.func.isRequired,
36 workspaces: MobxPropTypes.arrayOrObservableArray.isRequired,
37 };
38
39 static contextTypes = {
40 intl: intlShape,
41 };
42
43 render() {
44 const {
45 workspaces,
46 isLoading,
47 onCreateWorkspaceSubmit,
48 onWorkspaceClick,
49 classes,
50 } = this.props;
51 const { intl } = this.context;
52
53 return (
54 <div className="settings__main">
55 <div className="settings__header">
56 <h1>{intl.formatMessage(messages.headline)}</h1>
57 </div>
58 <div className="settings__body">
59 <div className={classes.body}>
60 <div className={classes.createForm}>
61 <CreateWorkspaceForm onSubmit={onCreateWorkspaceSubmit} />
62 </div>
63 {isLoading ? (
64 <Loader />
65 ) : (
66 <table className="workspace-table">
67 <tbody>
68 {workspaces.map(workspace => (
69 <WorkspaceItem
70 key={workspace.id}
71 workspace={workspace}
72 onItemClick={w => onWorkspaceClick(w)}
73 />
74 ))}
75 </tbody>
76 </table>
77 )}
78 </div>
79 </div>
80 </div>
81 );
82 }
83}
84
85export default WorkspacesDashboard;
diff --git a/src/features/workspaces/containers/EditWorkspaceScreen.js b/src/features/workspaces/containers/EditWorkspaceScreen.js
new file mode 100644
index 000000000..1b13bc2d4
--- /dev/null
+++ b/src/features/workspaces/containers/EditWorkspaceScreen.js
@@ -0,0 +1,59 @@
1import React, { Component } from 'react';
2import { inject, observer } from 'mobx-react';
3import PropTypes from 'prop-types';
4
5import ErrorBoundary from '../../../components/util/ErrorBoundary';
6import EditWorkspaceForm from '../components/EditWorkspaceForm';
7import { workspacesState } from '../state';
8import ServicesStore from '../../../stores/ServicesStore';
9import Workspace from '../models/Workspace';
10
11@inject('stores', 'actions') @observer
12class EditWorkspaceScreen extends Component {
13 static propTypes = {
14 actions: PropTypes.shape({
15 workspace: PropTypes.shape({
16 delete: PropTypes.func.isRequired,
17 }),
18 }).isRequired,
19 stores: PropTypes.shape({
20 services: PropTypes.instanceOf(ServicesStore).isRequired,
21 }).isRequired,
22 };
23
24 onDelete = () => {
25 const { workspaceBeingEdited } = workspacesState;
26 const { actions } = this.props;
27 if (!workspaceBeingEdited) return null;
28 actions.workspaces.delete({ workspace: workspaceBeingEdited });
29 };
30
31 onSave = (values) => {
32 const { workspaceBeingEdited } = workspacesState;
33 const { actions } = this.props;
34 const workspace = new Workspace(
35 Object.assign({}, workspaceBeingEdited, values),
36 );
37 actions.workspaces.update({ workspace });
38 };
39
40 render() {
41 const { workspaceBeingEdited } = workspacesState;
42 const { stores } = this.props;
43 if (!workspaceBeingEdited) return null;
44 return (
45 <ErrorBoundary>
46 <EditWorkspaceForm
47 workspace={workspaceBeingEdited}
48 services={stores.services.all}
49 onDelete={this.onDelete}
50 onSave={this.onSave}
51 isDeleting={false}
52 isSaving={false}
53 />
54 </ErrorBoundary>
55 );
56 }
57}
58
59export default EditWorkspaceScreen;
diff --git a/src/features/workspaces/containers/WorkspacesScreen.js b/src/features/workspaces/containers/WorkspacesScreen.js
new file mode 100644
index 000000000..94e714255
--- /dev/null
+++ b/src/features/workspaces/containers/WorkspacesScreen.js
@@ -0,0 +1,33 @@
1import React, { Component } from 'react';
2import { inject, observer } from 'mobx-react';
3import PropTypes from 'prop-types';
4import { workspacesState } from '../state';
5import WorkspacesDashboard from '../components/WorkspacesDashboard';
6import ErrorBoundary from '../../../components/util/ErrorBoundary';
7
8@inject('actions') @observer
9class WorkspacesScreen extends Component {
10 static propTypes = {
11 actions: PropTypes.shape({
12 workspace: PropTypes.shape({
13 edit: PropTypes.func.isRequired,
14 }),
15 }).isRequired,
16 };
17
18 render() {
19 const { actions } = this.props;
20 return (
21 <ErrorBoundary>
22 <WorkspacesDashboard
23 workspaces={workspacesState.workspaces}
24 isLoading={workspacesState.isLoading}
25 onCreateWorkspaceSubmit={data => actions.workspaces.create(data)}
26 onWorkspaceClick={w => actions.workspaces.edit({ workspace: w })}
27 />
28 </ErrorBoundary>
29 );
30 }
31}
32
33export default WorkspacesScreen;
diff --git a/src/features/workspaces/index.js b/src/features/workspaces/index.js
new file mode 100644
index 000000000..8091f49fc
--- /dev/null
+++ b/src/features/workspaces/index.js
@@ -0,0 +1,68 @@
1import { reaction, runInAction } from 'mobx';
2import WorkspacesStore from './store';
3import api from './api';
4import { workspacesState, resetState } from './state';
5
6const debug = require('debug')('Franz:feature:workspaces');
7
8let store = null;
9
10export const filterServicesByActiveWorkspace = (services) => {
11 const { isFeatureActive, activeWorkspace } = workspacesState;
12 if (isFeatureActive && activeWorkspace) {
13 return services.filter(s => activeWorkspace.services.includes(s.id));
14 }
15 return services;
16};
17
18export const getActiveWorkspaceServices = (services) => {
19 return filterServicesByActiveWorkspace(services);
20};
21
22export default function initWorkspaces(stores, actions) {
23 const { features, user } = stores;
24
25 // Toggle workspace feature
26 reaction(
27 () => (
28 features.features.isWorkspaceEnabled && (
29 !features.features.isWorkspacePremiumFeature || user.data.isPremium
30 )
31 ),
32 (isEnabled) => {
33 if (isEnabled) {
34 debug('Initializing `workspaces` feature');
35 store = new WorkspacesStore(stores, api, actions, workspacesState);
36 store.initialize();
37 runInAction(() => { workspacesState.isFeatureActive = true; });
38 } else if (store) {
39 debug('Disabling `workspaces` feature');
40 runInAction(() => { workspacesState.isFeatureActive = false; });
41 store.teardown();
42 store = null;
43 resetState(); // Reset state to default
44 }
45 },
46 {
47 fireImmediately: true,
48 },
49 );
50
51 // Update active service on workspace switches
52 reaction(() => ({
53 isFeatureActive: workspacesState.isFeatureActive,
54 activeWorkspace: workspacesState.activeWorkspace,
55 }), ({ isFeatureActive, activeWorkspace }) => {
56 if (!isFeatureActive) return;
57 if (activeWorkspace) {
58 const services = stores.services.allDisplayed;
59 const activeService = services.find(s => s.isActive);
60 const workspaceServices = filterServicesByActiveWorkspace(services);
61 const isActiveServiceInWorkspace = workspaceServices.includes(activeService);
62 if (!isActiveServiceInWorkspace) {
63 console.log(workspaceServices[0].id);
64 actions.service.setActive({ serviceId: workspaceServices[0].id });
65 }
66 }
67 });
68}
diff --git a/src/features/workspaces/models/Workspace.js b/src/features/workspaces/models/Workspace.js
new file mode 100644
index 000000000..6c73d7095
--- /dev/null
+++ b/src/features/workspaces/models/Workspace.js
@@ -0,0 +1,25 @@
1import { observable } from 'mobx';
2
3export default class Workspace {
4 id = null;
5
6 @observable name = null;
7
8 @observable order = null;
9
10 @observable services = [];
11
12 @observable userId = null;
13
14 constructor(data) {
15 if (!data.id) {
16 throw Error('Workspace requires Id');
17 }
18
19 this.id = data.id;
20 this.name = data.name;
21 this.order = data.order;
22 this.services.replace(data.services);
23 this.userId = data.userId;
24 }
25}
diff --git a/src/features/workspaces/state.js b/src/features/workspaces/state.js
new file mode 100644
index 000000000..963b96f81
--- /dev/null
+++ b/src/features/workspaces/state.js
@@ -0,0 +1,15 @@
1import { observable } from 'mobx';
2
3const defaultState = {
4 activeWorkspace: null,
5 isLoading: false,
6 isFeatureActive: false,
7 workspaces: [],
8 workspaceBeingEdited: null,
9};
10
11export const workspacesState = observable(defaultState);
12
13export function resetState() {
14 Object.assign(workspacesState, defaultState);
15}
diff --git a/src/features/workspaces/store.js b/src/features/workspaces/store.js
new file mode 100644
index 000000000..a2997a0d2
--- /dev/null
+++ b/src/features/workspaces/store.js
@@ -0,0 +1,114 @@
1import { observable, reaction, action } from 'mobx';
2import Store from '../../stores/lib/Store';
3import CachedRequest from '../../stores/lib/CachedRequest';
4import Workspace from './models/Workspace';
5import { matchRoute } from '../../helpers/routing-helpers';
6import workspaceActions from './actions';
7
8const debug = require('debug')('Franz:feature:workspaces');
9
10export default class WorkspacesStore extends Store {
11 @observable allWorkspacesRequest = new CachedRequest(this.api, 'getUserWorkspaces');
12
13 constructor(stores, api, actions, state) {
14 super(stores, api, actions);
15 this.state = state;
16 }
17
18 setup() {
19 debug('fetching workspaces');
20 this.allWorkspacesRequest.execute();
21
22 /**
23 * Update the state workspaces array when workspaces request has results.
24 */
25 reaction(
26 () => this.allWorkspacesRequest.result,
27 workspaces => this._setWorkspaces(workspaces),
28 );
29 /**
30 * Update the loading state when workspace request is executing.
31 */
32 reaction(
33 () => this.allWorkspacesRequest.isExecuting,
34 isExecuting => this._setIsLoading(isExecuting),
35 );
36 /**
37 * Update the state with the workspace to be edited when route matches.
38 */
39 reaction(
40 () => ({
41 pathname: this.stores.router.location.pathname,
42 workspaces: this.state.workspaces,
43 }),
44 ({ pathname }) => {
45 const match = matchRoute('/settings/workspaces/edit/:id', pathname);
46 if (match) {
47 this.state.workspaceBeingEdited = this._getWorkspaceById(match.id);
48 }
49 },
50 );
51
52 workspaceActions.edit.listen(this._edit);
53 workspaceActions.create.listen(this._create);
54 workspaceActions.delete.listen(this._delete);
55 workspaceActions.update.listen(this._update);
56 workspaceActions.activate.listen(this._setActiveWorkspace);
57 workspaceActions.deactivate.listen(this._deactivateActiveWorkspace);
58 }
59
60 _getWorkspaceById = id => this.state.workspaces.find(w => w.id === id);
61
62 @action _setWorkspaces = (workspaces) => {
63 debug('setting user workspaces', workspaces.slice());
64 this.state.workspaces = workspaces.map(data => new Workspace(data));
65 };
66
67 @action _setIsLoading = (isLoading) => {
68 this.state.isLoading = isLoading;
69 };
70
71 @action _edit = ({ workspace }) => {
72 this.stores.router.push(`/settings/workspaces/edit/${workspace.id}`);
73 };
74
75 @action _create = async ({ name }) => {
76 try {
77 const result = await this.api.createWorkspace(name);
78 const workspace = new Workspace(result);
79 this.state.workspaces.push(workspace);
80 this._edit({ workspace });
81 } catch (error) {
82 throw error;
83 }
84 };
85
86 @action _delete = async ({ workspace }) => {
87 try {
88 await this.api.deleteWorkspace(workspace);
89 this.state.workspaces.remove(workspace);
90 this.stores.router.push('/settings/workspaces');
91 } catch (error) {
92 throw error;
93 }
94 };
95
96 @action _update = async ({ workspace }) => {
97 try {
98 await this.api.updateWorkspace(workspace);
99 const localWorkspace = this.state.workspaces.find(ws => ws.id === workspace.id);
100 Object.assign(localWorkspace, workspace);
101 this.stores.router.push('/settings/workspaces');
102 } catch (error) {
103 throw error;
104 }
105 };
106
107 @action _setActiveWorkspace = ({ workspace }) => {
108 this.state.activeWorkspace = workspace;
109 };
110
111 @action _deactivateActiveWorkspace = () => {
112 this.state.activeWorkspace = null;
113 };
114}
diff --git a/src/features/workspaces/styles/workspaces-table.scss b/src/features/workspaces/styles/workspaces-table.scss
new file mode 100644
index 000000000..6d0e7b4f5
--- /dev/null
+++ b/src/features/workspaces/styles/workspaces-table.scss
@@ -0,0 +1,53 @@
1@import '../../../styles/config';
2
3.theme__dark .workspace-table {
4 .workspace-table__column-info .mdi { color: $dark-theme-gray-lightest; }
5
6 .workspace-table__row {
7 border-bottom: 1px solid $dark-theme-gray-darker;
8
9 &:hover { background: $dark-theme-gray-darker; }
10 &.workspace-table__row--disabled { color: $dark-theme-gray; }
11 }
12}
13
14.workspace-table {
15 width: 100%;
16
17 .workspace-table__toggle {
18 width: 60px;
19
20 .franz-form__field {
21 margin-bottom: 0;
22 }
23 }
24
25 .workspace-table__column-action {
26 width: 40px
27 }
28
29 .workspace-table__column-info {
30 width: 40px;
31
32 .mdi {
33 color: $theme-gray-light;
34 display: block;
35 font-size: 18px;
36 }
37 }
38
39 .workspace-table__row {
40 border-bottom: 1px solid $theme-gray-lightest;
41
42 &:hover {
43 cursor: initial;
44 background: $theme-gray-lightest;
45 }
46
47 &.workspace-table__row--disabled {
48 color: $theme-gray-light;
49 }
50 }
51
52 td { padding: 10px; }
53}
diff --git a/src/i18n/locales/de.json b/src/i18n/locales/de.json
index b5abb56d4..0c1fb8aa6 100644
--- a/src/i18n/locales/de.json
+++ b/src/i18n/locales/de.json
@@ -74,6 +74,9 @@
74 "menu.window" : "Fenster", 74 "menu.window" : "Fenster",
75 "menu.window.close" : "Schließen", 75 "menu.window.close" : "Schließen",
76 "menu.window.minimize" : "Minimieren", 76 "menu.window.minimize" : "Minimieren",
77 "menu.workspaces": "Workspaces",
78 "menu.workspaces.defaultWorkspace": "All services",
79 "menu.workspaces.addNewWorkspace": "Add New Workspace",
77 "password.email.label" : "E-Mail Adresse", 80 "password.email.label" : "E-Mail Adresse",
78 "password.headline" : "Passwort zurücksetzen", 81 "password.headline" : "Passwort zurücksetzen",
79 "password.link.login" : "An Deinem Konto anmelden", 82 "password.link.login" : "An Deinem Konto anmelden",
@@ -158,6 +161,7 @@
158 "settings.navigation.logout" : "Abmelden", 161 "settings.navigation.logout" : "Abmelden",
159 "settings.navigation.settings" : "Einstellungen", 162 "settings.navigation.settings" : "Einstellungen",
160 "settings.navigation.yourServices" : "Deine Dienste", 163 "settings.navigation.yourServices" : "Deine Dienste",
164 "settings.navigation.yourWorkspaces": "Deine Workspaces",
161 "settings.recipes.all" : "Alle Dienste", 165 "settings.recipes.all" : "Alle Dienste",
162 "settings.recipes.dev" : "Entwicklung", 166 "settings.recipes.dev" : "Entwicklung",
163 "settings.recipes.headline" : "Verfügbare Dienste", 167 "settings.recipes.headline" : "Verfügbare Dienste",
@@ -216,6 +220,14 @@
216 "settings.services.tooltip.isMuted" : "Alle Töne sind deaktiviert", 220 "settings.services.tooltip.isMuted" : "Alle Töne sind deaktiviert",
217 "settings.services.tooltip.notificationsDisabled" : "Benachrichtigungen deaktiviert", 221 "settings.services.tooltip.notificationsDisabled" : "Benachrichtigungen deaktiviert",
218 "settings.services.updatedInfo" : "Deine Änderungen wurden gespeichert", 222 "settings.services.updatedInfo" : "Deine Änderungen wurden gespeichert",
223 "settings.workspaces.headline": "Deine Workspaces",
224 "settings.workspace.add.form.submitButton": "Workspace erstellen",
225 "settings.workspace.add.form.name": "Name",
226 "settings.workspace.form.yourWorkspaces": "Deine Workspaces",
227 "settings.workspace.form.name": "Name",
228 "settings.workspace.form.buttonDelete": "Workspace löschen",
229 "settings.workspace.form.buttonSave": "Workspace speichern",
230 "settings.workspace.form.servicesInWorkspaceHeadline": "Services in diesem Workspace",
219 "settings.user.form.accountType.company" : "Firma", 231 "settings.user.form.accountType.company" : "Firma",
220 "settings.user.form.accountType.individual" : "Einzelperson", 232 "settings.user.form.accountType.individual" : "Einzelperson",
221 "settings.user.form.accountType.label" : "Konto-Typ", 233 "settings.user.form.accountType.label" : "Konto-Typ",
diff --git a/src/i18n/locales/en-US.json b/src/i18n/locales/en-US.json
index 25ec027d8..2a51662a2 100644
--- a/src/i18n/locales/en-US.json
+++ b/src/i18n/locales/en-US.json
@@ -97,6 +97,7 @@
97 "settings.invite.headline": "Invite Friends", 97 "settings.invite.headline": "Invite Friends",
98 "settings.navigation.availableServices": "Available services", 98 "settings.navigation.availableServices": "Available services",
99 "settings.navigation.yourServices": "Your services", 99 "settings.navigation.yourServices": "Your services",
100 "settings.navigation.yourWorkspaces": "Your workspaces",
100 "settings.navigation.account": "Account", 101 "settings.navigation.account": "Account",
101 "settings.navigation.settings": "Settings", 102 "settings.navigation.settings": "Settings",
102 "settings.navigation.inviteFriends": "Invite Friends", 103 "settings.navigation.inviteFriends": "Invite Friends",
@@ -199,6 +200,14 @@
199 "settings.user.form.accountType.individual": "Individual", 200 "settings.user.form.accountType.individual": "Individual",
200 "settings.user.form.accountType.non-profit": "Non-Profit", 201 "settings.user.form.accountType.non-profit": "Non-Profit",
201 "settings.user.form.accountType.company": "Company", 202 "settings.user.form.accountType.company": "Company",
203 "settings.workspaces.headline": "Your workspaces",
204 "settings.workspace.add.form.submitButton": "Create Workspace",
205 "settings.workspace.add.form.name": "Name",
206 "settings.workspace.form.yourWorkspaces": "Your workspaces",
207 "settings.workspace.form.name": "Name",
208 "settings.workspace.form.buttonDelete": "Delete Workspace",
209 "settings.workspace.form.buttonSave": "Save Workspace",
210 "settings.workspace.form.servicesInWorkspaceHeadline": "Services in this Workspace",
202 "subscription.type.free": "free", 211 "subscription.type.free": "free",
203 "subscription.type.month": "month", 212 "subscription.type.month": "month",
204 "subscription.type.year": "year", 213 "subscription.type.year": "year",
@@ -267,7 +276,10 @@
267 "menu.app.hideOthers": "Hide Others", 276 "menu.app.hideOthers": "Hide Others",
268 "menu.app.unhide": "Unhide", 277 "menu.app.unhide": "Unhide",
269 "menu.app.quit": "Quit", 278 "menu.app.quit": "Quit",
270 "menu.services.addNewService": "Add New Service...", 279 "menu.services.addNewService": "Add New Service",
280 "menu.workspaces": "Workspaces",
281 "menu.workspaces.defaultWorkspace": "All services",
282 "menu.workspaces.addNewWorkspace": "Add New Workspace",
271 "validation.required": "{field} is required", 283 "validation.required": "{field} is required",
272 "validation.email": "{field} is not valid", 284 "validation.email": "{field} is not valid",
273 "validation.url": "{field} is not a valid URL", 285 "validation.url": "{field} is not a valid URL",
diff --git a/src/lib/Menu.js b/src/lib/Menu.js
index c378619ad..1560dd285 100644
--- a/src/lib/Menu.js
+++ b/src/lib/Menu.js
@@ -3,6 +3,8 @@ import { observable, autorun, computed } from 'mobx';
3import { defineMessages } from 'react-intl'; 3import { defineMessages } from 'react-intl';
4 4
5import { isMac, ctrlKey, cmdKey } from '../environment'; 5import { isMac, ctrlKey, cmdKey } from '../environment';
6import { workspacesState } from '../features/workspaces/state';
7import workspaceActions from '../features/workspaces/actions';
6 8
7const { app, Menu, dialog } = remote; 9const { app, Menu, dialog } = remote;
8 10
@@ -179,6 +181,18 @@ const menuItems = defineMessages({
179 id: 'menu.services.addNewService', 181 id: 'menu.services.addNewService',
180 defaultMessage: '!!!Add New Service...', 182 defaultMessage: '!!!Add New Service...',
181 }, 183 },
184 workspaces: {
185 id: 'menu.workspaces',
186 defaultMessage: '!!!Workspaces',
187 },
188 defaultWorkspace: {
189 id: 'menu.workspaces.defaultWorkspace',
190 defaultMessage: '!!!Default',
191 },
192 addNewWorkspace: {
193 id: 'menu.workspaces.addNewWorkspace',
194 defaultMessage: '!!!Add New Workspace...',
195 },
182}); 196});
183 197
184function getActiveWebview() { 198function getActiveWebview() {
@@ -266,6 +280,10 @@ const _templateFactory = intl => [
266 submenu: [], 280 submenu: [],
267 }, 281 },
268 { 282 {
283 label: intl.formatMessage(menuItems.workspaces),
284 submenu: [],
285 },
286 {
269 label: intl.formatMessage(menuItems.window), 287 label: intl.formatMessage(menuItems.window),
270 role: 'window', 288 role: 'window',
271 submenu: [ 289 submenu: [
@@ -499,7 +517,9 @@ export default class FranzMenu {
499 } 517 }
500 518
501 _build() { 519 _build() {
502 const serviceTpl = Object.assign([], this.serviceTpl); // need to clone object so we don't modify computed (cached) object 520 // need to clone object so we don't modify computed (cached) object
521 const serviceTpl = Object.assign([], this.serviceTpl);
522 const workspacesMenu = Object.assign([], this.workspacesMenu);
503 523
504 if (window.franz === undefined) { 524 if (window.franz === undefined) {
505 return; 525 return;
@@ -632,7 +652,7 @@ export default class FranzMenu {
632 }, 652 },
633 ); 653 );
634 654
635 tpl[4].submenu.unshift(about, { 655 tpl[5].submenu.unshift(about, {
636 type: 'separator', 656 type: 'separator',
637 }); 657 });
638 } else { 658 } else {
@@ -678,6 +698,8 @@ export default class FranzMenu {
678 tpl[3].submenu = serviceTpl; 698 tpl[3].submenu = serviceTpl;
679 } 699 }
680 700
701 tpl[4].submenu = workspacesMenu;
702
681 this.currentTemplate = tpl; 703 this.currentTemplate = tpl;
682 const menu = Menu.buildFromTemplate(tpl); 704 const menu = Menu.buildFromTemplate(tpl);
683 Menu.setApplicationMenu(menu); 705 Menu.setApplicationMenu(menu);
@@ -701,6 +723,51 @@ export default class FranzMenu {
701 return []; 723 return [];
702 } 724 }
703 725
726 @computed get workspacesMenu() {
727 const { workspaces, activeWorkspace } = workspacesState;
728 const { intl } = window.franz;
729 const menu = [];
730
731 // Add new workspace item:
732 menu.push({
733 label: intl.formatMessage(menuItems.addNewWorkspace),
734 accelerator: `${cmdKey}+Shift+N`,
735 click: () => {
736 this.actions.ui.openSettings({ path: 'workspaces' });
737 },
738 enabled: this.stores.user.isLoggedIn,
739 }, {
740 type: 'separator',
741 });
742
743 // Default workspace
744 menu.push({
745 label: intl.formatMessage(menuItems.defaultWorkspace),
746 accelerator: `${cmdKey}+Alt+1`,
747 type: 'radio',
748 checked: !activeWorkspace,
749 click: () => {
750 workspaceActions.deactivate();
751 },
752 });
753
754 // Workspace items
755 if (this.stores.user.isLoggedIn) {
756 workspaces.forEach((workspace, i) => menu.push({
757 label: workspace.name,
758 accelerator: i < 9 ? `${cmdKey}+Alt+${i + 2}` : null,
759 type: 'radio',
760 checked: activeWorkspace ? workspace.id === activeWorkspace.id : false,
761 click: () => {
762 workspaceActions.activate({ workspace });
763 },
764 }));
765 }
766
767 console.log(menu);
768 return menu;
769 }
770
704 _getServiceName(service) { 771 _getServiceName(service) {
705 if (service.name) { 772 if (service.name) {
706 return service.name; 773 return service.name;
diff --git a/src/stores/FeaturesStore.js b/src/stores/FeaturesStore.js
index d2842083c..b7130904b 100644
--- a/src/stores/FeaturesStore.js
+++ b/src/stores/FeaturesStore.js
@@ -7,6 +7,7 @@ import delayApp from '../features/delayApp';
7import spellchecker from '../features/spellchecker'; 7import spellchecker from '../features/spellchecker';
8import serviceProxy from '../features/serviceProxy'; 8import serviceProxy from '../features/serviceProxy';
9import basicAuth from '../features/basicAuth'; 9import basicAuth from '../features/basicAuth';
10import workspaces from '../features/workspaces';
10import shareFranz from '../features/shareFranz'; 11import shareFranz from '../features/shareFranz';
11 12
12import { DEFAULT_FEATURES_CONFIG } from '../config'; 13import { DEFAULT_FEATURES_CONFIG } from '../config';
@@ -38,7 +39,7 @@ export default class FeaturesStore extends Store {
38 39
39 @computed get features() { 40 @computed get features() {
40 if (this.stores.user.isLoggedIn) { 41 if (this.stores.user.isLoggedIn) {
41 return this.featuresRequest.execute().result || DEFAULT_FEATURES_CONFIG; 42 return Object.assign({}, DEFAULT_FEATURES_CONFIG, this.featuresRequest.execute().result);
42 } 43 }
43 44
44 return DEFAULT_FEATURES_CONFIG; 45 return DEFAULT_FEATURES_CONFIG;
@@ -57,6 +58,7 @@ export default class FeaturesStore extends Store {
57 spellchecker(this.stores, this.actions); 58 spellchecker(this.stores, this.actions);
58 serviceProxy(this.stores, this.actions); 59 serviceProxy(this.stores, this.actions);
59 basicAuth(this.stores, this.actions); 60 basicAuth(this.stores, this.actions);
61 workspaces(this.stores, this.actions);
60 shareFranz(this.stores, this.actions); 62 shareFranz(this.stores, this.actions);
61 } 63 }
62} 64}
diff --git a/src/stores/ServicesStore.js b/src/stores/ServicesStore.js
index c63bef196..a86db8103 100644
--- a/src/stores/ServicesStore.js
+++ b/src/stores/ServicesStore.js
@@ -2,7 +2,7 @@ import {
2 action, 2 action,
3 reaction, 3 reaction,
4 computed, 4 computed,
5 observable, 5 observable, runInAction,
6} from 'mobx'; 6} from 'mobx';
7import { debounce, remove } from 'lodash'; 7import { debounce, remove } from 'lodash';
8import ms from 'ms'; 8import ms from 'ms';
@@ -12,6 +12,8 @@ import Request from './lib/Request';
12import CachedRequest from './lib/CachedRequest'; 12import CachedRequest from './lib/CachedRequest';
13import { matchRoute } from '../helpers/routing-helpers'; 13import { matchRoute } from '../helpers/routing-helpers';
14import { gaEvent } from '../lib/analytics'; 14import { gaEvent } from '../lib/analytics';
15import { workspacesState } from '../features/workspaces/state';
16import { filterServicesByActiveWorkspace, getActiveWorkspaceServices } from '../features/workspaces';
15 17
16const debug = require('debug')('Franz:ServiceStore'); 18const debug = require('debug')('Franz:ServiceStore');
17 19
@@ -98,7 +100,6 @@ export default class ServicesStore extends Store {
98 return observable(services.slice().slice().sort((a, b) => a.order - b.order)); 100 return observable(services.slice().slice().sort((a, b) => a.order - b.order));
99 } 101 }
100 } 102 }
101
102 return []; 103 return [];
103 } 104 }
104 105
@@ -107,13 +108,16 @@ export default class ServicesStore extends Store {
107 } 108 }
108 109
109 @computed get allDisplayed() { 110 @computed get allDisplayed() {
110 return this.stores.settings.all.app.showDisabledServices ? this.all : this.enabled; 111 const services = this.stores.settings.all.app.showDisabledServices ? this.all : this.enabled;
112 return filterServicesByActiveWorkspace(services);
111 } 113 }
112 114
113 // This is just used to avoid unnecessary rerendering of resource-heavy webviews 115 // This is just used to avoid unnecessary rerendering of resource-heavy webviews
114 @computed get allDisplayedUnordered() { 116 @computed get allDisplayedUnordered() {
117 const { showDisabledServices } = this.stores.settings.all.app;
115 const services = this.allServicesRequest.execute().result || []; 118 const services = this.allServicesRequest.execute().result || [];
116 return this.stores.settings.all.app.showDisabledServices ? services : services.filter(service => service.isEnabled); 119 const filteredServices = showDisabledServices ? services : services.filter(service => service.isEnabled);
120 return getActiveWorkspaceServices(filteredServices);
117 } 121 }
118 122
119 @computed get filtered() { 123 @computed get filtered() {
diff --git a/src/styles/main.scss b/src/styles/main.scss
index 784a04d3d..9ba7f5827 100644
--- a/src/styles/main.scss
+++ b/src/styles/main.scss
@@ -31,6 +31,9 @@ $mdi-font-path: '../node_modules/mdi/fonts';
31@import './invite.scss'; 31@import './invite.scss';
32@import './title-bar.scss'; 32@import './title-bar.scss';
33 33
34// Workspaces legacy css
35@import '../features/workspaces/styles/workspaces-table';
36
34// form 37// form
35@import './input.scss'; 38@import './input.scss';
36@import './radio.scss'; 39@import './radio.scss';