Merge branch 'master' of github.com:Human-Connection/Human-Connection into 1710-list-and-protocol-moderation

This commit is contained in:
Wolfgang Huß 2019-10-23 08:22:41 +02:00
commit f5126e919f
51 changed files with 2566 additions and 1225 deletions

View File

@ -0,0 +1,2 @@
since-tag=0.1.5
release-branch=master

View File

@ -6,13 +6,19 @@
**Fixed bugs:**
- 🐛 \[Bug\] Error when saving changed article [\#1992](https://github.com/Human-Connection/Human-Connection/issues/1992)
- 🐛 \[Bug\] Translations in german for pin a post missing [\#1971](https://github.com/Human-Connection/Human-Connection/issues/1971)
- 🐛 \[Bug\] Comments both editors are visible at the same time [\#1970](https://github.com/Human-Connection/Human-Connection/issues/1970)
- 🐛 \[Bug\] Cropped images, at the moment, are much larger [\#1933](https://github.com/Human-Connection/Human-Connection/issues/1933)
- 🐛 \[Bug\] All images uploaded since introducing image cropping are named ...-blob [\#1932](https://github.com/Human-Connection/Human-Connection/issues/1932)
- 🐛 \[Bug\] Moderators reports list does not sort [\#1924](https://github.com/Human-Connection/Human-Connection/issues/1924)
- 🐛 \[Bug\] Double ellipses for truncated strings [\#1893](https://github.com/Human-Connection/Human-Connection/issues/1893)
- 🐛 \[Bug\] Login page translation error DE [\#1874](https://github.com/Human-Connection/Human-Connection/issues/1874)
- 🐛 \[Bug\] Add Reference ToS and Data privacy Statement to Register Dialogue [\#1873](https://github.com/Human-Connection/Human-Connection/issues/1873)
- 🐛 \[Bug\] extend Title to 100 characters [\#1812](https://github.com/Human-Connection/Human-Connection/issues/1812)
- 🐛 \[Bug\] Shortened text is shown longer than full text [\#1795](https://github.com/Human-Connection/Human-Connection/issues/1795)
- 🐛 \[Bug\] Order contributions chronologically on profile page [\#1754](https://github.com/Human-Connection/Human-Connection/issues/1754)
- 🐛 \[Bug\] Sorting is not maintained after page navigation [\#1733](https://github.com/Human-Connection/Human-Connection/issues/1733)
- 🐛 \[Bug\] Update maintenance page email [\#1731](https://github.com/Human-Connection/Human-Connection/issues/1731)
- 🐛 \[Bug\] Editing comments is not reactive again [\#1718](https://github.com/Human-Connection/Human-Connection/issues/1718)
- 🐛 \[Bug\] Comments with mentions in the end not displayed [\#1665](https://github.com/Human-Connection/Human-Connection/issues/1665)
@ -31,6 +37,7 @@
- 🐛 \[Bug\] One cypress test fails but it does not fail the build [\#1312](https://github.com/Human-Connection/Human-Connection/issues/1312)
- 🐛 \[Bug\] ContributionForm CreatePost is throwing Vue errors [\#1311](https://github.com/Human-Connection/Human-Connection/issues/1311)
- 🐛 \[Bug\] TypeError: Cannot read property 'offsetTop' of null [\#1273](https://github.com/Human-Connection/Human-Connection/issues/1273)
- 🍰 Translate texts for pinning a post to German [\#1972](https://github.com/Human-Connection/Human-Connection/pull/1972) ([Tirokk](https://github.com/Tirokk))
- 🍰 Add Cypher statement for ordering [\#1926](https://github.com/Human-Connection/Human-Connection/pull/1926) ([Tirokk](https://github.com/Tirokk))
**Closed issues:**
@ -47,6 +54,7 @@
- 🚀 \[Feature\] Report with reason [\#1469](https://github.com/Human-Connection/Human-Connection/issues/1469)
- 🚀 \[Feature\] Image cropping [\#1466](https://github.com/Human-Connection/Human-Connection/issues/1466)
- 🚀 \[Feature\] Update `lastActiveAt` on every JWT token check [\#1305](https://github.com/Human-Connection/Human-Connection/issues/1305)
- 🚀 \[Feature\] Create a pinned Post for administration [\#1205](https://github.com/Human-Connection/Human-Connection/issues/1205)
- 🚀 \[Feature\] Expand and mark comment if one jumps to it by URL hashtag [\#1204](https://github.com/Human-Connection/Human-Connection/issues/1204)
- 🚀 \[Feature\] Make Invite an Registration E-Mails translatable and pretty [\#1186](https://github.com/Human-Connection/Human-Connection/issues/1186)
- 🚀 \[Feature\] @Username: Unique user identification if identical profile names exist [\#1069](https://github.com/Human-Connection/Human-Connection/issues/1069)
@ -54,21 +62,43 @@
**Merged pull requests:**
- build\(deps\): bump nuxt from 2.10.1 to 2.10.2 in /webapp [\#1987](https://github.com/Human-Connection/Human-Connection/pull/1987) ([dependabot-preview[bot]](https://github.com/apps/dependabot-preview))
- build\(deps-dev\): bump @storybook/vue from 5.2.4 to 5.2.5 in /webapp [\#1981](https://github.com/Human-Connection/Human-Connection/pull/1981) ([dependabot-preview[bot]](https://github.com/apps/dependabot-preview))
- build\(deps-dev\): bump eslint-plugin-jest from 22.17.0 to 22.20.0 in /backend [\#1978](https://github.com/Human-Connection/Human-Connection/pull/1978) ([dependabot-preview[bot]](https://github.com/apps/dependabot-preview))
- build\(deps\): bump node from 12.12.0-alpine to 12.13.0-alpine in /webapp [\#1977](https://github.com/Human-Connection/Human-Connection/pull/1977) ([dependabot-preview[bot]](https://github.com/apps/dependabot-preview))
- Hide new CommentForm while editing a comment [\#1973](https://github.com/Human-Connection/Human-Connection/pull/1973) ([mattwr18](https://github.com/mattwr18))
- fix: Only one ellipse is displayed [\#1968](https://github.com/Human-Connection/Human-Connection/pull/1968) ([Mogge](https://github.com/Mogge))
- build\(deps-dev\): bump @vue/cli-shared-utils from 3.12.0 to 4.0.4 in /webapp [\#1965](https://github.com/Human-Connection/Human-Connection/pull/1965) ([dependabot-preview[bot]](https://github.com/apps/dependabot-preview))
- build\(deps\): bump neo4j from 3.5.11-enterprise to 3.5.12-enterprise in /neo4j [\#1963](https://github.com/Human-Connection/Human-Connection/pull/1963) ([dependabot-preview[bot]](https://github.com/apps/dependabot-preview))
- build\(deps-dev\): bump date-fns from 2.5.0 to 2.5.1 [\#1962](https://github.com/Human-Connection/Human-Connection/pull/1962) ([dependabot-preview[bot]](https://github.com/apps/dependabot-preview))
- build\(deps\): bump faker from `10bfb9f` to `9fd8d7d` in /backend [\#1961](https://github.com/Human-Connection/Human-Connection/pull/1961) ([dependabot-preview[bot]](https://github.com/apps/dependabot-preview))
- build\(deps-dev\): bump cypress-file-upload from 3.3.4 to 3.4.0 [\#1960](https://github.com/Human-Connection/Human-Connection/pull/1960) ([dependabot-preview[bot]](https://github.com/apps/dependabot-preview))
- build\(deps\): bump date-fns from 2.5.0 to 2.5.1 in /backend [\#1959](https://github.com/Human-Connection/Human-Connection/pull/1959) ([dependabot-preview[bot]](https://github.com/apps/dependabot-preview))
- build\(deps-dev\): bump faker from `10bfb9f` to `9fd8d7d` [\#1958](https://github.com/Human-Connection/Human-Connection/pull/1958) ([dependabot-preview[bot]](https://github.com/apps/dependabot-preview))
- Refactor reports resolver spec [\#1957](https://github.com/Human-Connection/Human-Connection/pull/1957) ([aonomike](https://github.com/aonomike))
- Update to version 0.1.5 [\#1951](https://github.com/Human-Connection/Human-Connection/pull/1951) ([mattwr18](https://github.com/mattwr18))
- build\(deps\): bump tiptap-extensions from 1.28.3 to 1.28.4 in /webapp [\#1946](https://github.com/Human-Connection/Human-Connection/pull/1946) ([dependabot-preview[bot]](https://github.com/apps/dependabot-preview))
- build\(deps\): bump metascraper-soundcloud from 5.7.6 to 5.7.7 in /backend [\#1943](https://github.com/Human-Connection/Human-Connection/pull/1943) ([dependabot-preview[bot]](https://github.com/apps/dependabot-preview))
- fix: console warnings during frontend tests [\#1942](https://github.com/Human-Connection/Human-Connection/pull/1942) ([roschaefer](https://github.com/roschaefer))
- Fix vue errors for Contribution form [\#1941](https://github.com/Human-Connection/Human-Connection/pull/1941) ([vbelolapotkov](https://github.com/vbelolapotkov))
- Follow @alina-beck and @Tirokk PR suggestions [\#1940](https://github.com/Human-Connection/Human-Connection/pull/1940) ([mattwr18](https://github.com/mattwr18))
- Maintain filename for cropped images [\#1935](https://github.com/Human-Connection/Human-Connection/pull/1935) ([mattwr18](https://github.com/mattwr18))
- Language will be saved in the database of the user during registration [\#1927](https://github.com/Human-Connection/Human-Connection/pull/1927) ([ogerly](https://github.com/ogerly))
- Improved comment truncation [\#1925](https://github.com/Human-Connection/Human-Connection/pull/1925) ([alina-beck](https://github.com/alina-beck))
- build\(deps\): bump styleguide from `808b3c5` to `d46fc15` [\#1923](https://github.com/Human-Connection/Human-Connection/pull/1923) ([dependabot-preview[bot]](https://github.com/apps/dependabot-preview))
- build\(deps\): bump date-fns from 2.4.1 to 2.5.0 in /webapp [\#1921](https://github.com/Human-Connection/Human-Connection/pull/1921) ([dependabot-preview[bot]](https://github.com/apps/dependabot-preview))
- build\(deps-dev\): bump async-validator from 3.1.0 to 3.2.0 in /webapp [\#1920](https://github.com/Human-Connection/Human-Connection/pull/1920) ([dependabot-preview[bot]](https://github.com/apps/dependabot-preview))
- build\(deps-dev\): bump date-fns from 2.4.1 to 2.5.0 [\#1919](https://github.com/Human-Connection/Human-Connection/pull/1919) ([dependabot-preview[bot]](https://github.com/apps/dependabot-preview))
- build\(deps-dev\): bump neode from 0.3.3 to 0.3.6 [\#1918](https://github.com/Human-Connection/Human-Connection/pull/1918) ([dependabot-preview[bot]](https://github.com/apps/dependabot-preview))
- build\(deps-dev\): bump dotenv from 8.1.0 to 8.2.0 [\#1917](https://github.com/Human-Connection/Human-Connection/pull/1917) ([dependabot-preview[bot]](https://github.com/apps/dependabot-preview))
- build\(deps-dev\): bump nodemon from 1.19.3 to 1.19.4 in /backend [\#1916](https://github.com/Human-Connection/Human-Connection/pull/1916) ([dependabot-preview[bot]](https://github.com/apps/dependabot-preview))
- build\(deps\): bump date-fns from 2.4.1 to 2.5.0 in /backend [\#1915](https://github.com/Human-Connection/Human-Connection/pull/1915) ([dependabot-preview[bot]](https://github.com/apps/dependabot-preview))
- build\(deps\): bump @sentry/node from 5.7.0 to 5.7.1 in /backend [\#1914](https://github.com/Human-Connection/Human-Connection/pull/1914) ([dependabot-preview[bot]](https://github.com/apps/dependabot-preview))
- build\(deps\): bump dotenv from 8.1.0 to 8.2.0 in /backend [\#1912](https://github.com/Human-Connection/Human-Connection/pull/1912) ([dependabot-preview[bot]](https://github.com/apps/dependabot-preview))
- fix: typo in German translation [\#1911](https://github.com/Human-Connection/Human-Connection/pull/1911) ([roschaefer](https://github.com/roschaefer))
- Add missing translations for Title placeholder [\#1910](https://github.com/Human-Connection/Human-Connection/pull/1910) ([mattwr18](https://github.com/mattwr18))
- Confirm privacy policy minimum age at registration [\#1907](https://github.com/Human-Connection/Human-Connection/pull/1907) ([ogerly](https://github.com/ogerly))
- Add storybook stories for our university students [\#1906](https://github.com/Human-Connection/Human-Connection/pull/1906) ([roschaefer](https://github.com/roschaefer))
- 1873 -WITH CHECKBOX [\#1905](https://github.com/Human-Connection/Human-Connection/pull/1905) ([ogerly](https://github.com/ogerly))
- refactor: improve locale imports [\#1904](https://github.com/Human-Connection/Human-Connection/pull/1904) ([roschaefer](https://github.com/roschaefer))
- Highlight and expand linked comment [\#1903](https://github.com/Human-Connection/Human-Connection/pull/1903) ([alina-beck](https://github.com/alina-beck))
@ -86,8 +116,8 @@
- build\(deps-dev\): bump eslint-plugin-jest from 22.17.0 to 22.19.0 in /backend [\#1888](https://github.com/Human-Connection/Human-Connection/pull/1888) ([dependabot-preview[bot]](https://github.com/apps/dependabot-preview))
- Fix translation error in login page [\#1885](https://github.com/Human-Connection/Human-Connection/pull/1885) ([janethavi](https://github.com/janethavi))
- 1773 refactor rewards spec [\#1884](https://github.com/Human-Connection/Human-Connection/pull/1884) ([aonomike](https://github.com/aonomike))
- 🍰 Refactor Database for Reporting with specific information [\#1878](https://github.com/Human-Connection/Human-Connection/pull/1878) ([Tirokk](https://github.com/Tirokk))
- Fix embeds settings page [\#1877](https://github.com/Human-Connection/Human-Connection/pull/1877) ([mattwr18](https://github.com/mattwr18))
- 🍰 Fix - maintaining sorting after navigation [\#1872](https://github.com/Human-Connection/Human-Connection/pull/1872) ([nimitbhargava](https://github.com/nimitbhargava))
- build\(deps\): bump @sentry/node from 5.6.2 to 5.7.0 in /backend [\#1871](https://github.com/Human-Connection/Human-Connection/pull/1871) ([dependabot-preview[bot]](https://github.com/apps/dependabot-preview))
- build\(deps-dev\): bump apollo-server-testing from 2.9.5 to 2.9.6 in /backend [\#1870](https://github.com/Human-Connection/Human-Connection/pull/1870) ([dependabot-preview[bot]](https://github.com/apps/dependabot-preview))
- build\(deps-dev\): bump @vue/cli-shared-utils from 3.11.0 to 3.12.0 in /webapp [\#1869](https://github.com/Human-Connection/Human-Connection/pull/1869) ([dependabot-preview[bot]](https://github.com/apps/dependabot-preview))
@ -103,6 +133,7 @@
- Add Hall of Fame to README [\#1859](https://github.com/Human-Connection/Human-Connection/pull/1859) ([roschaefer](https://github.com/roschaefer))
- build\(deps-dev\): bump cypress-cucumber-preprocessor from 1.16.1 to 1.16.2 [\#1855](https://github.com/Human-Connection/Human-Connection/pull/1855) ([dependabot-preview[bot]](https://github.com/apps/dependabot-preview))
- build\(deps\): bump nodemailer from 6.3.0 to 6.3.1 in /backend [\#1854](https://github.com/Human-Connection/Human-Connection/pull/1854) ([dependabot-preview[bot]](https://github.com/apps/dependabot-preview))
- Added createdAt date for follow and shout [\#1853](https://github.com/Human-Connection/Human-Connection/pull/1853) ([KapilJ22](https://github.com/KapilJ22))
- Save user setting to show embed code II [\#1852](https://github.com/Human-Connection/Human-Connection/pull/1852) ([ogerly](https://github.com/ogerly))
- Title character increased from 64 to 100 [\#1850](https://github.com/Human-Connection/Human-Connection/pull/1850) ([ogerly](https://github.com/ogerly))
- build\(deps-dev\): bump @babel/preset-env from 7.6.2 to 7.6.3 in /webapp [\#1849](https://github.com/Human-Connection/Human-Connection/pull/1849) ([dependabot-preview[bot]](https://github.com/apps/dependabot-preview))
@ -110,6 +141,7 @@
- build\(deps-dev\): bump @babel/cli from 7.6.2 to 7.6.3 in /backend [\#1847](https://github.com/Human-Connection/Human-Connection/pull/1847) ([dependabot-preview[bot]](https://github.com/apps/dependabot-preview))
- build\(deps-dev\): bump @babel/preset-env from 7.6.2 to 7.6.3 in /backend [\#1846](https://github.com/Human-Connection/Human-Connection/pull/1846) ([dependabot-preview[bot]](https://github.com/apps/dependabot-preview))
- build\(deps-dev\): bump @babel/node from 7.6.2 to 7.6.3 in /backend [\#1843](https://github.com/Human-Connection/Human-Connection/pull/1843) ([dependabot-preview[bot]](https://github.com/apps/dependabot-preview))
- Allow admins to pin a post [\#1840](https://github.com/Human-Connection/Human-Connection/pull/1840) ([mattwr18](https://github.com/mattwr18))
- build\(deps\): bump styleguide from `808b3c5` to `d46fc15` [\#1839](https://github.com/Human-Connection/Human-Connection/pull/1839) ([dependabot-preview[bot]](https://github.com/apps/dependabot-preview))
- build\(deps-dev\): bump @storybook/addon-actions from 5.2.1 to 5.2.3 in /webapp [\#1838](https://github.com/Human-Connection/Human-Connection/pull/1838) ([dependabot-preview[bot]](https://github.com/apps/dependabot-preview))
- build\(deps\): bump node from 12.11.0-alpine to 12.11.1-alpine in /backend [\#1837](https://github.com/Human-Connection/Human-Connection/pull/1837) ([dependabot-preview[bot]](https://github.com/apps/dependabot-preview))
@ -177,7 +209,6 @@
- Bump metascraper-title from 5.7.5 to 5.7.6 in /backend [\#1759](https://github.com/Human-Connection/Human-Connection/pull/1759) ([dependabot-preview[bot]](https://github.com/apps/dependabot-preview))
- Bump nodemon from 1.19.2 to 1.19.3 in /backend [\#1758](https://github.com/Human-Connection/Human-Connection/pull/1758) ([dependabot-preview[bot]](https://github.com/apps/dependabot-preview))
- fix email middleware transport config [\#1757](https://github.com/Human-Connection/Human-Connection/pull/1757) ([vbelolapotkov](https://github.com/vbelolapotkov))
- 1273 fix post page nav suggestions [\#1756](https://github.com/Human-Connection/Human-Connection/pull/1756) ([roschaefer](https://github.com/roschaefer))
- docs: moves storybook into webapp/README.md [\#1755](https://github.com/Human-Connection/Human-Connection/pull/1755) ([roschaefer](https://github.com/roschaefer))
- Bump date-fns from 2.2.1 to 2.4.0 in /webapp [\#1752](https://github.com/Human-Connection/Human-Connection/pull/1752) ([dependabot-preview[bot]](https://github.com/apps/dependabot-preview))
- fix: Github's security vulnerability warning [\#1751](https://github.com/Human-Connection/Human-Connection/pull/1751) ([roschaefer](https://github.com/roschaefer))

View File

@ -1 +1 @@
0.1.3
0.1.6

View File

@ -779,30 +779,6 @@
"regexpu-core": "^4.6.0"
}
},
"@babel/polyfill": {
"version": "7.6.0",
"resolved": "https://registry.npmjs.org/@babel/polyfill/-/polyfill-7.6.0.tgz",
"integrity": "sha512-q5BZJI0n/B10VaQQvln1IlDK3BTBJFbADx7tv+oXDPIDZuTo37H5Adb9jhlXm/fEN4Y7/64qD9mnrJJG7rmaTw==",
"dev": true,
"requires": {
"core-js": "^2.6.5",
"regenerator-runtime": "^0.13.2"
},
"dependencies": {
"core-js": {
"version": "2.6.10",
"resolved": "https://registry.npmjs.org/core-js/-/core-js-2.6.10.tgz",
"integrity": "sha512-I39t74+4t+zau64EN1fE5v2W31Adtc/REhzWN+gWRRXg6WH5qAsZm62DHpQ1+Yhe4047T55jvzz7MUqF/dBBlA==",
"dev": true
},
"regenerator-runtime": {
"version": "0.13.3",
"resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.3.tgz",
"integrity": "sha512-naKIZz2GQ8JWh///G7L3X6LaQUAMp2lvb1rvwwsURe/VXwD6VMfr+/1NuNw3ag8v2kY1aQ/go5SNn79O9JU7yw==",
"dev": true
}
}
},
"@babel/preset-env": {
"version": "7.6.3",
"resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.6.3.tgz",
@ -2204,12 +2180,12 @@
"dev": true
},
"assertion-error-formatter": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/assertion-error-formatter/-/assertion-error-formatter-2.0.1.tgz",
"integrity": "sha512-cjC3jUCh9spkroKue5PDSKH5RFQ/KNuZJhk3GwHYmB/8qqETxLOmMdLH+ohi/VukNzxDlMvIe7zScvLoOdhb6Q==",
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/assertion-error-formatter/-/assertion-error-formatter-3.0.0.tgz",
"integrity": "sha512-6YyAVLrEze0kQ7CmJfUgrLHb+Y7XghmL2Ie7ijVa2Y9ynP3LV+VDiwFk62Dn0qtqbmY0BT0ss6p1xxpiF2PYbQ==",
"dev": true,
"requires": {
"diff": "^3.0.0",
"diff": "^4.0.1",
"pad-right": "^0.2.2",
"repeat-string": "^1.6.1"
}
@ -2499,9 +2475,9 @@
"dev": true
},
"bluebird": {
"version": "3.7.0",
"resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.0.tgz",
"integrity": "sha512-aBQ1FxIa7kSWCcmKHlcHFlT2jt6J/l4FzC7KcPELkOJOsPOb/bccdhmIrKDfXhwFrmc7vDoDrrepFvGqjyXGJg==",
"version": "3.7.1",
"resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.1.tgz",
"integrity": "sha512-DdmyoGCleJnkbp3nkbxTLJ18rjDsE4yCggEwKNXkeV123sPNfOCYeDoeuOY+F2FrSjO1YXcTU+dsy96KMy+gcg==",
"dev": true
},
"body-parser": {
@ -3823,100 +3799,97 @@
}
},
"cucumber": {
"version": "5.1.0",
"resolved": "https://registry.npmjs.org/cucumber/-/cucumber-5.1.0.tgz",
"integrity": "sha512-zrl2VYTBRgvxucwV2GKAvLqcfA1Naeax8plPvWgPEzl3SCJiuPPv3WxBHIRHtPYcEdbHDR6oqLpZP4bJ8UIdmA==",
"version": "6.0.2",
"resolved": "https://registry.npmjs.org/cucumber/-/cucumber-6.0.2.tgz",
"integrity": "sha512-yEwPYGvgS2KG6ODdUXQwWcxjyr/l31dmpGJsZSkJIXNLNNmieKVefTpf8zLj6+0V2TCPwkmUZt4+OIXv97duEw==",
"dev": true,
"requires": {
"@babel/polyfill": "^7.2.3",
"assertion-error-formatter": "^2.0.1",
"assertion-error-formatter": "^3.0.0",
"bluebird": "^3.4.1",
"cli-table3": "^0.5.1",
"colors": "^1.1.2",
"commander": "^2.9.0",
"cross-spawn": "^6.0.5",
"cucumber-expressions": "^6.0.0",
"cucumber-tag-expressions": "^1.1.1",
"commander": "^3.0.1",
"cucumber-expressions": "^8.0.1",
"cucumber-tag-expressions": "^2.0.2",
"duration": "^0.2.1",
"escape-string-regexp": "^1.0.5",
"figures": "2.0.0",
"gherkin": "^5.0.0",
"escape-string-regexp": "^2.0.0",
"figures": "^3.0.0",
"gherkin": "5.0.0",
"glob": "^7.1.3",
"indent-string": "^3.1.0",
"indent-string": "^4.0.0",
"is-generator": "^1.0.2",
"is-stream": "^1.1.0",
"is-stream": "^2.0.0",
"knuth-shuffle-seeded": "^1.0.6",
"lodash": "^4.17.10",
"lodash": "^4.17.14",
"mz": "^2.4.0",
"progress": "^2.0.0",
"resolve": "^1.3.3",
"serialize-error": "^3.0.0",
"serialize-error": "^4.1.0",
"stack-chain": "^2.0.0",
"stacktrace-js": "^2.0.0",
"string-argv": "0.1.1",
"string-argv": "^0.3.0",
"title-case": "^2.1.1",
"util-arity": "^1.0.2",
"verror": "^1.9.0"
},
"dependencies": {
"cross-spawn": {
"version": "6.0.5",
"resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz",
"integrity": "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==",
"dev": true,
"requires": {
"nice-try": "^1.0.4",
"path-key": "^2.0.1",
"semver": "^5.5.0",
"shebang-command": "^1.2.0",
"which": "^1.2.9"
}
},
"path-key": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz",
"integrity": "sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A=",
"commander": {
"version": "3.0.2",
"resolved": "https://registry.npmjs.org/commander/-/commander-3.0.2.tgz",
"integrity": "sha512-Gar0ASD4BDyKC4hl4DwHqDrmvjoxWKZigVnAbn5H1owvm4CxCPdb0HQDehwNYMJpla5+M2tPmPARzhtYuwpHow==",
"dev": true
},
"shebang-command": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz",
"integrity": "sha1-RKrGW2lbAzmJaMOfNj/uXer98eo=",
"dev": true,
"requires": {
"shebang-regex": "^1.0.0"
}
},
"shebang-regex": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz",
"integrity": "sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM=",
"escape-string-regexp": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz",
"integrity": "sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==",
"dev": true
},
"which": {
"version": "1.3.1",
"resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz",
"integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==",
"figures": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/figures/-/figures-3.1.0.tgz",
"integrity": "sha512-ravh8VRXqHuMvZt/d8GblBeqDMkdJMBdv/2KntFH+ra5MXkO7nxNKpzQ3n6QD/2da1kH0aWmNISdvhM7gl2gVg==",
"dev": true,
"requires": {
"isexe": "^2.0.0"
"escape-string-regexp": "^1.0.5"
},
"dependencies": {
"escape-string-regexp": {
"version": "1.0.5",
"resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz",
"integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=",
"dev": true
}
}
},
"indent-string": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz",
"integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==",
"dev": true
},
"is-stream": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.0.tgz",
"integrity": "sha512-XCoy+WlUr7d1+Z8GgSuXmpuUFC9fOhRXglJMx+dwLKTkL44Cjd4W1Z5P+BQZpr+cR93aGP4S/s7Ftw6Nd/kiEw==",
"dev": true
}
}
},
"cucumber-expressions": {
"version": "6.6.2",
"resolved": "https://registry.npmjs.org/cucumber-expressions/-/cucumber-expressions-6.6.2.tgz",
"integrity": "sha512-WcFSVBiWNLJbIcAAC3t/ACU46vaOKfe1UIF5H3qveoq+Y4XQm9j3YwHurQNufRKBBg8nCnpU7Ttsx7egjS3hwA==",
"version": "8.0.1",
"resolved": "https://registry.npmjs.org/cucumber-expressions/-/cucumber-expressions-8.0.1.tgz",
"integrity": "sha512-g+A+tUEafNofe6ErwvOkqaMvDj9NuOr0GouGotpw4r5yK2d4144o9/6sQpXBr2YXbRy5ItmER/2bzAyDAzhPyQ==",
"dev": true,
"requires": {
"becke-ch--regex--s0-0-v1--base--pl--lib": "^1.2.0"
"becke-ch--regex--s0-0-v1--base--pl--lib": "^1.4.0",
"xregexp": "^4.2.4"
}
},
"cucumber-tag-expressions": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/cucumber-tag-expressions/-/cucumber-tag-expressions-1.1.1.tgz",
"integrity": "sha1-f1x7cACbwrZmWRv+ZIVFeL7e6Fo=",
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/cucumber-tag-expressions/-/cucumber-tag-expressions-2.0.2.tgz",
"integrity": "sha512-DohmT4X641KX/sb96bdb7J2kXNcQBPrYmf3Oc5kiHCLfzFMWx/o2kB4JvjvQPZnYuA9lRt6pqtArM5gvUn4uzw==",
"dev": true
},
"d": {
@ -3967,9 +3940,9 @@
}
},
"date-fns": {
"version": "2.4.1",
"resolved": "https://registry.npmjs.org/date-fns/-/date-fns-2.4.1.tgz",
"integrity": "sha512-2RhmH/sjDSCYW2F3ZQxOUx/I7PvzXpi89aQL2d3OAxSTwLx6NilATeUbe0menFE3Lu5lFkOFci36ivimwYHHxw=="
"version": "2.5.1",
"resolved": "https://registry.npmjs.org/date-fns/-/date-fns-2.5.1.tgz",
"integrity": "sha512-ZBrQmuaqH9YqIejbgu8f09ki7wdD2JxWsRTZ/+HnnLNmkI56ty0evnWzKY+ihLT0xX5VdUX0vDNZCxJJGKX2+Q=="
},
"debug": {
"version": "4.1.1",
@ -4114,9 +4087,9 @@
}
},
"diff": {
"version": "3.5.0",
"resolved": "https://registry.npmjs.org/diff/-/diff-3.5.0.tgz",
"integrity": "sha512-A46qtFgd+g7pDZinpnwiRJtxbC1hpgf0uzP3iG89scHk0AUC7A1TGxf5OiiOUv/JMZR8GOt8hL900hV0bOy5xA==",
"version": "4.0.1",
"resolved": "https://registry.npmjs.org/diff/-/diff-4.0.1.tgz",
"integrity": "sha512-s2+XdvhPCOF01LRQBC8hf4vhbVmI2CGS5aZnxLJlT5FtdhPCDFq80q++zK2KlrVorVDdL5BOGZ/VfLrVtYNF+Q==",
"dev": true
},
"diff-sequences": {
@ -4194,9 +4167,9 @@
}
},
"dotenv": {
"version": "8.1.0",
"resolved": "https://registry.npmjs.org/dotenv/-/dotenv-8.1.0.tgz",
"integrity": "sha512-GUE3gqcDCaMltj2++g6bRQ5rBJWtkWTmqmD0fo1RnnMuUqHNCt2oTPeDnS9n6fKYvlhn7AeBkb38lymBtWBQdA=="
"version": "8.2.0",
"resolved": "https://registry.npmjs.org/dotenv/-/dotenv-8.2.0.tgz",
"integrity": "sha512-8sJ78ElpbDJBHNeBzUbUVLsqKdccaa/BXF1uPTw3GrvQTBgrQrtObr2mUrE38vzYd8cEv+m/JBfDLioYcfXoaw=="
},
"duplexer3": {
"version": "0.1.4",
@ -4514,9 +4487,9 @@
}
},
"eslint-config-prettier": {
"version": "6.3.0",
"resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-6.3.0.tgz",
"integrity": "sha512-EWaGjlDAZRzVFveh2Jsglcere2KK5CJBhkNSa1xs3KfMUGdRiT7lG089eqPdvlzWHpAqaekubOsOMu8W8Yk71A==",
"version": "6.4.0",
"resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-6.4.0.tgz",
"integrity": "sha512-YrKucoFdc7SEko5Sxe4r6ixqXPDP1tunGw91POeZTTRKItf/AMFYt/YLEQtZMkR2LVpAVhcAcZgcWpm1oGPW7w==",
"dev": true,
"requires": {
"get-stdin": "^6.0.0"
@ -4799,9 +4772,9 @@
}
},
"eslint-plugin-jest": {
"version": "22.17.0",
"resolved": "https://registry.npmjs.org/eslint-plugin-jest/-/eslint-plugin-jest-22.17.0.tgz",
"integrity": "sha512-WT4DP4RoGBhIQjv+5D0FM20fAdAUstfYAf/mkufLNTojsfgzc5/IYW22cIg/Q4QBavAZsROQlqppiWDpFZDS8Q==",
"version": "22.20.0",
"resolved": "https://registry.npmjs.org/eslint-plugin-jest/-/eslint-plugin-jest-22.20.0.tgz",
"integrity": "sha512-UwHGXaYprxwd84Wer8H7jZS+5C3LeEaU8VD7NqORY6NmPJrs+9Ugbq3wyjqO3vWtSsDaLar2sqEB8COmOZA4zw==",
"dev": true,
"requires": {
"@typescript-eslint/experimental-utils": "^1.13.0"
@ -5553,9 +5526,9 @@
}
},
"gherkin": {
"version": "5.1.0",
"resolved": "https://registry.npmjs.org/gherkin/-/gherkin-5.1.0.tgz",
"integrity": "sha1-aEu7A63STq9731RPWAM+so+zxtU=",
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/gherkin/-/gherkin-5.0.0.tgz",
"integrity": "sha1-lt70EZjsOQgli1Ea909lWidk0qE=",
"dev": true
},
"glob": {
@ -9034,13 +9007,13 @@
}
},
"metascraper-soundcloud": {
"version": "5.7.6",
"resolved": "https://registry.npmjs.org/metascraper-soundcloud/-/metascraper-soundcloud-5.7.6.tgz",
"integrity": "sha512-fBxX5mYPFf8rWhhEX2XZD5QrmvtUI5IIPzryGuwEWsbPuMGuUkvFA9JjHJiC46uYXoi6UuKLXwSmYHcAACG3Jg==",
"version": "5.7.7",
"resolved": "https://registry.npmjs.org/metascraper-soundcloud/-/metascraper-soundcloud-5.7.7.tgz",
"integrity": "sha512-TDJxUwFJCxU4bTrrx3GWiGeZdNhvRhlI61JiprLkYBriM65uzCfaJ5FjS5uzZy1CfMYhvQgxLZ7XRq1bgbPpTg==",
"requires": {
"@metascraper/helpers": "^5.7.6",
"memoize-one": "~5.1.1",
"tldts": "~5.5.0"
"tldts": "~5.6.1"
},
"dependencies": {
"@metascraper/helpers": {
@ -9831,18 +9804,18 @@
}
},
"nodemon": {
"version": "1.19.3",
"resolved": "https://registry.npmjs.org/nodemon/-/nodemon-1.19.3.tgz",
"integrity": "sha512-TBNKRmJykEbxpTniZBusqRrUTHIEqa2fpecbTQDQj1Gxjth7kKAPP296ztR0o5gPUWsiYbuEbt73/+XMYab1+w==",
"version": "1.19.4",
"resolved": "https://registry.npmjs.org/nodemon/-/nodemon-1.19.4.tgz",
"integrity": "sha512-VGPaqQBNk193lrJFotBU8nvWZPqEZY2eIzymy2jjY0fJ9qIsxA0sxQ8ATPl0gZC645gijYEc1jtZvpS8QWzJGQ==",
"dev": true,
"requires": {
"chokidar": "^2.1.5",
"debug": "^3.1.0",
"chokidar": "^2.1.8",
"debug": "^3.2.6",
"ignore-by-default": "^1.0.1",
"minimatch": "^3.0.4",
"pstree.remy": "^1.1.6",
"semver": "^5.5.0",
"supports-color": "^5.2.0",
"pstree.remy": "^1.1.7",
"semver": "^5.7.1",
"supports-color": "^5.5.0",
"touch": "^3.1.0",
"undefsafe": "^2.0.2",
"update-notifier": "^2.5.0"
@ -11446,10 +11419,13 @@
}
},
"serialize-error": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/serialize-error/-/serialize-error-3.0.0.tgz",
"integrity": "sha512-+y3nkkG/go1Vdw+2f/+XUXM1DXX1XcxTl99FfiD/OEPUNw4uo0i6FKABfTAN5ZcgGtjTRZcEbxcE/jtXbEY19A==",
"dev": true
"version": "4.1.0",
"resolved": "https://registry.npmjs.org/serialize-error/-/serialize-error-4.1.0.tgz",
"integrity": "sha512-5j9GgyGsP9vV9Uj1S0lDCvlsd+gc2LEPVK7HHHte7IyPwOD4lVQFeaX143gx3U5AnoCi+wbcb3mvaxVysjpxEw==",
"dev": true,
"requires": {
"type-fest": "^0.3.0"
}
},
"serve-static": {
"version": "1.14.1",
@ -11894,9 +11870,9 @@
"integrity": "sha1-gIudDlb8Jz2Am6VzOOkpkZoanxo="
},
"string-argv": {
"version": "0.1.1",
"resolved": "https://registry.npmjs.org/string-argv/-/string-argv-0.1.1.tgz",
"integrity": "sha512-El1Va5ehZ0XTj3Ekw4WFidXvTmt9SrC0+eigdojgtJMVtPkF0qbBe9fyNSl9eQf+kUHnTSQxdQYzuHfZy8V+DQ==",
"version": "0.3.1",
"resolved": "https://registry.npmjs.org/string-argv/-/string-argv-0.3.1.tgz",
"integrity": "sha512-a1uQGz7IyVy9YwhqjZIZu1c8JO8dNIe20xBmSS6qu9kv++k3JGzCVmprbNN5Kn+BgzD5E7YYwg1CcjuJMRNsvg==",
"dev": true
},
"string-length": {
@ -12303,11 +12279,11 @@
"integrity": "sha512-7MUlYyGJ6rSitEZ3r1Q1QNV8uSIzapS8SmmhSusBuIc7uIxPPwsKllEP0GRp1NS6Ik6F+fRZvnjDWm3ecv2hDw=="
},
"tldts": {
"version": "5.5.0",
"resolved": "https://registry.npmjs.org/tldts/-/tldts-5.5.0.tgz",
"integrity": "sha512-CZ/d7Y4k8onxwerMWz/mTCeKJtX3VAMiL+ajXVFnxsKhH4BV+QavjnZ1Mb9OeCHo3jX0S3Dw6ERNRXqOMVsDvw==",
"version": "5.6.1",
"resolved": "https://registry.npmjs.org/tldts/-/tldts-5.6.1.tgz",
"integrity": "sha512-I+imSP592J9GUYApIoiDdJk3KlroHY4zmDmpAp+TlIDZZAPxx192yOUViMB2QmlcRtZUz5XLEM3cS2F0V7P1Fw==",
"requires": {
"tldts-core": "^5.5.0"
"tldts-core": "^5.6.1"
}
},
"tldts-core": {

View File

@ -42,7 +42,7 @@
},
"dependencies": {
"@hapi/joi": "^16.1.7",
"@sentry/node": "^5.7.0",
"@sentry/node": "^5.7.1",
"apollo-cache-inmemory": "~1.6.3",
"apollo-client": "~2.6.4",
"apollo-link-context": "~1.0.19",
@ -121,7 +121,7 @@
"eslint-config-prettier": "~6.4.0",
"eslint-config-standard": "~14.1.0",
"eslint-plugin-import": "~2.18.2",
"eslint-plugin-jest": "~22.19.0",
"eslint-plugin-jest": "~22.20.0",
"eslint-plugin-node": "~10.0.0",
"eslint-plugin-prettier": "~3.1.1",
"eslint-plugin-promise": "~4.2.1",

View File

@ -134,6 +134,7 @@ const permissions = shield(
PostsEmotionsByCurrentUser: isAuthenticated,
blockedUsers: isAuthenticated,
notifications: isAuthenticated,
profilePagePosts: or(onlyEnabledContent, isModerator),
},
Mutation: {
'*': deny,
@ -174,6 +175,8 @@ const permissions = shield(
markAsRead: isAuthenticated,
AddEmailAddress: isAuthenticated,
VerifyEmailAddress: isAuthenticated,
pinPost: isAdmin,
unpinPost: isAdmin,
},
User: {
email: or(isMyOwn, isAdmin),

View File

@ -114,6 +114,15 @@ module.exports = {
target: 'Location',
direction: 'out',
},
pinned: {
type: 'relationship',
relationship: 'PINNED',
target: 'Post',
direction: 'out',
properties: {
createdAt: { type: 'string', isoDate: true, default: () => new Date().toISOString() },
},
},
allowEmbedIframes: {
type: 'boolean',
default: false,

View File

@ -86,6 +86,7 @@ export default function Resolver(type, options = {}) {
}
return resolvers
}
const result = {
...undefinedToNullResolver(undefinedToNull),
...booleanResolver(boolean),

View File

@ -2,10 +2,9 @@ import uuid from 'uuid/v4'
import { neo4jgraphql } from 'neo4j-graphql-js'
import fileUpload from './fileUpload'
import { getBlockedUsers, getBlockedByUsers } from './users.js'
import { mergeWith, isArray } from 'lodash'
import { mergeWith, isArray, isEmpty } from 'lodash'
import { UserInputError } from 'apollo-server'
import Resolver from './helpers/Resolver'
const filterForBlockedUsers = async (params, context) => {
if (!context.user) return params
const [blockedUsers, blockedByUsers] = await Promise.all([
@ -29,16 +28,31 @@ const filterForBlockedUsers = async (params, context) => {
return params
}
const maintainPinnedPosts = params => {
const pinnedPostFilter = { pinnedBy_in: { role_in: ['admin'] } }
if (isEmpty(params.filter)) {
params.filter = { OR: [pinnedPostFilter, {}] }
} else {
params.filter = { OR: [pinnedPostFilter, { ...params.filter }] }
}
return params
}
export default {
Query: {
Post: async (object, params, context, resolveInfo) => {
params = await filterForBlockedUsers(params, context)
params = await maintainPinnedPosts(params)
return neo4jgraphql(object, params, context, resolveInfo, false)
},
findPosts: async (object, params, context, resolveInfo) => {
params = await filterForBlockedUsers(params, context)
return neo4jgraphql(object, params, context, resolveInfo, false)
},
profilePagePosts: async (object, params, context, resolveInfo) => {
params = await filterForBlockedUsers(params, context)
return neo4jgraphql(object, params, context, resolveInfo, false)
},
PostsEmotionsCountByEmotion: async (object, params, context, resolveInfo) => {
const session = context.driver.session()
const { postId, data } = params
@ -115,10 +129,10 @@ export default {
delete params.categoryIds
params = await fileUpload(params, { file: 'imageUpload', url: 'image' })
const session = context.driver.session()
let updatePostCypher = `MATCH (post:Post {id: $params.id})
SET post += $params
SET post.updatedAt = toString(datetime())
WITH post
`
if (categoryIds && categoryIds.length) {
@ -131,10 +145,10 @@ export default {
await session.run(cypherDeletePreviousRelations, { params })
updatePostCypher += `
WITH post
UNWIND $categoryIds AS categoryId
MATCH (category:Category {id: categoryId})
MERGE (post)-[:CATEGORIZED]->(category)
WITH post
`
}
@ -211,10 +225,78 @@ export default {
})
return emoted
},
pinPost: async (_parent, params, context, _resolveInfo) => {
let pinnedPostWithNestedAttributes
const { driver, user } = context
const session = driver.session()
const { id: userId } = user
let writeTxResultPromise = session.writeTransaction(async transaction => {
const deletePreviousRelationsResponse = await transaction.run(
`
MATCH (:User)-[previousRelations:PINNED]->(post:Post)
REMOVE post.pinned
DELETE previousRelations
RETURN post
`,
)
return deletePreviousRelationsResponse.records.map(record => record.get('post').properties)
})
await writeTxResultPromise
writeTxResultPromise = session.writeTransaction(async transaction => {
const pinPostTransactionResponse = await transaction.run(
`
MATCH (user:User {id: $userId}) WHERE user.role = 'admin'
MATCH (post:Post {id: $params.id})
MERGE (user)-[pinned:PINNED {createdAt: toString(datetime())}]->(post)
SET post.pinned = true
RETURN post, pinned.createdAt as pinnedAt
`,
{ userId, params },
)
return pinPostTransactionResponse.records.map(record => ({
pinnedPost: record.get('post').properties,
pinnedAt: record.get('pinnedAt'),
}))
})
try {
const [transactionResult] = await writeTxResultPromise
const { pinnedPost, pinnedAt } = transactionResult
pinnedPostWithNestedAttributes = {
...pinnedPost,
pinnedAt,
}
} finally {
session.close()
}
return pinnedPostWithNestedAttributes
},
unpinPost: async (_parent, params, context, _resolveInfo) => {
let unpinnedPost
const session = context.driver.session()
const writeTxResultPromise = session.writeTransaction(async transaction => {
const unpinPostTransactionResponse = await transaction.run(
`
MATCH (:User)-[previousRelations:PINNED]->(post:Post {id: $params.id})
REMOVE post.pinned
DELETE previousRelations
RETURN post
`,
{ params },
)
return unpinPostTransactionResponse.records.map(record => record.get('post').properties)
})
try {
;[unpinnedPost] = await writeTxResultPromise
} finally {
session.close()
}
return unpinnedPost
},
},
Post: {
...Resolver('Post', {
undefinedToNull: ['activityId', 'objectId', 'image', 'language'],
undefinedToNull: ['activityId', 'objectId', 'image', 'language', 'pinnedAt', 'pinned'],
hasMany: {
tags: '-[:TAGGED]->(related:Tag)',
categories: '-[:CATEGORIZED]->(related:Category)',
@ -225,6 +307,7 @@ export default {
hasOne: {
author: '<-[:WROTE]-(related:User)',
disabledBy: '<-[:DISABLED]-(related:User)',
pinnedBy: '<-[:PINNED]-(related:User)',
},
count: {
commentsCount:

View File

@ -39,7 +39,8 @@ const createPostMutation = gql`
}
`
beforeAll(() => {
beforeAll(async () => {
await factory.cleanDatabase()
const { server } = createServer({
context: () => {
return {
@ -269,7 +270,10 @@ describe('CreatePost', () => {
})
it('creates a post', async () => {
const expected = { data: { CreatePost: { title: 'I am a title', content: 'Some content' } } }
const expected = {
data: { CreatePost: { title: 'I am a title', content: 'Some content' } },
errors: undefined,
}
await expect(mutate({ mutation: createPostMutation, variables })).resolves.toMatchObject(
expected,
)
@ -285,6 +289,7 @@ describe('CreatePost', () => {
},
},
},
errors: undefined,
}
await expect(mutate({ mutation: createPostMutation, variables })).resolves.toMatchObject(
expected,
@ -366,7 +371,12 @@ describe('UpdatePost', () => {
mutation($id: ID!, $title: String!, $content: String!, $categoryIds: [ID]) {
UpdatePost(id: $id, title: $title, content: $content, categoryIds: $categoryIds) {
id
title
content
author {
name
slug
}
categories {
id
}
@ -386,7 +396,6 @@ describe('UpdatePost', () => {
})
variables = {
...variables,
id: 'p9876',
title: 'New title',
content: 'New content',
@ -395,8 +404,11 @@ describe('UpdatePost', () => {
describe('unauthenticated', () => {
it('throws authorization error', async () => {
const { errors } = await mutate({ mutation: updatePostMutation, variables })
expect(errors[0]).toHaveProperty('message', 'Not Authorised!')
authenticatedUser = null
expect(mutate({ mutation: updatePostMutation, variables })).resolves.toMatchObject({
errors: [{ message: 'Not Authorised!' }],
data: { UpdatePost: null },
})
})
})
@ -550,6 +562,399 @@ describe('UpdatePost', () => {
})
})
})
describe('pin posts', () => {
const pinPostMutation = gql`
mutation($id: ID!) {
pinPost(id: $id) {
id
title
content
author {
name
slug
}
pinnedBy {
id
name
role
}
createdAt
updatedAt
pinnedAt
pinned
}
}
`
beforeEach(async () => {
variables = { ...variables }
})
describe('unauthenticated', () => {
it('throws authorization error', async () => {
authenticatedUser = null
await expect(mutate({ mutation: pinPostMutation, variables })).resolves.toMatchObject({
errors: [{ message: 'Not Authorised!' }],
data: { pinPost: null },
})
})
})
describe('ordinary users', () => {
it('throws authorization error', async () => {
await expect(mutate({ mutation: pinPostMutation, variables })).resolves.toMatchObject({
errors: [{ message: 'Not Authorised!' }],
data: { pinPost: null },
})
})
})
describe('moderators', () => {
let moderator
beforeEach(async () => {
moderator = await user.update({ role: 'moderator', updatedAt: new Date().toISOString() })
authenticatedUser = await moderator.toJson()
})
it('throws authorization error', async () => {
await expect(mutate({ mutation: pinPostMutation, variables })).resolves.toMatchObject({
errors: [{ message: 'Not Authorised!' }],
data: { pinPost: null },
})
})
})
describe('admins', () => {
let admin
beforeEach(async () => {
admin = await user.update({
role: 'admin',
name: 'Admin',
updatedAt: new Date().toISOString(),
})
authenticatedUser = await admin.toJson()
})
describe('are allowed to pin posts', () => {
beforeEach(async () => {
await factory.create('Post', {
id: 'created-and-pinned-by-same-admin',
author: admin,
})
variables = { ...variables, id: 'created-and-pinned-by-same-admin' }
})
it('responds with the updated Post', async () => {
const expected = {
data: {
pinPost: {
id: 'created-and-pinned-by-same-admin',
author: {
name: 'Admin',
},
pinnedBy: {
id: 'current-user',
name: 'Admin',
role: 'admin',
},
},
},
errors: undefined,
}
await expect(mutate({ mutation: pinPostMutation, variables })).resolves.toMatchObject(
expected,
)
})
it('sets createdAt date for PINNED', async () => {
const expected = {
data: {
pinPost: {
id: 'created-and-pinned-by-same-admin',
pinnedAt: expect.any(String),
},
},
errors: undefined,
}
await expect(mutate({ mutation: pinPostMutation, variables })).resolves.toMatchObject(
expected,
)
})
it('sets redundant `pinned` property for performant ordering', async () => {
variables = { ...variables, id: 'created-and-pinned-by-same-admin' }
const expected = {
data: { pinPost: { pinned: true } },
errors: undefined,
}
await expect(mutate({ mutation: pinPostMutation, variables })).resolves.toMatchObject(
expected,
)
})
})
describe('post created by another admin', () => {
let otherAdmin
beforeEach(async () => {
otherAdmin = await factory.create('User', {
role: 'admin',
name: 'otherAdmin',
})
authenticatedUser = await otherAdmin.toJson()
await factory.create('Post', {
id: 'created-by-one-admin-pinned-by-different-one',
author: otherAdmin,
})
})
it('responds with the updated Post', async () => {
authenticatedUser = await admin.toJson()
variables = { ...variables, id: 'created-by-one-admin-pinned-by-different-one' }
const expected = {
data: {
pinPost: {
id: 'created-by-one-admin-pinned-by-different-one',
author: {
name: 'otherAdmin',
},
pinnedBy: {
id: 'current-user',
name: 'Admin',
role: 'admin',
},
},
},
errors: undefined,
}
await expect(mutate({ mutation: pinPostMutation, variables })).resolves.toMatchObject(
expected,
)
})
})
describe('post created by another user', () => {
it('responds with the updated Post', async () => {
const expected = {
data: {
pinPost: {
id: 'p9876',
author: {
slug: 'the-author',
},
pinnedBy: {
id: 'current-user',
name: 'Admin',
role: 'admin',
},
},
},
errors: undefined,
}
await expect(mutate({ mutation: pinPostMutation, variables })).resolves.toMatchObject(
expected,
)
})
})
describe('pinned post already exists', () => {
let pinnedPost
beforeEach(async () => {
await factory.create('Post', {
id: 'only-pinned-post',
author: admin,
})
await mutate({ mutation: pinPostMutation, variables })
})
it('removes previous `pinned` attribute', async () => {
const cypher = 'MATCH (post:Post) WHERE post.pinned IS NOT NULL RETURN post'
pinnedPost = await neode.cypher(cypher)
expect(pinnedPost.records).toHaveLength(1)
variables = { ...variables, id: 'only-pinned-post' }
await mutate({ mutation: pinPostMutation, variables })
pinnedPost = await neode.cypher(cypher)
expect(pinnedPost.records).toHaveLength(1)
})
it('removes previous PINNED relationship', async () => {
variables = { ...variables, id: 'only-pinned-post' }
await mutate({ mutation: pinPostMutation, variables })
pinnedPost = await neode.cypher(
`MATCH (:User)-[pinned:PINNED]->(post:Post) RETURN post, pinned`,
)
expect(pinnedPost.records).toHaveLength(1)
})
})
describe('PostOrdering', () => {
let pinnedPost, admin
beforeEach(async () => {
;[pinnedPost] = await Promise.all([
neode.create('Post', {
id: 'im-a-pinned-post',
pinned: true,
}),
neode.create('Post', {
id: 'i-was-created-after-pinned-post',
createdAt: '2019-10-22T17:26:29.070Z', // this should always be 3rd
}),
])
admin = await user.update({
role: 'admin',
name: 'Admin',
updatedAt: new Date().toISOString(),
})
await admin.relateTo(pinnedPost, 'pinned')
})
it('pinned post appear first even when created before other posts', async () => {
const postOrderingQuery = gql`
query($orderBy: [_PostOrdering]) {
Post(orderBy: $orderBy) {
id
pinnedAt
}
}
`
const expected = {
data: {
Post: [
{
id: 'im-a-pinned-post',
pinnedAt: expect.any(String),
},
{
id: 'p9876',
pinnedAt: null,
},
{
id: 'i-was-created-after-pinned-post',
pinnedAt: null,
},
],
},
}
variables = { orderBy: ['pinned_desc', 'createdAt_desc'] }
await expect(query({ query: postOrderingQuery, variables })).resolves.toMatchObject(
expected,
)
})
})
})
})
describe('unpin posts', () => {
const unpinPostMutation = gql`
mutation($id: ID!) {
unpinPost(id: $id) {
id
title
content
author {
name
slug
}
pinnedBy {
id
name
role
}
createdAt
updatedAt
pinned
pinnedAt
}
}
`
beforeEach(async () => {
variables = { ...variables }
})
describe('unauthenticated', () => {
it('throws authorization error', async () => {
authenticatedUser = null
await expect(mutate({ mutation: unpinPostMutation, variables })).resolves.toMatchObject({
errors: [{ message: 'Not Authorised!' }],
data: { unpinPost: null },
})
})
})
describe('users cannot unpin posts', () => {
it('throws authorization error', async () => {
await expect(mutate({ mutation: unpinPostMutation, variables })).resolves.toMatchObject({
errors: [{ message: 'Not Authorised!' }],
data: { unpinPost: null },
})
})
})
describe('moderators cannot unpin posts', () => {
let moderator
beforeEach(async () => {
moderator = await user.update({ role: 'moderator', updatedAt: new Date().toISOString() })
authenticatedUser = await moderator.toJson()
})
it('throws authorization error', async () => {
await expect(mutate({ mutation: unpinPostMutation, variables })).resolves.toMatchObject({
errors: [{ message: 'Not Authorised!' }],
data: { unpinPost: null },
})
})
})
describe('admin can unpin posts', () => {
let admin, pinnedPost
beforeEach(async () => {
pinnedPost = await factory.create('Post', { id: 'post-to-be-unpinned' })
admin = await user.update({
role: 'admin',
name: 'Admin',
updatedAt: new Date().toISOString(),
})
authenticatedUser = await admin.toJson()
await admin.relateTo(pinnedPost, 'pinned', { createdAt: new Date().toISOString() })
variables = { ...variables, id: 'post-to-be-unpinned' }
})
it('responds with the unpinned Post', async () => {
authenticatedUser = await admin.toJson()
const expected = {
data: {
unpinPost: {
id: 'post-to-be-unpinned',
pinnedBy: null,
pinnedAt: null,
},
},
errors: undefined,
}
await expect(mutate({ mutation: unpinPostMutation, variables })).resolves.toMatchObject(
expected,
)
})
it('unsets `pinned` property', async () => {
const expected = {
data: {
unpinPost: {
id: 'post-to-be-unpinned',
pinned: null,
},
},
errors: undefined,
}
await expect(mutate({ mutation: unpinPostMutation, variables })).resolves.toMatchObject(
expected,
)
})
})
})
})
describe('DeletePost', () => {

File diff suppressed because it is too large Load Diff

View File

@ -1,3 +1,37 @@
enum _PostOrdering {
id_asc
id_desc
activityId_asc
activityId_desc
objectId_asc
objectId_desc
title_asc
title_desc
slug_asc
slug_desc
content_asc
content_desc
contentExcerpt_asc
contentExcerpt_desc
image_asc
image_desc
visibility_asc
visibility_desc
deleted_asc
deleted_desc
disabled_asc
disabled_desc
createdAt_asc
createdAt_desc
updatedAt_asc
updatedAt_desc
language_asc
language_desc
pinned_asc
pinned_desc
}
type Post {
id: ID!
activityId: String
@ -12,10 +46,15 @@ type Post {
visibility: Visibility
deleted: Boolean
disabled: Boolean
pinned: Boolean
disabledBy: User @relation(name: "DISABLED", direction: "IN")
createdAt: String
updatedAt: String
language: String
pinnedAt: String @cypher(
statement: "MATCH (this)<-[pinned:PINNED]-(:User) WHERE NOT this.deleted = true AND NOT this.disabled = true RETURN pinned.createdAt"
)
pinnedBy: User @relation(name:"PINNED", direction: "IN")
relatedContributions: [Post]!
@cypher(
statement: """
@ -40,7 +79,7 @@ type Post {
@cypher(
statement: "MATCH (this)<-[:SHOUTED]-(r:User) WHERE NOT r.deleted = true AND NOT r.disabled = true RETURN COUNT(DISTINCT r)"
)
# Has the currently logged in user shouted that post?
shoutedByCurrentUser: Boolean!
@cypher(
@ -84,9 +123,12 @@ type Mutation {
DeletePost(id: ID!): Post
AddPostEmotions(to: _PostInput!, data: _EMOTEDInput!): EMOTED
RemovePostEmotions(to: _PostInput!, data: _EMOTEDInput!): EMOTED
pinPost(id: ID!): Post
unpinPost(id: ID!): Post
}
type Query {
PostsEmotionsCountByEmotion(postId: ID!, data: _EMOTEDInput!): Int!
PostsEmotionsByCurrentUser(postId: ID!): [String]
profilePagePosts(filter: _PostFilter, first: Int, offset: Int, orderBy: [_PostOrdering]): [Post]
}

View File

@ -1,182 +1,181 @@
type User {
id: ID!
actorId: String
name: String
email: String! @cypher(statement: "MATCH (this)-[: PRIMARY_EMAIL]->(e: EmailAddress) RETURN e.email")
slug: String!
avatar: String
coverImg: String
deleted: Boolean
disabled: Boolean
disabledBy: User @relation(name: "DISABLED", direction: "IN")
role: UserGroup!
publicKey: String
invitedBy: User @relation(name: "INVITED", direction: "IN")
invited: [User] @relation(name: "INVITED", direction: "OUT")
id: ID!
actorId: String
name: String
email: String! @cypher(statement: "MATCH (this)-[: PRIMARY_EMAIL]->(e: EmailAddress) RETURN e.email")
slug: String!
avatar: String
coverImg: String
deleted: Boolean
disabled: Boolean
disabledBy: User @relation(name: "DISABLED", direction: "IN")
role: UserGroup!
publicKey: String
invitedBy: User @relation(name: "INVITED", direction: "IN")
invited: [User] @relation(name: "INVITED", direction: "OUT")
location: Location @cypher(statement: "MATCH (this)-[: IS_IN]->(l: Location) RETURN l")
locationName: String
about: String
socialMedia: [SocialMedia]! @relation(name: "OWNED_BY", direction: "IN")
location: Location @cypher(statement: "MATCH (this)-[: IS_IN]->(l: Location) RETURN l")
locationName: String
about: String
socialMedia: [SocialMedia]! @relation(name: "OWNED_BY", direction: "IN")
# createdAt: DateTime
# updatedAt: DateTime
createdAt: String
updatedAt: String
# createdAt: DateTime
# updatedAt: DateTime
createdAt: String
updatedAt: String
termsAndConditionsAgreedVersion: String
termsAndConditionsAgreedAt: String
termsAndConditionsAgreedVersion: String
termsAndConditionsAgreedAt: String
allowEmbedIframes: Boolean
allowEmbedIframes: Boolean
locale: String
friends: [User]! @relation(name: "FRIENDS", direction: "BOTH")
friendsCount: Int! @cypher(statement: "MATCH (this)<-[: FRIENDS]->(r: User) RETURN COUNT(DISTINCT r)")
locale: String
following: [User]! @relation(name: "FOLLOWS", direction: "OUT")
followingCount: Int! @cypher(statement: "MATCH (this)-[: FOLLOWS]->(r: User) RETURN COUNT(DISTINCT r)")
friends: [User]! @relation(name: "FRIENDS", direction: "BOTH")
friendsCount: Int! @cypher(statement: "MATCH (this)<-[: FRIENDS]->(r: User) RETURN COUNT(DISTINCT r)")
followedBy: [User]! @relation(name: "FOLLOWS", direction: "IN")
followedByCount: Int! @cypher(statement: "MATCH (this)<-[: FOLLOWS]-(r: User) RETURN COUNT(DISTINCT r)")
following: [User]! @relation(name: "FOLLOWS", direction: "OUT")
followingCount: Int! @cypher(statement: "MATCH (this)-[: FOLLOWS]->(r: User) RETURN COUNT(DISTINCT r)")
# Is the currently logged in user following that user?
followedByCurrentUser: Boolean! @cypher(
statement: """
MATCH (this)<-[: FOLLOWS]-(u: User { id: $cypherParams.currentUserId})
RETURN COUNT(u) >= 1
"""
)
isBlocked: Boolean! @cypher(
statement: """
MATCH (this)<-[: BLOCKED]-(u: User { id: $cypherParams.currentUserId})
RETURN COUNT(u) >= 1
"""
)
followedBy: [User]! @relation(name: "FOLLOWS", direction: "IN")
followedByCount: Int! @cypher(statement: "MATCH (this)<-[: FOLLOWS]-(r: User) RETURN COUNT(DISTINCT r)")
# contributions: [WrittenPost]!
# contributions2(first: Int = 10, offset: Int = 0): [WrittenPost2]!
# @cypher(
# statement: "MATCH (this)-[w:WROTE]->(p:Post) RETURN p as Post, w.timestamp as timestamp"
# )
contributions: [Post]! @relation(name: "WROTE", direction: "OUT")
contributionsCount: Int! @cypher(
statement: """
MATCH (this)-[: WROTE]->(r: Post)
WHERE NOT r.deleted = true AND NOT r.disabled = true
RETURN COUNT(r)
"""
)
# Is the currently logged in user following that user?
followedByCurrentUser: Boolean! @cypher(
statement: """
MATCH (this)<-[: FOLLOWS]-(u: User { id: $cypherParams.currentUserId})
RETURN COUNT(u) >= 1
"""
)
isBlocked: Boolean! @cypher(
statement: """
MATCH (this)<-[: BLOCKED]-(u: User { id: $cypherParams.currentUserId})
RETURN COUNT(u) >= 1
"""
)
comments: [Comment]! @relation(name: "WROTE", direction: "OUT")
commentedCount: Int! @cypher(statement: "MATCH (this)-[: WROTE]->(: Comment)-[: COMMENTS]->(p: Post) WHERE NOT p.deleted = true AND NOT p.disabled = true RETURN COUNT(DISTINCT(p))")
# contributions: [WrittenPost]!
# contributions2(first: Int = 10, offset: Int = 0): [WrittenPost2]!
# @cypher(
# statement: "MATCH (this)-[w:WROTE]->(p:Post) RETURN p as Post, w.timestamp as timestamp"
# )
contributions: [Post]! @relation(name: "WROTE", direction: "OUT")
contributionsCount: Int! @cypher(
statement: """
MATCH (this)-[: WROTE]->(r: Post)
WHERE NOT r.deleted = true AND NOT r.disabled = true
RETURN COUNT(r)
"""
)
shouted: [Post]! @relation(name: "SHOUTED", direction: "OUT")
shoutedCount: Int! @cypher(statement: "MATCH (this)-[: SHOUTED]->(r: Post) WHERE NOT r.deleted = true AND NOT r.disabled = true RETURN COUNT(DISTINCT r)")
comments: [Comment]! @relation(name: "WROTE", direction: "OUT")
commentedCount: Int! @cypher(statement: "MATCH (this)-[: WROTE]->(: Comment)-[: COMMENTS]->(p: Post) WHERE NOT p.deleted = true AND NOT p.disabled = true RETURN COUNT(DISTINCT(p))")
categories: [Category]! @relation(name: "CATEGORIZED", direction: "OUT")
shouted: [Post]! @relation(name: "SHOUTED", direction: "OUT")
shoutedCount: Int! @cypher(statement: "MATCH (this)-[: SHOUTED]->(r: Post) WHERE NOT r.deleted = true AND NOT r.disabled = true RETURN COUNT(DISTINCT r)")
badges: [Badge]! @relation(name: "REWARDED", direction: "IN")
badgesCount: Int! @cypher(statement: "MATCH (this)<-[: REWARDED]-(r: Badge) RETURN COUNT(r)")
categories: [Category]! @relation(name: "CATEGORIZED", direction: "OUT")
badges: [Badge]! @relation(name: "REWARDED", direction: "IN")
badgesCount: Int! @cypher(statement: "MATCH (this)<-[: REWARDED]-(r: Badge) RETURN COUNT(r)")
emotions: [EMOTED]
emotions: [EMOTED]
}
input _UserFilter {
AND: [_UserFilter!]
OR: [_UserFilter!]
name_contains: String
about_contains: String
slug_contains: String
id: ID
id_not: ID
id_in: [ID!]
id_not_in: [ID!]
id_contains: ID
id_not_contains: ID
id_starts_with: ID
id_not_starts_with: ID
id_ends_with: ID
id_not_ends_with: ID
friends: _UserFilter
friends_not: _UserFilter
friends_in: [_UserFilter!]
friends_not_in: [_UserFilter!]
friends_some: _UserFilter
friends_none: _UserFilter
friends_single: _UserFilter
friends_every: _UserFilter
following: _UserFilter
following_not: _UserFilter
following_in: [_UserFilter!]
following_not_in: [_UserFilter!]
following_some: _UserFilter
following_none: _UserFilter
following_single: _UserFilter
following_every: _UserFilter
followedBy: _UserFilter
followedBy_not: _UserFilter
followedBy_in: [_UserFilter!]
followedBy_not_in: [_UserFilter!]
followedBy_some: _UserFilter
followedBy_none: _UserFilter
followedBy_single: _UserFilter
followedBy_every: _UserFilter
AND: [_UserFilter!]
OR: [_UserFilter!]
name_contains: String
about_contains: String
slug_contains: String
id: ID
id_not: ID
id_in: [ID!]
id_not_in: [ID!]
id_contains: ID
id_not_contains: ID
id_starts_with: ID
id_not_starts_with: ID
id_ends_with: ID
id_not_ends_with: ID
friends: _UserFilter
friends_not: _UserFilter
friends_in: [_UserFilter!]
friends_not_in: [_UserFilter!]
friends_some: _UserFilter
friends_none: _UserFilter
friends_single: _UserFilter
friends_every: _UserFilter
following: _UserFilter
following_not: _UserFilter
following_in: [_UserFilter!]
following_not_in: [_UserFilter!]
following_some: _UserFilter
following_none: _UserFilter
following_single: _UserFilter
following_every: _UserFilter
followedBy: _UserFilter
followedBy_not: _UserFilter
followedBy_in: [_UserFilter!]
followedBy_not_in: [_UserFilter!]
followedBy_some: _UserFilter
followedBy_none: _UserFilter
followedBy_single: _UserFilter
followedBy_every: _UserFilter
role_in: [UserGroup!]
}
type Query {
User(
id: ID
email: String
actorId: String
name: String
slug: String
avatar: String
coverImg: String
role: UserGroup
locationName: String
about: String
createdAt: String
updatedAt: String
friendsCount: Int
followingCount: Int
followedByCount: Int
followedByCurrentUser: Boolean
contributionsCount: Int
commentedCount: Int
shoutedCount: Int
badgesCount: Int
first: Int
offset: Int
orderBy: [_UserOrdering]
filter: _UserFilter
): [User]
User(
id: ID
email: String
actorId: String
name: String
slug: String
avatar: String
coverImg: String
role: UserGroup
locationName: String
about: String
createdAt: String
updatedAt: String
friendsCount: Int
followingCount: Int
followedByCount: Int
followedByCurrentUser: Boolean
contributionsCount: Int
commentedCount: Int
shoutedCount: Int
badgesCount: Int
first: Int
offset: Int
orderBy: [_UserOrdering]
filter: _UserFilter
): [User]
blockedUsers: [User]
currentUser: User
blockedUsers: [User]
currentUser: User
}
type Mutation {
UpdateUser (
id: ID!
name: String
email: String
slug: String
avatar: String
coverImg: String
avatarUpload: Upload
locationName: String
about: String
termsAndConditionsAgreedVersion: String
termsAndConditionsAgreedAt: String
allowEmbedIframes: Boolean
UpdateUser (
id: ID!
name: String
email: String
slug: String
avatar: String
coverImg: String
avatarUpload: Upload
locationName: String
about: String
termsAndConditionsAgreedVersion: String
termsAndConditionsAgreedAt: String
allowEmbedIframes: Boolean
locale: String
): User
): User
DeleteUser(id: ID!, resource: [Deletable]): User
DeleteUser(id: ID!, resource: [Deletable]): User
block(id: ID!): User
unblock(id: ID!): User
block(id: ID!): User
unblock(id: ID!): User
}

View File

@ -1042,60 +1042,60 @@
resolved "https://registry.yarnpkg.com/@protobufjs/utf8/-/utf8-1.1.0.tgz#a777360b5b39a1a2e5106f8e858f2fd2d060c570"
integrity sha1-p3c2C1s5oaLlEG+OhY8v0tBgxXA=
"@sentry/core@5.7.0":
version "5.7.0"
resolved "https://registry.yarnpkg.com/@sentry/core/-/core-5.7.0.tgz#c2aa5341e703ec7cf2acc69e51971a0b1f7d102a"
integrity sha512-gQel0d7LBSWJGHc7gfZllYAu+RRGD9GcYGmkRfemurmDyDGQDf/sfjiBi8f9QxUc2iFTHnvIR5nMTyf0U3yl3Q==
"@sentry/core@5.7.1":
version "5.7.1"
resolved "https://registry.yarnpkg.com/@sentry/core/-/core-5.7.1.tgz#3eb2b7662cac68245931ee939ec809bf7a639d0e"
integrity sha512-AOn3k3uVWh2VyajcHbV9Ta4ieDIeLckfo7UMLM+CTk2kt7C89SayDGayJMSsIrsZlL4qxBoLB9QY4W2FgAGJrg==
dependencies:
"@sentry/hub" "5.7.0"
"@sentry/minimal" "5.7.0"
"@sentry/types" "5.7.0"
"@sentry/utils" "5.7.0"
"@sentry/hub" "5.7.1"
"@sentry/minimal" "5.7.1"
"@sentry/types" "5.7.1"
"@sentry/utils" "5.7.1"
tslib "^1.9.3"
"@sentry/hub@5.7.0":
version "5.7.0"
resolved "https://registry.yarnpkg.com/@sentry/hub/-/hub-5.7.0.tgz#f7c356202a9db1daae82ce7f48ebf1139e4e9d02"
integrity sha512-qNdYheJ6j4P9Sk0eqIINpJohImmu/+trCwFb4F8BGLQth5iGMVQD6D0YUrgjf4ZaQwfhw9tv4W6VEfF5tyASoA==
"@sentry/hub@5.7.1":
version "5.7.1"
resolved "https://registry.yarnpkg.com/@sentry/hub/-/hub-5.7.1.tgz#a52acd9fead7f3779d96e9965c6978aecc8b9cad"
integrity sha512-evGh323WR073WSBCg/RkhlUmCQyzU0xzBzCZPscvcoy5hd4SsLE6t9Zin+WACHB9JFsRQIDwNDn+D+pj3yKsig==
dependencies:
"@sentry/types" "5.7.0"
"@sentry/utils" "5.7.0"
"@sentry/types" "5.7.1"
"@sentry/utils" "5.7.1"
tslib "^1.9.3"
"@sentry/minimal@5.7.0":
version "5.7.0"
resolved "https://registry.yarnpkg.com/@sentry/minimal/-/minimal-5.7.0.tgz#832d26bcd862c6ea628d48ad199ac7f966a2d907"
integrity sha512-0sizE2prS9nmfLyVUKmVzFFFqRNr9iorSCCejwnlRe3crqKqjf84tuRSzm6NkZjIyYj9djuuo9l9XN12NLQ/4A==
"@sentry/minimal@5.7.1":
version "5.7.1"
resolved "https://registry.yarnpkg.com/@sentry/minimal/-/minimal-5.7.1.tgz#56afc537737586929e25349765e37a367958c1e1"
integrity sha512-nS/Dg+jWAZtcxQW8wKbkkw4dYvF6uyY/vDiz/jFCaux0LX0uhgXAC9gMOJmgJ/tYBLJ64l0ca5LzpZa7BMJQ0g==
dependencies:
"@sentry/hub" "5.7.0"
"@sentry/types" "5.7.0"
"@sentry/hub" "5.7.1"
"@sentry/types" "5.7.1"
tslib "^1.9.3"
"@sentry/node@^5.7.0":
version "5.7.0"
resolved "https://registry.yarnpkg.com/@sentry/node/-/node-5.7.0.tgz#153777f06b2fcd346edbff9adbb6b231c7e5fa0a"
integrity sha512-iqQbGAJDBlpQkp1rl9RkDCIfnukr4cOtHPgJPmLY19m/KXIHD2cdKhvbqoCvIPBTIAeSGQIvDT9jD5zT46eoqQ==
"@sentry/node@^5.7.1":
version "5.7.1"
resolved "https://registry.yarnpkg.com/@sentry/node/-/node-5.7.1.tgz#94e2fbac94f6cc061be3bc14b22813536c59698d"
integrity sha512-hVM10asFStrOhYZzMqFM7V1lrHkr1ydc2n/SFG0ZmIQxfTjCVElyXV/BJASIdqadM1fFIvvtD/EfgkTcZmub1g==
dependencies:
"@sentry/core" "5.7.0"
"@sentry/hub" "5.7.0"
"@sentry/types" "5.7.0"
"@sentry/utils" "5.7.0"
"@sentry/core" "5.7.1"
"@sentry/hub" "5.7.1"
"@sentry/types" "5.7.1"
"@sentry/utils" "5.7.1"
cookie "^0.3.1"
https-proxy-agent "^3.0.0"
lru_map "^0.3.3"
tslib "^1.9.3"
"@sentry/types@5.7.0":
version "5.7.0"
resolved "https://registry.yarnpkg.com/@sentry/types/-/types-5.7.0.tgz#e8677e57b40c2c63cad42c02add12b238e647c10"
integrity sha512-bFRVortg713dE2yJXNFgNe6sNBVVSkpoELLkGPatdVQi0dYc6OggIIX4UZZvkynFx72GwYqO1NOrtUcJY2gmMg==
"@sentry/types@5.7.1":
version "5.7.1"
resolved "https://registry.yarnpkg.com/@sentry/types/-/types-5.7.1.tgz#4c4c1d4d891b6b8c2c3c7b367d306a8b1350f090"
integrity sha512-tbUnTYlSliXvnou5D4C8Zr+7/wJrHLbpYX1YkLXuIJRU0NSi81bHMroAuHWILcQKWhVjaV/HZzr7Y/hhWtbXVQ==
"@sentry/utils@5.7.0":
version "5.7.0"
resolved "https://registry.yarnpkg.com/@sentry/utils/-/utils-5.7.0.tgz#a6850aa4f5476fa26517cd5c6248f871d8d9939b"
integrity sha512-XmwQpLqea9mj8x1N7P/l4JvnEb0Rn5Py5OtBgl0ctk090W+GB1uM8rl9mkMf6698o1s1Z8T/tI/QY0yFA5uZXg==
"@sentry/utils@5.7.1":
version "5.7.1"
resolved "https://registry.yarnpkg.com/@sentry/utils/-/utils-5.7.1.tgz#cf37ad55f78e317665cd8680f202d307fa77f1d0"
integrity sha512-nhirUKj/qFLsR1i9kJ5BRvNyzdx/E2vorIsukuDrbo8e3iZ11JMgCOVrmC8Eq9YkHBqgwX4UnrPumjFyvGMZ2Q==
dependencies:
"@sentry/types" "5.7.0"
"@sentry/types" "5.7.1"
tslib "^1.9.3"
"@sindresorhus/is@^0.14.0":
@ -3259,10 +3259,10 @@ eslint-plugin-import@~2.18.2:
read-pkg-up "^2.0.0"
resolve "^1.11.0"
eslint-plugin-jest@~22.19.0:
version "22.19.0"
resolved "https://registry.yarnpkg.com/eslint-plugin-jest/-/eslint-plugin-jest-22.19.0.tgz#0cf90946a8c927d40a2c64458c89bb635d0f2a0b"
integrity sha512-4zUc3rh36ds0SXdl2LywT4YWA3zRe8sfLhz8bPp8qQPIKvynTTkNGwmSCMpl5d9QiZE2JxSinGF+WD8yU+O0Lg==
eslint-plugin-jest@~22.20.0:
version "22.20.0"
resolved "https://registry.yarnpkg.com/eslint-plugin-jest/-/eslint-plugin-jest-22.20.0.tgz#a3c3615c516fcbd20d50dbf395ea37361bd9e3b2"
integrity sha512-UwHGXaYprxwd84Wer8H7jZS+5C3LeEaU8VD7NqORY6NmPJrs+9Ugbq3wyjqO3vWtSsDaLar2sqEB8COmOZA4zw==
dependencies:
"@typescript-eslint/experimental-utils" "^1.13.0"
@ -3594,7 +3594,8 @@ extsprintf@^1.2.0:
faker@Marak/faker.js#master:
version "4.1.0"
resolved "https://codeload.github.com/Marak/faker.js/tar.gz/10bfb9f467b0ac2b8912ffc15690b50ef3244f09"
uid "9fd8d7d37b398842d0784a116a340f7aa6afb89b"
resolved "https://codeload.github.com/Marak/faker.js/tar.gz/9fd8d7d37b398842d0784a116a340f7aa6afb89b"
fast-deep-equal@^2.0.1:
version "2.0.1"

View File

@ -26,7 +26,7 @@
"cypress-cucumber-preprocessor": "^1.16.2",
"cypress-file-upload": "^3.4.0",
"cypress-plugin-retries": "^1.3.0",
"date-fns": "^2.5.0",
"date-fns": "^2.5.1",
"dotenv": "^8.2.0",
"faker": "Marak/faker.js#master",
"graphql-request": "^1.8.2",

View File

@ -1,4 +1,4 @@
FROM node:12.12.0-alpine as base
FROM node:12.13.0-alpine as base
LABEL Description="Web Frontend of the Social Network Human-Connection.org" Vendor="Human-Connection gGmbH" Version="0.0.1" Maintainer="Human-Connection gGmbH (developer@human-connection.org)"
EXPOSE 3000

View File

@ -1,4 +1,4 @@
FROM node:12.12.0-alpine as build
FROM node:12.13.0-alpine as build
LABEL Description="Web Frontend of the Social Network Human-Connection.org" Vendor="Human-Connection gGmbH" Version="0.0.1" Maintainer="Human-Connection gGmbH (developer@human-connection.org)"
EXPOSE 3000

View File

@ -149,6 +149,7 @@ export default {
},
editCommentMenu(showMenu) {
this.openEditCommentMenu = showMenu
this.$emit('toggleNewCommentForm', !showMenu)
},
updateComment(comment) {
this.$emit('updateComment', comment)

View File

@ -0,0 +1,45 @@
import { storiesOf } from '@storybook/vue'
import { withA11y } from '@storybook/addon-a11y'
import HcCommentList from './CommentList.vue'
import helpers from '~/storybook/helpers'
import faker from 'faker'
helpers.init()
const commentMock = fields => {
return {
id: faker.random.uuid(),
title: faker.lorem.sentence(),
content: faker.lorem.paragraph(),
createdAt: faker.date.past(),
updatedAt: faker.date.recent(),
deleted: false,
disabled: false,
...fields,
}
}
const comments = [
commentMock(),
commentMock(),
commentMock(),
commentMock(),
commentMock(),
commentMock(),
commentMock(),
commentMock(),
commentMock(),
commentMock(),
]
storiesOf('CommentList', module)
.addDecorator(withA11y)
.addDecorator(helpers.layout)
.add('given 10 comments', () => ({
components: { HcCommentList },
store: helpers.store,
data: () => ({
post: { comments },
}),
template: `<hc-comment-list :post="post" />`,
}))

View File

@ -25,6 +25,7 @@
:routeHash="routeHash"
@deleteComment="updateCommentList"
@updateComment="updateCommentList"
@toggleNewCommentForm="toggleNewCommentForm"
/>
</div>
</div>
@ -51,6 +52,9 @@ export default {
return comment.id === updatedComment.id ? updatedComment : comment
})
},
toggleNewCommentForm(showNewCommentForm) {
this.$emit('toggleNewCommentForm', showNewCommentForm)
},
},
}
</script>

View File

@ -55,24 +55,46 @@ export default {
routes() {
let routes = []
if (this.isOwner && this.resourceType === 'contribution') {
routes.push({
name: this.$t(`post.menu.edit`),
path: this.$router.resolve({
name: 'post-edit-id',
params: {
id: this.resource.id,
if (this.resourceType === 'contribution') {
if (this.isOwner) {
routes.push({
name: this.$t(`post.menu.edit`),
path: this.$router.resolve({
name: 'post-edit-id',
params: {
id: this.resource.id,
},
}).href,
icon: 'edit',
})
routes.push({
name: this.$t(`post.menu.delete`),
callback: () => {
this.openModal('delete')
},
}).href,
icon: 'edit',
})
routes.push({
name: this.$t(`post.menu.delete`),
callback: () => {
this.openModal('delete')
},
icon: 'trash',
})
icon: 'trash',
})
}
if (this.isAdmin) {
if (!this.resource.pinnedBy) {
routes.push({
name: this.$t(`post.menu.pin`),
callback: () => {
this.$emit('pinPost', this.resource)
},
icon: 'link',
})
} else {
routes.push({
name: this.$t(`post.menu.unpin`),
callback: () => {
this.$emit('unpinPost', this.resource)
},
icon: 'unlink',
})
}
}
}
if (this.isOwner && this.resourceType === 'comment') {
@ -155,6 +177,9 @@ export default {
isModerator() {
return this.$store.getters['auth/isModerator']
},
isAdmin() {
return this.$store.getters['auth/isAdmin']
},
},
methods: {
openItem(route, toggleMenu) {

View File

@ -67,13 +67,13 @@ export default {
},
computed: {
...mapGetters({
filteredCategoryIds: 'postsFilter/filteredCategoryIds',
filteredCategoryIds: 'posts/filteredCategoryIds',
}),
},
methods: {
...mapMutations({
resetCategories: 'postsFilter/RESET_CATEGORIES',
toggleCategory: 'postsFilter/TOGGLE_CATEGORY',
resetCategories: 'posts/RESET_CATEGORIES',
toggleCategory: 'posts/TOGGLE_CATEGORY',
}),
},
}

View File

@ -50,20 +50,20 @@ describe('FilterPosts.vue', () => {
describe('mount', () => {
mutations = {
'postsFilter/TOGGLE_FILTER_BY_FOLLOWED': jest.fn(),
'postsFilter/RESET_CATEGORIES': jest.fn(),
'postsFilter/TOGGLE_CATEGORY': jest.fn(),
'postsFilter/TOGGLE_EMOTION': jest.fn(),
'posts/TOGGLE_FILTER_BY_FOLLOWED': jest.fn(),
'posts/RESET_CATEGORIES': jest.fn(),
'posts/TOGGLE_CATEGORY': jest.fn(),
'posts/TOGGLE_EMOTION': jest.fn(),
}
getters = {
'postsFilter/isActive': () => false,
'posts/isActive': () => false,
'auth/isModerator': () => false,
'auth/user': () => {
return { id: 'u34' }
},
'postsFilter/filteredCategoryIds': jest.fn(() => []),
'postsFilter/filteredByUsersFollowed': jest.fn(),
'postsFilter/filteredByEmotions': jest.fn(() => []),
'posts/filteredCategoryIds': jest.fn(() => []),
'posts/filteredByUsersFollowed': jest.fn(),
'posts/filteredByEmotions': jest.fn(() => []),
}
const openFilterPosts = () => {
const store = new Vuex.Store({ mutations, getters })
@ -94,18 +94,18 @@ describe('FilterPosts.vue', () => {
const wrapper = openFilterPosts()
environmentAndNatureButton = wrapper.findAll('button').at(2)
environmentAndNatureButton.trigger('click')
expect(mutations['postsFilter/TOGGLE_CATEGORY']).toHaveBeenCalledWith({}, 'cat4')
expect(mutations['posts/TOGGLE_CATEGORY']).toHaveBeenCalledWith({}, 'cat4')
})
it('sets category button attribute `primary` when corresponding category is filtered', () => {
getters['postsFilter/filteredCategoryIds'] = jest.fn(() => ['cat9'])
getters['posts/filteredCategoryIds'] = jest.fn(() => ['cat9'])
const wrapper = openFilterPosts()
democracyAndPoliticsButton = wrapper.findAll('button').at(4)
expect(democracyAndPoliticsButton.attributes().class).toContain('ds-button-primary')
})
it('sets "filter-by-followed-authors-only" button attribute `primary`', () => {
getters['postsFilter/filteredByUsersFollowed'] = jest.fn(() => true)
getters['posts/filteredByUsersFollowed'] = jest.fn(() => true)
const wrapper = openFilterPosts()
expect(
wrapper.find({ name: 'filter-by-followed-authors-only' }).classes('ds-button-primary'),
@ -120,7 +120,7 @@ describe('FilterPosts.vue', () => {
})
it('calls TOGGLE_FILTER_BY_FOLLOWED', () => {
expect(mutations['postsFilter/TOGGLE_FILTER_BY_FOLLOWED']).toHaveBeenCalledWith({}, 'u34')
expect(mutations['posts/TOGGLE_FILTER_BY_FOLLOWED']).toHaveBeenCalledWith({}, 'u34')
})
})
@ -129,11 +129,11 @@ describe('FilterPosts.vue', () => {
const wrapper = openFilterPosts()
happyEmotionButton = wrapper.findAll('button.emotions-buttons').at(1)
happyEmotionButton.trigger('click')
expect(mutations['postsFilter/TOGGLE_EMOTION']).toHaveBeenCalledWith({}, 'happy')
expect(mutations['posts/TOGGLE_EMOTION']).toHaveBeenCalledWith({}, 'happy')
})
it('sets the attribute `src` to colorized image', () => {
getters['postsFilter/filteredByEmotions'] = jest.fn(() => ['happy'])
getters['posts/filteredByEmotions'] = jest.fn(() => ['happy'])
const wrapper = openFilterPosts()
happyEmotionButton = wrapper.findAll('button.emotions-buttons').at(1)
const happyEmotionButtonImage = happyEmotionButton.find('img')

View File

@ -39,7 +39,7 @@ export default {
computed: {
...mapGetters({
currentUser: 'auth/user',
filterActive: 'postsFilter/isActive',
filterActive: 'posts/isActive',
}),
chunk() {
return chunk(this.categories, 2)

View File

@ -68,14 +68,14 @@ export default {
},
computed: {
...mapGetters({
filteredByUsersFollowed: 'postsFilter/filteredByUsersFollowed',
filteredByEmotions: 'postsFilter/filteredByEmotions',
filteredByUsersFollowed: 'posts/filteredByUsersFollowed',
filteredByEmotions: 'posts/filteredByEmotions',
}),
},
methods: {
...mapMutations({
toggleFilteredByFollowed: 'postsFilter/TOGGLE_FILTER_BY_FOLLOWED',
toogleFilteredByEmotions: 'postsFilter/TOGGLE_EMOTION',
toggleFilteredByFollowed: 'posts/TOGGLE_FILTER_BY_FOLLOWED',
toogleFilteredByEmotions: 'posts/TOGGLE_EMOTION',
}),
iconPath(emotion) {
if (this.filteredByEmotions.includes(emotion)) {

View File

@ -0,0 +1,75 @@
import { storiesOf } from '@storybook/vue'
import { withA11y } from '@storybook/addon-a11y'
import { action } from '@storybook/addon-actions'
import Vuex from 'vuex'
import helpers from '~/storybook/helpers'
import LoginForm from './LoginForm.vue'
helpers.init()
const createStore = ({ loginSuccess }) => {
return new Vuex.Store({
modules: {
auth: {
namespaced: true,
state: () => ({
pending: false,
}),
mutations: {
SET_PENDING(state, pending) {
state.pending = pending
},
},
getters: {
pending(state) {
return !!state.pending
},
},
actions: {
async login({ commit, dispatch }, args) {
action('Vuex action `auth/login`')(args)
return new Promise((resolve, reject) => {
commit('SET_PENDING', true)
setTimeout(() => {
commit('SET_PENDING', false)
if (loginSuccess) {
resolve(loginSuccess)
} else {
reject(new Error('Login unsuccessful'))
}
}, 1000)
})
},
},
},
},
})
}
storiesOf('LoginForm', module)
.addDecorator(withA11y)
.addDecorator(helpers.layout)
.add('successful login', () => {
return {
components: { LoginForm },
store: createStore({ loginSuccess: true }),
methods: {
handleSuccess() {
action('Login successful!')()
},
},
template: `<login-form @success="handleSuccess"/>`,
}
})
.add('unsuccessful login', () => {
return {
components: { LoginForm },
store: createStore({ loginSuccess: false }),
methods: {
handleSuccess() {
action('Login successful!')()
},
},
template: `<login-form @success="handleSuccess"/>`,
}
})

View File

@ -0,0 +1,121 @@
<template>
<ds-container width="medium">
<ds-space margin="small">
<blockquote>
<p>{{ $t('quotes.african.quote') }}</p>
<b>- {{ $t('quotes.african.author') }}</b>
</blockquote>
</ds-space>
<ds-card class="login-card">
<ds-flex gutter="small">
<ds-flex-item :width="{ base: '100%', sm: '50%' }" centered>
<client-only>
<locale-switch class="login-locale-switch" offset="5" />
</client-only>
<ds-space margin-top="small" margin-bottom="xxx-small" centered>
<img
class="login-image"
alt="Human Connection"
src="/img/sign-up/humanconnection.svg"
/>
</ds-space>
</ds-flex-item>
<ds-flex-item :width="{ base: '100%', sm: '50%' }" centered>
<ds-space margin="small">
<a :href="$t('login.moreInfoURL')" :title="$t('login.moreInfoHint')" target="_blank">
{{ $t('login.moreInfo') }}
</a>
</ds-space>
<ds-space margin="small">
<ds-text size="small">{{ $t('login.copy') }}</ds-text>
</ds-space>
<form :disabled="pending" @submit.prevent="onSubmit">
<ds-input
v-model="form.email"
:disabled="pending"
:placeholder="$t('login.email')"
type="email"
name="email"
icon="envelope"
/>
<ds-input
v-model="form.password"
:disabled="pending"
:placeholder="$t('login.password')"
icon="lock"
icon-right="question-circle"
name="password"
type="password"
/>
<ds-space margin-bottom="large">
<nuxt-link to="/password-reset/request">{{ $t('login.forgotPassword') }}</nuxt-link>
</ds-space>
<ds-button
:loading="pending"
primary
fullwidth
name="submit"
type="submit"
icon="sign-in"
>
{{ $t('login.login') }}
</ds-button>
<ds-space margin-top="large" margin-bottom="x-small">
{{ $t('login.no-account') }}
<nuxt-link to="/registration/signup">{{ $t('login.register') }}</nuxt-link>
</ds-space>
</form>
</ds-flex-item>
</ds-flex>
</ds-card>
</ds-container>
</template>
<script>
import LocaleSwitch from '~/components/LocaleSwitch/LocaleSwitch.vue'
export default {
components: {
LocaleSwitch,
},
data() {
return {
form: {
email: '',
password: '',
},
}
},
computed: {
pending() {
return this.$store.getters['auth/pending']
},
},
methods: {
async onSubmit() {
try {
await this.$store.dispatch('auth/login', { ...this.form })
this.$toast.success(this.$t('login.success'))
this.$emit('success')
} catch (err) {
this.$toast.error(this.$t('login.failure'))
}
},
},
}
</script>
<style lang="scss">
.login-image {
width: 90%;
max-width: 200px;
}
.login-card {
position: relative;
}
.login-locale-switch {
position: absolute;
top: 1em;
left: 1em;
}
</style>

View File

@ -2,7 +2,7 @@ import { config, shallowMount, mount, createLocalVue, RouterLinkStub } from '@vu
import Styleguide from '@human-connection/styleguide'
import Vuex from 'vuex'
import Filters from '~/plugins/vue-filters'
import PostCard from '.'
import PostCard from './PostCard.vue'
const localVue = createLocalVue()

View File

@ -1,6 +1,6 @@
import { storiesOf } from '@storybook/vue'
import { withA11y } from '@storybook/addon-a11y'
import HcPostCard from '~/components/PostCard'
import HcPostCard from './PostCard.vue'
import helpers from '~/storybook/helpers'
helpers.init()
@ -76,3 +76,23 @@ storiesOf('Post Card', module)
/>
`,
}))
.add('pinned by admin', () => ({
components: { HcPostCard },
store: helpers.store,
data: () => ({
post: {
...post,
pinnedBy: {
id: '4711',
name: 'Ad Min',
role: 'admin',
},
},
}),
template: `
<hc-post-card
:post="post"
:width="{ base: '100%', xs: '100%', md: '50%', xl: '33%' }"
/>
`,
}))

View File

@ -1,7 +1,7 @@
<template>
<ds-card
:image="post.image | proxyApiUrl"
:class="{ 'post-card': true, 'disabled-content': post.disabled }"
:class="{ 'post-card': true, 'disabled-content': post.disabled, 'post--pinned': isPinned }"
>
<!-- Post Link Target -->
<nuxt-link
@ -16,7 +16,8 @@
<client-only>
<hc-user :user="post.author" :trunc="35" :date-time="post.createdAt" />
</client-only>
<hc-ribbon :text="$t('post.name')" />
<hc-ribbon v-if="isPinned" class="ribbon--pinned" :text="$t('post.pinned')" />
<hc-ribbon v-else :text="$t('post.name')" />
</div>
<ds-space margin-bottom="small" />
<!-- Post Title -->
@ -61,6 +62,8 @@
:resource="post"
:modalsData="menuModalsData"
:is-owner="isAuthor"
@pinPost="pinPost"
@unpinPost="unpinPost"
/>
</div>
</client-only>
@ -114,6 +117,9 @@ export default {
this.deletePostCallback,
)
},
isPinned() {
return this.post && this.post.pinnedBy
},
},
methods: {
async deletePostCallback() {
@ -127,6 +133,12 @@ export default {
this.$toast.error(err.message)
}
},
pinPost(post) {
this.$emit('pinPost', post)
},
unpinPost(post) {
this.$emit('unpinPost', post)
},
},
}
</script>
@ -167,4 +179,8 @@ export default {
text-indent: -999999px;
}
}
.post--pinned {
border: 1px solid $color-warning;
}
</style>

View File

@ -46,4 +46,12 @@ export default {
border-color: $background-color-secondary transparent transparent $background-color-secondary;
}
}
.ribbon--pinned {
background-color: $color-warning-active;
&::before {
border-color: $color-warning transparent transparent $color-warning;
}
}
</style>

View File

@ -93,7 +93,7 @@ export default {
return data.notifications
},
error(error) {
this.$toast.error(error)
this.$toast.error(error.message)
},
},
},

View File

@ -57,6 +57,12 @@ export const postFragment = lang => gql`
name
icon
}
pinnedBy {
id
name
role
}
pinnedAt
}
`
export const commentFragment = lang => gql`

View File

@ -50,6 +50,11 @@ export default () => {
content
contentExcerpt
language
pinnedBy {
id
name
role
}
}
}
`,
@ -86,5 +91,39 @@ export default () => {
}
}
`,
pinPost: gql`
mutation($id: ID!) {
pinPost(id: $id) {
id
title
slug
content
contentExcerpt
language
pinnedBy {
id
name
role
}
}
}
`,
unpinPost: gql`
mutation($id: ID!) {
unpinPost(id: $id) {
id
title
slug
content
contentExcerpt
language
pinnedBy {
id
name
role
}
}
}
`,
}
}

View File

@ -35,6 +35,26 @@ export const filterPosts = i18n => {
`
}
export const profilePagePosts = i18n => {
const lang = i18n.locale().toUpperCase()
return gql`
${postFragment(lang)}
${postCountsFragment}
query profilePagePosts(
$filter: _PostFilter
$first: Int
$offset: Int
$orderBy: [_PostOrdering]
) {
profilePagePosts(filter: $filter, first: $first, offset: $offset, orderBy: $orderBy) {
...post
...postCounts
}
}
`
}
export const PostsEmotionsByCurrentUser = () => {
return gql`
query PostsEmotionsByCurrentUser($postId: ID!) {

View File

@ -50,6 +50,18 @@
}
}
},
"store": {
"posts": {
"orderBy": {
"newest": {
"label": "Neueste"
},
"oldest": {
"label": "Älteste"
}
}
}
},
"maintenance": {
"title": "Human Connection befindet sich in der Wartung",
"explanation": "Zurzeit führen wir einige geplante Wartungsarbeiten durch, bitte versuch es später erneut.",
@ -95,10 +107,6 @@
"code-of-conduct": "Verhaltenscodex",
"back-to-login": "Zurück zur Anmeldung"
},
"sorting": {
"newest": "Neueste",
"oldest": "Älteste"
},
"login": {
"copy": "Wenn Du bereits ein Konto bei Human Connection hast, melde Dich bitte hier an.",
"login": "Einloggen",
@ -112,7 +120,8 @@
"moreInfoURL": "https://human-connection.org",
"moreInfoHint": "zur Präsentationsseite",
"hello": "Hallo",
"success": "Du bist eingeloggt!"
"success": "Du bist eingeloggt!",
"failure": "Fehlerhafte E-Mail-Adresse oder Passwort."
},
"editor": {
"placeholder": "Schreib etwas Inspirierendes …",
@ -354,6 +363,7 @@
},
"post": {
"name": "Beitrag",
"pinned": "Meldung",
"moreInfo": {
"name": "Mehr Info",
"title": "Mehr Informationen",
@ -367,7 +377,11 @@
},
"menu": {
"edit": "Beitrag bearbeiten",
"delete": "Beitrag löschen"
"delete": "Beitrag löschen",
"pin": "Post festpinnen",
"pinnedSuccessfully": "Post erfolgreich festgepinnt!",
"unpin": "Post nicht mehr festpinnen",
"unpinnedSuccessfully": "Post erfolgreich nicht mehr festgepinnt!"
},
"comment": {
"submit": "Kommentiere",

View File

@ -51,6 +51,18 @@
}
}
},
"store": {
"posts": {
"orderBy": {
"newest": {
"label": "Newest"
},
"oldest": {
"label": "Oldest"
}
}
}
},
"maintenance": {
"title": "Human Connection is under maintenance",
"explanation": "At the moment we are doing some scheduled maintenance, please try again later.",
@ -96,10 +108,6 @@
"code-of-conduct": "Code of Conduct",
"back-to-login": "Back to login page"
},
"sorting": {
"newest": "Newest",
"oldest": "Oldest"
},
"login": {
"copy": "If you already have a human-connection account, please login.",
"login": "Login",
@ -113,7 +121,8 @@
"moreInfoURL": "https://human-connection.org/en/",
"moreInfoHint": "to the presentation page",
"hello": "Hello",
"success": "You are logged in!"
"success": "You are logged in!",
"failure": "Incorrect email address or password."
},
"editor": {
"placeholder": "Leave your inspirational thoughts …",
@ -355,6 +364,7 @@
},
"post": {
"name": "Post",
"pinned": "Announcement",
"moreInfo": {
"name": "More info",
"title": "More information",
@ -368,7 +378,11 @@
},
"menu": {
"edit": "Edit Post",
"delete": "Delete Post"
"delete": "Delete Post",
"pin": "Pin post",
"pinnedSuccessfully": "Post pinned successfully!",
"unpin": "Unpin post",
"unpinnedSuccessfully": "Post unpinned successfully!"
},
"comment": {
"submit": "Comment",

View File

@ -12,7 +12,7 @@
"scripts": {
"dev": "nuxt",
"dev:styleguide": "cross-env STYLEGUIDE_DEV=true yarn run dev",
"storybook": "start-storybook -p 3002 -c storybook/",
"storybook": "start-storybook -p 3002 -s ./static -c storybook/",
"build": "nuxt build",
"start": "nuxt start",
"generate:maintenance": "nuxt generate -c nuxt.config.maintenance.js",
@ -72,7 +72,7 @@
"jsonwebtoken": "~8.5.1",
"linkify-it": "~2.2.0",
"node-fetch": "^2.6.0",
"nuxt": "~2.10.1",
"nuxt": "~2.10.2",
"nuxt-dropzone": "^1.0.4",
"nuxt-env": "~0.1.0",
"stack-utils": "^1.0.2",
@ -97,12 +97,12 @@
"@babel/preset-env": "~7.6.3",
"@storybook/addon-a11y": "^5.2.4",
"@storybook/addon-actions": "^5.2.4",
"@storybook/vue": "~5.2.4",
"@storybook/vue": "~5.2.5",
"@vue/cli-shared-utils": "~4.0.4",
"@vue/eslint-config-prettier": "~5.0.0",
"@vue/server-test-utils": "~1.0.0-beta.29",
"@vue/test-utils": "~1.0.0-beta.29",
"async-validator": "^3.1.0",
"async-validator": "^3.2.0",
"babel-core": "~7.0.0-bridge.0",
"babel-eslint": "~10.0.3",
"babel-jest": "~24.9.0",
@ -121,6 +121,7 @@
"eslint-plugin-promise": "~4.2.1",
"eslint-plugin-standard": "~4.0.1",
"eslint-plugin-vue": "~5.2.3",
"faker": "^4.1.0",
"flush-promises": "^1.0.2",
"fuse.js": "^3.4.5",
"identity-obj-proxy": "^3.0.0",

View File

@ -24,15 +24,37 @@ describe('PostIndex', () => {
let Wrapper
let store
let mocks
let mutations
beforeEach(() => {
mutations = {
'posts/SELECT_ORDER': jest.fn(),
}
store = new Vuex.Store({
getters: {
'postsFilter/postsFilter': () => ({}),
'posts/filter': () => ({}),
'posts/orderOptions': () => () => [
{
key: 'store.posts.orderBy.oldest.label',
label: 'store.posts.orderBy.oldest.label',
icon: 'sort-amount-asc',
value: 'createdAt_asc',
},
{
key: 'store.posts.orderBy.newest.label',
label: 'store.posts.orderBy.newest.label',
icon: 'sort-amount-desc',
value: 'createdAt_desc',
},
],
'posts/selectedOrder': () => () => 'createdAt_desc',
'posts/orderIcon': () => 'sort-amount-desc',
'posts/orderBy': () => 'createdAt_desc',
'auth/user': () => {
return { id: 'u23' }
},
},
mutations,
})
mocks = {
$t: key => key,
@ -103,12 +125,12 @@ describe('PostIndex', () => {
})
})
it('sets the post in the store when there are posts', () => {
it('calls store when using order by menu', () => {
wrapper
.findAll('li')
.at(0)
.trigger('click')
expect(wrapper.vm.sorting).toEqual('createdAt_desc')
expect(mutations['posts/SELECT_ORDER']).toHaveBeenCalledWith({}, 'createdAt_asc')
})
it('updates offset when a user clicks on the load more button', () => {

View File

@ -10,8 +10,7 @@
v-model="selected"
:options="sortingOptions"
size="large"
v-bind:icon-right="sortingIcon"
@input="toggleOnlySorting"
:icon-right="sortingIcon"
></ds-select>
</div>
</ds-grid-item>
@ -21,6 +20,8 @@
:post="post"
:width="{ base: '100%', xs: '100%', md: '50%', xl: '33%' }"
@removePostFromList="deletePost"
@pinPost="pinPost"
@unpinPost="unpinPost"
/>
</masonry-grid-item>
</template>
@ -58,12 +59,13 @@
<script>
import FilterMenu from '~/components/FilterMenu/FilterMenu.vue'
import HcEmpty from '~/components/Empty'
import HcPostCard from '~/components/PostCard'
import HcPostCard from '~/components/PostCard/PostCard.vue'
import HcLoadMore from '~/components/LoadMore.vue'
import MasonryGrid from '~/components/MasonryGrid/MasonryGrid.vue'
import MasonryGridItem from '~/components/MasonryGrid/MasonryGridItem.vue'
import { mapGetters } from 'vuex'
import { mapGetters, mapMutations } from 'vuex'
import { filterPosts } from '~/graphql/PostQuery.js'
import PostMutations from '~/graphql/PostMutations'
export default {
components: {
@ -83,30 +85,29 @@ export default {
offset: 0,
pageSize: 12,
hashtag,
placeholder: this.$t('sorting.newest'),
selected: this.$t('sorting.newest'),
sortingIcon: 'sort-amount-desc',
sorting: 'createdAt_desc',
sortingOptions: [
{
label: this.$t('sorting.newest'),
value: 'Newest',
icons: 'sort-amount-desc',
order: 'createdAt_desc',
},
{
label: this.$t('sorting.oldest'),
value: 'Oldest',
icons: 'sort-amount-asc',
order: 'createdAt_asc',
},
],
}
},
computed: {
...mapGetters({
postsFilter: 'postsFilter/postsFilter',
postsFilter: 'posts/filter',
orderOptions: 'posts/orderOptions',
orderBy: 'posts/orderBy',
selectedOrder: 'posts/selectedOrder',
sortingIcon: 'posts/orderIcon',
}),
selected: {
get() {
return this.selectedOrder(this)
},
set({ value }) {
this.offset = 0
this.posts = []
this.selectOrder(value)
},
},
sortingOptions() {
return this.orderOptions(this)
},
finalFilters() {
let filter = this.postsFilter
if (this.hashtag) {
@ -122,12 +123,9 @@ export default {
},
},
methods: {
toggleOnlySorting(x) {
this.offset = 0
this.posts = []
this.sortingIcon = x.icons
this.sorting = x.order
},
...mapMutations({
selectOrder: 'posts/SELECT_ORDER',
}),
clearSearch() {
this.$router.push({ path: '/' })
this.hashtag = null
@ -148,7 +146,7 @@ export default {
offset: this.offset,
filter: this.finalFilters,
first: this.pageSize,
orderBy: this.sorting,
orderBy: this.orderBy,
},
updateQuery: (previousResult, { fetchMoreResult }) => {
if (!fetchMoreResult || fetchMoreResult.Post.length < this.pageSize) {
@ -166,6 +164,37 @@ export default {
return post.id !== deletedPost.id
})
},
resetPostList() {
this.offset = 0
this.posts = []
this.hasMore = true
},
pinPost(post) {
this.$apollo
.mutate({
mutation: PostMutations().pinPost,
variables: { id: post.id },
})
.then(() => {
this.$toast.success(this.$t('post.menu.pinnedSuccessfully'))
this.resetPostList()
this.$apollo.queries.Post.refetch()
})
.catch(error => this.$toast.error(error.message))
},
unpinPost(post) {
this.$apollo
.mutate({
mutation: PostMutations().unpinPost,
variables: { id: post.id },
})
.then(() => {
this.$toast.success(this.$t('post.menu.unpinnedSuccessfully'))
this.resetPostList()
this.$apollo.queries.Post.refetch()
})
.catch(error => this.$toast.error(error.message))
},
},
apollo: {
Post: {
@ -176,7 +205,7 @@ export default {
return {
filter: this.finalFilters,
first: this.pageSize,
orderBy: this.sorting,
orderBy: ['pinned_asc', this.orderBy],
offset: 0,
}
},

View File

@ -1,138 +1,27 @@
<template>
<transition name="fade" appear>
<ds-container v-if="ready" width="medium">
<ds-space margin="small">
<blockquote>
<p>{{ $t('quotes.african.quote') }}</p>
<b>- {{ $t('quotes.african.author') }}</b>
</blockquote>
</ds-space>
<ds-card class="login-card">
<ds-flex gutter="small">
<ds-flex-item :width="{ base: '100%', sm: '50%' }" centered>
<client-only>
<locale-switch class="login-locale-switch" offset="5" />
</client-only>
<ds-space margin-top="small" margin-bottom="xxx-small" centered>
<img
class="login-image"
alt="Human Connection"
src="/img/sign-up/humanconnection.svg"
/>
</ds-space>
</ds-flex-item>
<ds-flex-item :width="{ base: '100%', sm: '50%' }" centered>
<ds-space margin="small">
<a :href="$t('login.moreInfoURL')" :title="$t('login.moreInfoHint')" target="_blank">
{{ $t('login.moreInfo') }}
</a>
</ds-space>
<ds-space margin="small">
<ds-text size="small">{{ $t('login.copy') }}</ds-text>
</ds-space>
<form :disabled="pending" @submit.prevent="onSubmit">
<ds-input
v-model="form.email"
:disabled="pending"
:placeholder="$t('login.email')"
type="email"
name="email"
icon="envelope"
/>
<ds-input
v-model="form.password"
:disabled="pending"
:placeholder="$t('login.password')"
icon="lock"
icon-right="question-circle"
name="password"
type="password"
/>
<ds-space margin-bottom="large">
<nuxt-link to="/password-reset/request">{{ $t('login.forgotPassword') }}</nuxt-link>
</ds-space>
<ds-button
:loading="pending"
primary
fullwidth
name="submit"
type="submit"
icon="sign-in"
>
{{ $t('login.login') }}
</ds-button>
<ds-space margin-top="large" margin-bottom="x-small">
{{ $t('login.no-account') }}
<nuxt-link to="/registration/signup">{{ $t('login.register') }}</nuxt-link>
</ds-space>
</form>
</ds-flex-item>
</ds-flex>
</ds-card>
</ds-container>
<login-form @success="handleSuccess" />
</transition>
</template>
<script>
import LocaleSwitch from '~/components/LocaleSwitch/LocaleSwitch'
import LoginForm from '~/components/LoginForm/LoginForm.vue'
import { VERSION } from '~/constants/terms-and-conditions-version.js'
export default {
layout: 'no-header',
components: {
LocaleSwitch,
},
data() {
return {
ready: false,
form: {
email: '',
password: '',
},
}
},
computed: {
pending() {
return this.$store.getters['auth/pending']
},
LoginForm,
},
asyncData({ store, redirect }) {
if (store.getters['auth/user'].termsAndConditionsAgreedVersion === VERSION) {
redirect('/')
}
},
mounted() {
setTimeout(() => {
// NOTE: quick fix for jumping flexbox implementation
// will be fixed in a future update of the styleguide
this.ready = true
}, 50)
},
methods: {
async onSubmit() {
try {
await this.$store.dispatch('auth/login', { ...this.form })
this.$toast.success(this.$t('login.success'))
this.$router.replace(this.$route.query.path || '/')
} catch (err) {
this.$toast.error(err.message)
}
handleSuccess() {
this.$router.replace(this.$route.query.path || '/')
},
},
}
</script>
<style lang="scss">
.login-image {
width: 90%;
max-width: 200px;
}
.login-card {
position: relative;
}
.login-locale-switch {
position: absolute;
top: 1em;
left: 1em;
}
</style>

View File

@ -31,10 +31,10 @@ describe('PostSlug', () => {
$filters: {
truncate: a => a,
},
// If you are mocking the router, then don't use VueRouter with localVue: https://vue-test-utils.vuejs.org/guides/using-with-vue-router.html
$route: {
hash: '',
},
// If you are mocking the router, then don't use VueRouter with localVue: https://vue-test-utils.vuejs.org/guides/using-with-vue-router.html
$router: {
history: {
push: jest.fn(),

View File

@ -18,6 +18,8 @@
:resource="post"
:modalsData="menuModalsData"
:is-owner="isAuthor(post.author ? post.author.id : null)"
@pinPost="pinPost"
@unpinPost="unpinPost"
/>
</client-only>
<ds-space margin-bottom="small" />
@ -68,9 +70,13 @@
</ds-space>
<!-- Comments -->
<ds-section slot="footer">
<hc-comment-list :post="post" :routeHash="$route.hash" />
<hc-comment-list
:post="post"
:routeHash="$route.hash"
@toggleNewCommentForm="toggleNewCommentForm"
/>
<ds-space margin-bottom="large" />
<hc-comment-form :post="post" @createComment="createComment" />
<hc-comment-form v-if="showNewCommentForm" :post="post" @createComment="createComment" />
</ds-section>
</ds-card>
</transition>
@ -88,6 +94,7 @@ import HcCommentList from '~/components/CommentList/CommentList'
import { postMenuModalsData, deletePostMutation } from '~/components/utils/PostHelpers'
import PostQuery from '~/graphql/PostQuery'
import HcEmotions from '~/components/Emotions/Emotions'
import PostMutations from '~/graphql/PostMutations'
export default {
name: 'PostSlug',
@ -116,6 +123,7 @@ export default {
post: null,
ready: false,
title: 'loading',
showNewCommentForm: true,
}
},
watch: {
@ -156,6 +164,31 @@ export default {
async createComment(comment) {
this.post.comments.push(comment)
},
pinPost(post) {
this.$apollo
.mutate({
mutation: PostMutations().pinPost,
variables: { id: post.id },
})
.then(() => {
this.$toast.success(this.$t('post.menu.pinnedSuccessfully'))
})
.catch(error => this.$toast.error(error.message))
},
unpinPost(post) {
this.$apollo
.mutate({
mutation: PostMutations().unpinPost,
variables: { id: post.id },
})
.then(() => {
this.$toast.success(this.$t('post.menu.unpinnedSuccessfully'))
})
.catch(error => this.$toast.error(error.message))
},
toggleNewCommentForm(showNewCommentForm) {
this.showNewCommentForm = showNewCommentForm
},
},
apollo: {
Post: {

View File

@ -37,7 +37,7 @@
<script>
import HcEmpty from '~/components/Empty.vue'
import HcPostCard from '~/components/PostCard'
import HcPostCard from '~/components/PostCard/PostCard.vue'
import HcCategory from '~/components/Category'
import HcHashtag from '~/components/Hashtag/Hashtag'
import { relatedContributions } from '~/graphql/PostQuery'

View File

@ -234,6 +234,8 @@
:post="post"
:width="{ base: '100%', md: '100%', xl: '50%' }"
@removePostFromList="removePostFromList"
@pinPost="pinPost"
@unpinPost="unpinPost"
/>
</masonry-grid-item>
</template>
@ -268,7 +270,7 @@
<script>
import uniqBy from 'lodash/uniqBy'
import User from '~/components/User/User'
import HcPostCard from '~/components/PostCard'
import HcPostCard from '~/components/PostCard/PostCard.vue'
import HcFollowButton from '~/components/FollowButton.vue'
import HcCountTo from '~/components/CountTo.vue'
import HcBadges from '~/components/Badges.vue'
@ -279,9 +281,10 @@ import HcUpload from '~/components/Upload'
import HcAvatar from '~/components/Avatar/Avatar.vue'
import MasonryGrid from '~/components/MasonryGrid/MasonryGrid.vue'
import MasonryGridItem from '~/components/MasonryGrid/MasonryGridItem.vue'
import { filterPosts } from '~/graphql/PostQuery'
import { profilePagePosts } from '~/graphql/PostQuery'
import UserQuery from '~/graphql/User'
import { Block, Unblock } from '~/graphql/settings/BlockedUsers'
import PostMutations from '~/graphql/PostMutations'
const tabToFilterMapping = ({ tab, id }) => {
return {
@ -412,6 +415,32 @@ export default {
this.resetPostList()
this.$apollo.queries.Post.refetch()
},
pinPost(post) {
this.$apollo
.mutate({
mutation: PostMutations().pinPost,
variables: { id: post.id },
})
.then(() => {
this.$toast.success(this.$t('post.menu.pinnedSuccessfully'))
this.resetPostList()
this.$apollo.queries.Post.refetch()
})
.catch(error => this.$toast.error(error.message))
},
unpinPost(post) {
this.$apollo
.mutate({
mutation: PostMutations().unpinPost,
variables: { id: post.id },
})
.then(() => {
this.$toast.success(this.$t('post.menu.unpinnedSuccessfully'))
this.resetPostList()
this.$apollo.queries.Post.refetch()
})
.catch(error => this.$toast.error(error.message))
},
optimisticFollow({ followedByCurrentUser }) {
/*
* Note: followedByCountStartValue is updated to avoid counting from 0 when follow/unfollow
@ -437,7 +466,7 @@ export default {
apollo: {
Post: {
query() {
return filterPosts(this.$i18n)
return profilePagePosts(this.$i18n)
},
variables() {
return {
@ -447,8 +476,8 @@ export default {
orderBy: 'createdAt_desc',
}
},
update({ Post }) {
this.posts = Post
update({ profilePagePosts }) {
this.posts = profilePagePosts
},
fetchPolicy: 'cache-and-network',
},

View File

@ -31,11 +31,7 @@ export default ({ app = {} }) => {
if (length <= 0) {
return value
}
let output = trunc(value, length).html
if (output.length < value.length) {
output += ' …'
}
return output
return trunc(value, length).html
},
list: (value, glue = ', ', truncate = 0) => {
if (!Array.isArray(value) || !value.length) {

View File

@ -7,11 +7,25 @@ import clone from 'lodash/clone'
const defaultFilter = {}
const orderOptions = {
createdAt_asc: {
value: 'createdAt_asc',
key: 'store.posts.orderBy.oldest.label',
icon: 'sort-amount-asc',
},
createdAt_desc: {
value: 'createdAt_desc',
key: 'store.posts.orderBy.newest.label',
icon: 'sort-amount-desc',
},
}
export const state = () => {
return {
filter: {
...defaultFilter,
},
order: orderOptions['createdAt_desc'],
}
}
@ -46,13 +60,16 @@ export const mutations = {
if (isEmpty(get(filter, 'emotions_some.emotion_in'))) delete filter.emotions_some
state.filter = filter
},
SELECT_ORDER(state, value) {
state.order = orderOptions[value]
},
}
export const getters = {
isActive(state) {
return !isEqual(state.filter, defaultFilter)
},
postsFilter(state) {
filter(state) {
return state.filter
},
filteredCategoryIds(state) {
@ -64,4 +81,23 @@ export const getters = {
filteredByEmotions(state) {
return get(state.filter, 'emotions_some.emotion_in') || []
},
orderOptions: state => ({ $t }) =>
Object.values(orderOptions).map(option => {
return {
...option,
label: $t(option.key),
}
}),
selectedOrder: state => ({ $t }) => {
return {
...state.order,
label: $t(state.order.key),
}
},
orderBy(state) {
return state.order.value
},
orderIcon(state) {
return state.order.icon
},
}

View File

@ -1,7 +1,7 @@
import { getters, mutations } from './postsFilter.js'
import { getters, mutations } from './posts.js'
let state
let testAction
let testMutation
describe('getters', () => {
describe('isActive', () => {
@ -25,10 +25,10 @@ describe('getters', () => {
})
})
describe('postsFilter', () => {
describe('filter', () => {
it('returns filter', () => {
state = { filter: { author: { followedBy_some: { id: 7 } } } }
expect(getters.postsFilter(state)).toEqual({ author: { followedBy_some: { id: 7 } } })
expect(getters.filter(state)).toEqual({ author: { followedBy_some: { id: 7 } } })
})
})
@ -67,14 +67,48 @@ describe('getters', () => {
expect(getters.filteredByEmotions(state)).toEqual([])
})
})
describe('orderByOptions', () => {
it('returns all options regardless of current state', () => {
const $t = jest.fn(t => t)
expect(getters.orderOptions()({ $t })).toEqual([
{
key: 'store.posts.orderBy.oldest.label',
label: 'store.posts.orderBy.oldest.label',
icon: 'sort-amount-asc',
value: 'createdAt_asc',
},
{
key: 'store.posts.orderBy.newest.label',
label: 'store.posts.orderBy.newest.label',
icon: 'sort-amount-desc',
value: 'createdAt_desc',
},
])
})
})
describe('orderBy', () => {
it('returns value for graphql query', () => {
state = {
order: {
key: 'store.posts.orderBy.newest.label',
label: 'store.posts.orderBy.newest.label',
icon: 'sort-amount-desc',
value: 'createdAt_desc',
},
}
expect(getters.orderBy(state)).toEqual('createdAt_desc')
})
})
})
describe('mutations', () => {
describe('RESET_CATEGORIES', () => {
beforeEach(() => {
testAction = categoryId => {
testMutation = categoryId => {
mutations.RESET_CATEGORIES(state, categoryId)
return getters.postsFilter(state)
return getters.filter(state)
}
})
it('resets the categories filter', () => {
@ -84,37 +118,37 @@ describe('mutations', () => {
categories_some: { id_in: [23] },
},
}
expect(testAction(23)).toEqual({ author: { followedBy_some: { id: 7 } } })
expect(testMutation(23)).toEqual({ author: { followedBy_some: { id: 7 } } })
})
})
describe('TOGGLE_CATEGORY', () => {
beforeEach(() => {
testAction = categoryId => {
testMutation = categoryId => {
mutations.TOGGLE_CATEGORY(state, categoryId)
return getters.postsFilter(state)
return getters.filter(state)
}
})
it('creates category filter if empty', () => {
state = { filter: {} }
expect(testAction(23)).toEqual({ categories_some: { id_in: [23] } })
expect(testMutation(23)).toEqual({ categories_some: { id_in: [23] } })
})
it('adds category id not present', () => {
state = { filter: { categories_some: { id_in: [24] } } }
expect(testAction(23)).toEqual({ categories_some: { id_in: [24, 23] } })
expect(testMutation(23)).toEqual({ categories_some: { id_in: [24, 23] } })
})
it('removes category id if present', () => {
state = { filter: { categories_some: { id_in: [23, 24] } } }
const result = testAction(23)
const result = testMutation(23)
expect(result).toEqual({ categories_some: { id_in: [24] } })
})
it('removes category filter if empty', () => {
state = { filter: { categories_some: { id_in: [23] } } }
expect(testAction(23)).toEqual({})
expect(testMutation(23)).toEqual({})
})
it('does not get in the way of other filters', () => {
@ -124,15 +158,15 @@ describe('mutations', () => {
categories_some: { id_in: [23] },
},
}
expect(testAction(23)).toEqual({ author: { followedBy_some: { id: 7 } } })
expect(testMutation(23)).toEqual({ author: { followedBy_some: { id: 7 } } })
})
})
describe('TOGGLE_FILTER_BY_FOLLOWED', () => {
beforeEach(() => {
testAction = userId => {
testMutation = userId => {
mutations.TOGGLE_FILTER_BY_FOLLOWED(state, userId)
return getters.postsFilter(state)
return getters.filter(state)
}
})
@ -142,7 +176,7 @@ describe('mutations', () => {
})
it('attaches the id of the current user to the filter object', () => {
expect(testAction(4711)).toEqual({ author: { followedBy_some: { id: 4711 } } })
expect(testMutation(4711)).toEqual({ author: { followedBy_some: { id: 4711 } } })
})
})
@ -152,8 +186,23 @@ describe('mutations', () => {
})
it('remove the id of the current user from the filter object', () => {
expect(testAction(4711)).toEqual({})
expect(testMutation(4711)).toEqual({})
})
})
})
describe('SELECT_ORDER', () => {
beforeEach(() => {
testMutation = key => {
mutations.SELECT_ORDER(state, key)
return getters.orderBy(state)
}
})
it('switches the currently selected order', () => {
state = {
// does not matter
}
expect(testMutation('createdAt_asc')).toEqual('createdAt_asc')
})
})
})

View File

@ -3,7 +3,9 @@ import Vuex from 'vuex'
import vuexI18n from 'vuex-i18n/dist/vuex-i18n.umd.js'
import Styleguide from '@human-connection/styleguide'
import Filters from '~/plugins/vue-filters'
import IziToast from '~/plugins/izi-toast'
import layout from './layout.vue'
import locales from '~/locales/index.js'
import '~/plugins/v-tooltip'
@ -12,10 +14,13 @@ const helpers = {
Vue.use(Vuex)
Vue.use(Styleguide)
Vue.use(Filters)
Vue.use(IziToast)
Vue.use(vuexI18n.plugin, helpers.store)
Vue.i18n.add('en', require('~/locales/en.json'))
Vue.i18n.add('de', require('~/locales/de.json'))
locales.forEach(({ code }) => {
Vue.i18n.add(code, require(`~/locales/${code}.json`))
})
Vue.i18n.set('en')
Vue.i18n.fallback('en')
@ -35,14 +40,6 @@ const helpers = {
},
},
},
editor: {
namespaced: true,
getters: {
placeholder(state) {
return 'Leave your inspirational thoughts ...'
},
},
},
},
}),
layout(storyFn) {

View File

@ -1165,10 +1165,10 @@
resolved "https://registry.yarnpkg.com/@nodelib/fs.stat/-/fs.stat-1.1.3.tgz#2b5a3ab3f918cca48a8c754c08168e3f03eba61b"
integrity sha512-shAmDyaQC4H92APFoIaVDHCx5bStIocgvbwQyxPRrbUY20V1EYTbSDchWbuwlMG3V17cprZhA6+78JfB+3DTPw==
"@nuxt/babel-preset-app@2.10.1":
version "2.10.1"
resolved "https://registry.yarnpkg.com/@nuxt/babel-preset-app/-/babel-preset-app-2.10.1.tgz#9669ff09d652011fefeb55cdc1684cd21f49b34a"
integrity sha512-kTJ1+kperaoPdkIE1Do6x+/2cMEk0zMKiLCc6a4vUvnhkfPLc5m5/ylwx2kke42xXqTGHNX84BSaJ891AxDJgQ==
"@nuxt/babel-preset-app@2.10.2":
version "2.10.2"
resolved "https://registry.yarnpkg.com/@nuxt/babel-preset-app/-/babel-preset-app-2.10.2.tgz#2af6334a6bd0c4cc5abf9661bcddbe1cbc4af051"
integrity sha512-620Ho7tp0054PL+1fu4aJAaKs/VbpkS9KsuUMPNmmxPPt+UfVtEIesds5OIatT4tgO/SPQXfwPC4chA5u1duBQ==
dependencies:
"@babel/core" "^7.6.4"
"@babel/plugin-proposal-class-properties" "^7.5.5"
@ -1179,18 +1179,18 @@
"@vue/babel-preset-jsx" "^1.1.1"
core-js "^2.6.5"
"@nuxt/builder@2.10.1":
version "2.10.1"
resolved "https://registry.yarnpkg.com/@nuxt/builder/-/builder-2.10.1.tgz#06df592cb0e3b76a82505dbf34030834650264b2"
integrity sha512-LyKVoR7f8CKkeIk1EYvpXaMxO6ShASH3iA/5ck0PDm0qcl6iyn4bTwvF55cwkbPP+hStEjqpkhTccNxDTWCgQQ==
"@nuxt/builder@2.10.2":
version "2.10.2"
resolved "https://registry.yarnpkg.com/@nuxt/builder/-/builder-2.10.2.tgz#4b718e675c2e2206648fc233d73d438c21908b34"
integrity sha512-Apk46yuCbcSCrBN2dh1idIESjkxciW8pyAcGBfNW17IzEA55/XmkjQWTEMlI7fkHDUFQ4YXOcM+gYqP/cx72ew==
dependencies:
"@nuxt/devalue" "^1.2.4"
"@nuxt/utils" "2.10.1"
"@nuxt/vue-app" "2.10.1"
chokidar "^3.2.1"
"@nuxt/utils" "2.10.2"
"@nuxt/vue-app" "2.10.2"
chokidar "^3.2.2"
consola "^2.10.1"
fs-extra "^8.1.0"
glob "^7.1.4"
glob "^7.1.5"
hash-sum "^2.0.0"
ignore "^5.1.4"
lodash "^4.17.15"
@ -1199,18 +1199,18 @@
serialize-javascript "^2.1.0"
upath "^1.2.0"
"@nuxt/cli@2.10.1":
version "2.10.1"
resolved "https://registry.yarnpkg.com/@nuxt/cli/-/cli-2.10.1.tgz#92b43e2d7ea39703b63da0514228f353f2284061"
integrity sha512-byXTGebvtQfzd7yBSVeHD7IZqB+Qeh9shCO8Cn6j803fHJA7s+XwzhZq3lOqOvHBO4rQ3LTkjKnsBaYtGGtVuw==
"@nuxt/cli@2.10.2":
version "2.10.2"
resolved "https://registry.yarnpkg.com/@nuxt/cli/-/cli-2.10.2.tgz#62e376857e251492206c7efb0e1d143c7b3797c3"
integrity sha512-EYLb5zYggTkdxO9Og9Vn+5/LDcQioL1zijIr5V2gi690v3Zim2rSifdgxuUDOlUPzoy+3kiOFqdtzOJ81ES+bA==
dependencies:
"@nuxt/config" "2.10.1"
"@nuxt/utils" "2.10.1"
"@nuxt/config" "2.10.2"
"@nuxt/utils" "2.10.2"
boxen "^4.1.0"
chalk "^2.4.2"
consola "^2.10.1"
esm "^3.2.25"
execa "^2.1.0"
execa "^3.2.0"
exit "^0.1.2"
fs-extra "^8.1.0"
hable "^2.3.2"
@ -1220,25 +1220,25 @@
std-env "^2.2.1"
wrap-ansi "^6.0.0"
"@nuxt/config@2.10.1":
version "2.10.1"
resolved "https://registry.yarnpkg.com/@nuxt/config/-/config-2.10.1.tgz#3a2fc555bcdecdedc366a8e5fac94f3553e86603"
integrity sha512-ydxDU1U4bEwLixn8wqYy8Y+4nVOtMaSodW0a4Kuyx9Z/3qnQbI0yvdO58I6CIw+6njAmATsAqaApIcX9bJQOeQ==
"@nuxt/config@2.10.2":
version "2.10.2"
resolved "https://registry.yarnpkg.com/@nuxt/config/-/config-2.10.2.tgz#76555cafa69638d4a9f9b72faaa9a0c5ca3ff8fc"
integrity sha512-A4Tvm85PyeBAKwTlqQkFiuatmXr2Ro/oLelvi9wnrF/jSmgzU9NwcIZIQBND0/XpK1BL49ze5al5+SELOoGUpg==
dependencies:
"@nuxt/utils" "2.10.1"
"@nuxt/utils" "2.10.2"
consola "^2.10.1"
std-env "^2.2.1"
"@nuxt/core@2.10.1":
version "2.10.1"
resolved "https://registry.yarnpkg.com/@nuxt/core/-/core-2.10.1.tgz#fc934d70e9112fdc5fe7b459977d7f82b783c1d8"
integrity sha512-6GLUNo7wILEEeEzxcTLVc3N5ao+A7z36iW5RUK1PibT2CERwlJbyoQILMioxXwTldPTA4tPAm7xmOgb4CC66Yw==
"@nuxt/core@2.10.2":
version "2.10.2"
resolved "https://registry.yarnpkg.com/@nuxt/core/-/core-2.10.2.tgz#3fc0ef2afce3689a2a9d70d568bb64c046005932"
integrity sha512-PCA9J41kv7SA3rZbhuLwwzPMJr7NtDVofTzAMJ+NOpIuGiQ7rHTtwgprEXs9j08A5hyk5zfmgypjyZKxxmOFjA==
dependencies:
"@nuxt/config" "2.10.1"
"@nuxt/config" "2.10.2"
"@nuxt/devalue" "^1.2.4"
"@nuxt/server" "2.10.1"
"@nuxt/utils" "2.10.1"
"@nuxt/vue-renderer" "2.10.1"
"@nuxt/server" "2.10.2"
"@nuxt/utils" "2.10.2"
"@nuxt/vue-renderer" "2.10.2"
consola "^2.10.1"
debug "^4.1.1"
esm "^3.2.25"
@ -1264,12 +1264,12 @@
error-stack-parser "^2.0.0"
string-width "^2.0.0"
"@nuxt/generator@2.10.1":
version "2.10.1"
resolved "https://registry.yarnpkg.com/@nuxt/generator/-/generator-2.10.1.tgz#5430cd908f25f095af3a07df8fe6febff871a0a0"
integrity sha512-tjd1cf1fX3eGpdIeacgkdWloOIin3XQBFzJoquNbz4noqwWuhjyN6Noi+9FaDrFpMu6qZE5rvX1Zf0/6kP1SJg==
"@nuxt/generator@2.10.2":
version "2.10.2"
resolved "https://registry.yarnpkg.com/@nuxt/generator/-/generator-2.10.2.tgz#7b7aa2ba4e7a3c7fcf7b4c12a8e44d2c7f8410b6"
integrity sha512-0d8oENAxSnv5s2FtqtyDZ2S9lLVge9M1gKmw5BFaRJRyvfT0Bq9hG+tU9lnHslYkScEToomFUcV5Wt1E22fuvQ==
dependencies:
"@nuxt/utils" "2.10.1"
"@nuxt/utils" "2.10.2"
chalk "^2.4.2"
consola "^2.10.1"
fs-extra "^8.1.0"
@ -1294,13 +1294,13 @@
consola "^2.10.1"
node-fetch "^2.6.0"
"@nuxt/server@2.10.1":
version "2.10.1"
resolved "https://registry.yarnpkg.com/@nuxt/server/-/server-2.10.1.tgz#6f2a19ccde971df365f6a847c9a33181e81e2142"
integrity sha512-+1PMy8VknZWKj/uxKxwllTXuU+mgGOq17YSWfhKUAidlAb1YpdndlVOuWZgfdEsoQjJYq1vmIHMg8389chy7+g==
"@nuxt/server@2.10.2":
version "2.10.2"
resolved "https://registry.yarnpkg.com/@nuxt/server/-/server-2.10.2.tgz#6f9b5c19e8e6bb3dd3d063388045206f3b6f8d70"
integrity sha512-kWUmBq9/4ftXJXcSfNphMwweEfd8lBD7XCrFR/tK3FciIO/MuWlAtReNP8fC+KTC00RXks2fiR1xFpGEsIHUaA==
dependencies:
"@nuxt/config" "2.10.1"
"@nuxt/utils" "2.10.1"
"@nuxt/config" "2.10.2"
"@nuxt/utils" "2.10.2"
"@nuxtjs/youch" "^4.2.3"
chalk "^2.4.2"
compression "^1.7.4"
@ -1317,10 +1317,10 @@
serve-static "^1.14.1"
server-destroy "^1.0.1"
"@nuxt/utils@2.10.1":
version "2.10.1"
resolved "https://registry.yarnpkg.com/@nuxt/utils/-/utils-2.10.1.tgz#273f14519354b7676aa8640456716967c0b56857"
integrity sha512-SXTm0vSh3H6Izpib/p0IepopmKaJz4JUtSuHVoauCv+CQMj09GRUeKwZ8SbXjBNQmGI+tdKedVlUUKKYY8R4LQ==
"@nuxt/utils@2.10.2":
version "2.10.2"
resolved "https://registry.yarnpkg.com/@nuxt/utils/-/utils-2.10.2.tgz#01df9e0e8e8b264b100f7247e869076a0dc64419"
integrity sha512-GBtQlGovu7inXwaKBsD+ayt//4yZAJAazlHibMoRJxK/O8gfhuGf/hINxB98ZpjhjttCuJ6nABUN90+e06ARtg==
dependencies:
consola "^2.10.1"
fs-extra "^8.1.0"
@ -1331,10 +1331,10 @@
signal-exit "^3.0.2"
ua-parser-js "^0.7.20"
"@nuxt/vue-app@2.10.1":
version "2.10.1"
resolved "https://registry.yarnpkg.com/@nuxt/vue-app/-/vue-app-2.10.1.tgz#76fc682d45faddf953044806a7c9f4ed0c6e6945"
integrity sha512-GyjBOwyngKrb4NeSRP5s8tr4ccu05FhwuaN+TIlXsRSaPYaGz7LnLsxp5UgHrgMJH8TqIB6k4b9syejR7FT8Jg==
"@nuxt/vue-app@2.10.2":
version "2.10.2"
resolved "https://registry.yarnpkg.com/@nuxt/vue-app/-/vue-app-2.10.2.tgz#eb92ce5e8d7f5cc511626366d3a0fe080d2f9354"
integrity sha512-aP5JWQaaimo/zMyoZg7aUqS6wYZq9jtDt/woKWOeuJJvnKE+youitazXbuVf+1l4c771b4AZMEuDW1duOfjDRA==
dependencies:
node-fetch "^2.6.0"
unfetch "^4.1.0"
@ -1346,13 +1346,13 @@
vue-template-compiler "^2.6.10"
vuex "^3.1.1"
"@nuxt/vue-renderer@2.10.1":
version "2.10.1"
resolved "https://registry.yarnpkg.com/@nuxt/vue-renderer/-/vue-renderer-2.10.1.tgz#80219f78cda19fd0e665ed05eccdfcf23e3ee956"
integrity sha512-gjI8/0U5Qe5ieaRW9Y7/a+QOePABgvp4zkUZCUdQKtjniJ3AMKpvppSORKIH0YJl1Uv+X/BY84MfjEnLYdB0AQ==
"@nuxt/vue-renderer@2.10.2":
version "2.10.2"
resolved "https://registry.yarnpkg.com/@nuxt/vue-renderer/-/vue-renderer-2.10.2.tgz#6d5bb0e2fba28688065c5b3fc2d1337138947c25"
integrity sha512-nvgTlAPQ0gWAF8lXMGqjkbl54xunVX+v4he8CGqE+6S2ipdLxahmpbtxMRlJeAaGzOdv+rB6tF33O2PF9cL84w==
dependencies:
"@nuxt/devalue" "^1.2.4"
"@nuxt/utils" "2.10.1"
"@nuxt/utils" "2.10.2"
consola "^2.10.1"
fs-extra "^8.1.0"
lru-cache "^5.1.1"
@ -1360,18 +1360,18 @@
vue-meta "^2.3.1"
vue-server-renderer "^2.6.10"
"@nuxt/webpack@2.10.1":
version "2.10.1"
resolved "https://registry.yarnpkg.com/@nuxt/webpack/-/webpack-2.10.1.tgz#515db338b5df1abc1fef1b196d21679ecc45b92e"
integrity sha512-AH88HI8mJPj6EcMztgsVbfEwcUT46kcAkgFpYbVeMmucf7IxChyS+uf1ev9q4+wWvw1B8Hp9enAIZXBfEIjYTg==
"@nuxt/webpack@2.10.2":
version "2.10.2"
resolved "https://registry.yarnpkg.com/@nuxt/webpack/-/webpack-2.10.2.tgz#8006c6a2240d026d6eb4b3d356f7af3871cef851"
integrity sha512-Hb/9VDORABVk4AFrMLWwoEk4UV4XL8W6Yp9PvuGZ0t4a82243gWEZ39veawQmRHRsO96fBJrzs4dzwKVnkLosg==
dependencies:
"@babel/core" "^7.6.4"
"@nuxt/babel-preset-app" "2.10.1"
"@nuxt/babel-preset-app" "2.10.2"
"@nuxt/friendly-errors-webpack-plugin" "^2.5.0"
"@nuxt/utils" "2.10.1"
"@nuxt/utils" "2.10.2"
babel-loader "^8.0.6"
cache-loader "^4.1.0"
caniuse-lite "^1.0.30000999"
caniuse-lite "^1.0.30001002"
chalk "^2.4.2"
consola "^2.10.1"
css-loader "^3.2.0"
@ -1379,7 +1379,7 @@
eventsource-polyfill "^0.9.6"
extract-css-chunks-webpack-plugin "^4.6.0"
file-loader "^4.2.0"
glob "^7.1.4"
glob "^7.1.5"
hard-source-webpack-plugin "^0.13.1"
hash-sum "^2.0.0"
html-webpack-plugin "^3.2.0"
@ -1388,7 +1388,7 @@
pify "^4.0.1"
postcss "^7.0.18"
postcss-import "^12.0.1"
postcss-import-resolver "^1.2.3"
postcss-import-resolver "^2.0.0"
postcss-loader "^3.0.0"
postcss-preset-env "^6.7.0"
postcss-url "^8.0.0"
@ -1400,8 +1400,8 @@
time-fix-plugin "^2.0.6"
url-loader "^2.2.0"
vue-loader "^15.7.1"
webpack "^4.41.0"
webpack-bundle-analyzer "^3.5.2"
webpack "^4.41.2"
webpack-bundle-analyzer "^3.6.0"
webpack-dev-middleware "^3.7.2"
webpack-hot-middleware "^2.25.0"
webpack-node-externals "^1.7.2"
@ -1949,6 +1949,19 @@
global "^4.3.2"
util-deprecate "^1.0.2"
"@storybook/addons@5.2.5":
version "5.2.5"
resolved "https://registry.yarnpkg.com/@storybook/addons/-/addons-5.2.5.tgz#e3e23d5ea6eb221df31e1a5d125be47454e9a0e8"
integrity sha512-CvMj7Bs3go9tv5rZuAvFwuwe8p/16LDCHS7+5nVFosvcL8nuN339V3rzakw8nLy/S6XKeZ1ACu4t3vYkreRE3w==
dependencies:
"@storybook/api" "5.2.5"
"@storybook/channels" "5.2.5"
"@storybook/client-logger" "5.2.5"
"@storybook/core-events" "5.2.5"
core-js "^3.0.1"
global "^4.3.2"
util-deprecate "^1.0.2"
"@storybook/api@5.2.4":
version "5.2.4"
resolved "https://registry.yarnpkg.com/@storybook/api/-/api-5.2.4.tgz#b0b3dbd93444d163a80b455fb877d816a37b3149"
@ -1972,6 +1985,29 @@
telejson "^3.0.2"
util-deprecate "^1.0.2"
"@storybook/api@5.2.5":
version "5.2.5"
resolved "https://registry.yarnpkg.com/@storybook/api/-/api-5.2.5.tgz#dcc68c873820485372a47c095a8fc5e4fb53a34c"
integrity sha512-JvLafqFVgA3dIWpLMoGNk4sRuogE5imhD6/g0d8DOwnCID9xowj5xIptSrCTKvGGGxuN3wWRGn6I2lEbY6969g==
dependencies:
"@storybook/channels" "5.2.5"
"@storybook/client-logger" "5.2.5"
"@storybook/core-events" "5.2.5"
"@storybook/router" "5.2.5"
"@storybook/theming" "5.2.5"
core-js "^3.0.1"
fast-deep-equal "^2.0.1"
global "^4.3.2"
lodash "^4.17.15"
memoizerific "^1.11.3"
prop-types "^15.6.2"
react "^16.8.3"
semver "^6.0.0"
shallow-equal "^1.1.0"
store2 "^2.7.1"
telejson "^3.0.2"
util-deprecate "^1.0.2"
"@storybook/channel-postmessage@5.2.4":
version "5.2.4"
resolved "https://registry.yarnpkg.com/@storybook/channel-postmessage/-/channel-postmessage-5.2.4.tgz#e3735bdce42156e54bf462083aebaf23245ab5c3"
@ -1983,6 +2019,17 @@
global "^4.3.2"
telejson "^3.0.2"
"@storybook/channel-postmessage@5.2.5":
version "5.2.5"
resolved "https://registry.yarnpkg.com/@storybook/channel-postmessage/-/channel-postmessage-5.2.5.tgz#47397e543a87ea525cbe93f7d85bd8533edc9127"
integrity sha512-GoiC6dUM3YfNKpvj3syxQIQJLHBnH61CfLJzz4xygmn+3keHtjtz6yPHaU4+00MSSP2uDzqePkjgXx4DcLedHA==
dependencies:
"@storybook/channels" "5.2.5"
"@storybook/client-logger" "5.2.5"
core-js "^3.0.1"
global "^4.3.2"
telejson "^3.0.2"
"@storybook/channels@5.2.4":
version "5.2.4"
resolved "https://registry.yarnpkg.com/@storybook/channels/-/channels-5.2.4.tgz#7ab5c9478517ddb9e8ac0c4188b408b9d7e6b7e4"
@ -1990,6 +2037,13 @@
dependencies:
core-js "^3.0.1"
"@storybook/channels@5.2.5":
version "5.2.5"
resolved "https://registry.yarnpkg.com/@storybook/channels/-/channels-5.2.5.tgz#d6ca2b490281dacb272096563fe760ccb353c4bb"
integrity sha512-I+zB3ym5ozBcNBqyzZbvB6gRIG/ZKKkqy5k6LwKd5NMx7NU7zU74+LQUBBOcSIrigj8kCArZz7rlgb0tlSKXxQ==
dependencies:
core-js "^3.0.1"
"@storybook/client-api@5.2.4":
version "5.2.4"
resolved "https://registry.yarnpkg.com/@storybook/client-api/-/client-api-5.2.4.tgz#2507a3a739a6f6b13e4afefb938a6f3eab34ed55"
@ -2011,6 +2065,27 @@
qs "^6.6.0"
util-deprecate "^1.0.2"
"@storybook/client-api@5.2.5":
version "5.2.5"
resolved "https://registry.yarnpkg.com/@storybook/client-api/-/client-api-5.2.5.tgz#53151a236b6ffc2088acc4535a08e010013e3278"
integrity sha512-n7CAZ3+DZ7EUdmXbq8mXRb+stOavC8GMw3CzjGSo8O6t4rFcMpZQAzjS0YRX1RG/CGFSv9d3R3TNvEBcBGTwRg==
dependencies:
"@storybook/addons" "5.2.5"
"@storybook/channel-postmessage" "5.2.5"
"@storybook/channels" "5.2.5"
"@storybook/client-logger" "5.2.5"
"@storybook/core-events" "5.2.5"
"@storybook/router" "5.2.5"
common-tags "^1.8.0"
core-js "^3.0.1"
eventemitter3 "^4.0.0"
global "^4.3.2"
is-plain-object "^3.0.0"
lodash "^4.17.15"
memoizerific "^1.11.3"
qs "^6.6.0"
util-deprecate "^1.0.2"
"@storybook/client-logger@5.2.4":
version "5.2.4"
resolved "https://registry.yarnpkg.com/@storybook/client-logger/-/client-logger-5.2.4.tgz#6ebe37cbc92e0efe27c7119f52d94f647fbb470c"
@ -2018,6 +2093,13 @@
dependencies:
core-js "^3.0.1"
"@storybook/client-logger@5.2.5":
version "5.2.5"
resolved "https://registry.yarnpkg.com/@storybook/client-logger/-/client-logger-5.2.5.tgz#6f386ac6f81b4a783c57d54bb328281abbea1bab"
integrity sha512-6DyYUrMgAvF+th0foH7UNz+2JJpRdvNbpvYKtvi/+hlvRIaI6AqANgLkPUgMibaif5TLzjCr0bLdAYcjeJz03w==
dependencies:
core-js "^3.0.1"
"@storybook/components@5.2.4":
version "5.2.4"
resolved "https://registry.yarnpkg.com/@storybook/components/-/components-5.2.4.tgz#9ecd080416eac4e8453030dd601cbeaa32ce4126"
@ -2042,6 +2124,31 @@
react-textarea-autosize "^7.1.0"
simplebar-react "^1.0.0-alpha.6"
"@storybook/components@5.2.5":
version "5.2.5"
resolved "https://registry.yarnpkg.com/@storybook/components/-/components-5.2.5.tgz#40190dafbee34f083182255d26c19a0ea50789c8"
integrity sha512-6NVaBJm5wY53e9k+2ZiL2ABsHghE1ssQciLTG3jJPahnM6rfkM8ue66rhxhP88jE9isT48JgOZOJepEyxDz/fg==
dependencies:
"@storybook/client-logger" "5.2.5"
"@storybook/theming" "5.2.5"
"@types/react-syntax-highlighter" "10.1.0"
"@types/react-textarea-autosize" "^4.3.3"
core-js "^3.0.1"
global "^4.3.2"
markdown-to-jsx "^6.9.1"
memoizerific "^1.11.3"
polished "^3.3.1"
popper.js "^1.14.7"
prop-types "^15.7.2"
react "^16.8.3"
react-dom "^16.8.3"
react-focus-lock "^1.18.3"
react-helmet-async "^1.0.2"
react-popper-tooltip "^2.8.3"
react-syntax-highlighter "^8.0.1"
react-textarea-autosize "^7.1.0"
simplebar-react "^1.0.0-alpha.6"
"@storybook/core-events@5.2.4":
version "5.2.4"
resolved "https://registry.yarnpkg.com/@storybook/core-events/-/core-events-5.2.4.tgz#210c968e96e2fc031cad1d3a09b06fa69ae433fc"
@ -2049,25 +2156,32 @@
dependencies:
core-js "^3.0.1"
"@storybook/core@5.2.4":
version "5.2.4"
resolved "https://registry.yarnpkg.com/@storybook/core/-/core-5.2.4.tgz#188509ac0eb0c85144816c385c21acfb5c8fbefd"
integrity sha512-r5kDgZETNawHxpsAPw+h+pRk6l/mJhsSHeDo9/OdYtYFW7lmk2gadViXOTM+6gIWc6vQ8y750bgkahmyIIY0nQ==
"@storybook/core-events@5.2.5":
version "5.2.5"
resolved "https://registry.yarnpkg.com/@storybook/core-events/-/core-events-5.2.5.tgz#62881164a4a01aa99ff0691e70eaed2dd58e229e"
integrity sha512-O5GM8XEBbYNbM6Z7a4H1bbnbO2cxQrXMhEwansC7a7YinQdkTPiuGxke3NiyK+7pLDh778kpQyjoCjXq6UfAoQ==
dependencies:
core-js "^3.0.1"
"@storybook/core@5.2.5":
version "5.2.5"
resolved "https://registry.yarnpkg.com/@storybook/core/-/core-5.2.5.tgz#cc04313480a1847aa6881420c675517cc400dc2e"
integrity sha512-R6A6VzSh++pB1a+9DsywW5Mlp0/eauQz1A8m2DrllWcTHTjbn0ZovlG5HBrKjpknFXpCWxkUKE4eTAE2tWsryA==
dependencies:
"@babel/plugin-proposal-class-properties" "^7.3.3"
"@babel/plugin-proposal-object-rest-spread" "^7.3.2"
"@babel/plugin-syntax-dynamic-import" "^7.2.0"
"@babel/plugin-transform-react-constant-elements" "^7.2.0"
"@babel/preset-env" "^7.4.5"
"@storybook/addons" "5.2.4"
"@storybook/channel-postmessage" "5.2.4"
"@storybook/client-api" "5.2.4"
"@storybook/client-logger" "5.2.4"
"@storybook/core-events" "5.2.4"
"@storybook/node-logger" "5.2.4"
"@storybook/router" "5.2.4"
"@storybook/theming" "5.2.4"
"@storybook/ui" "5.2.4"
"@storybook/addons" "5.2.5"
"@storybook/channel-postmessage" "5.2.5"
"@storybook/client-api" "5.2.5"
"@storybook/client-logger" "5.2.5"
"@storybook/core-events" "5.2.5"
"@storybook/node-logger" "5.2.5"
"@storybook/router" "5.2.5"
"@storybook/theming" "5.2.5"
"@storybook/ui" "5.2.5"
airbnb-js-shims "^1 || ^2"
ansi-to-html "^0.6.11"
autoprefixer "^9.4.9"
@ -2123,10 +2237,10 @@
webpack-dev-middleware "^3.7.0"
webpack-hot-middleware "^2.25.0"
"@storybook/node-logger@5.2.4":
version "5.2.4"
resolved "https://registry.yarnpkg.com/@storybook/node-logger/-/node-logger-5.2.4.tgz#52dc380c76bdac68de35e7d72efe920c3ba52a23"
integrity sha512-4OOzce02IAfrRv+Y7h3icyw6WIuDekpWF2eYjgYVVvAJYklCEwgeBTBCY0/2TJjPPTBDPUKHVP1Bdz3Vpci9pA==
"@storybook/node-logger@5.2.5":
version "5.2.5"
resolved "https://registry.yarnpkg.com/@storybook/node-logger/-/node-logger-5.2.5.tgz#87f53de795db6eed912b54d3cca82fd7b7857771"
integrity sha512-UNyXGOhOr4Bn9wKwBTZABTBXQzrgvGxPLSmvAFZuMx9ZhqoT/EXAuLUl0/wiJtkyuYpoOOskNwIdKxLBdTKS2w==
dependencies:
chalk "^2.4.2"
core-js "^3.0.1"
@ -2147,6 +2261,19 @@
memoizerific "^1.11.3"
qs "^6.6.0"
"@storybook/router@5.2.5":
version "5.2.5"
resolved "https://registry.yarnpkg.com/@storybook/router/-/router-5.2.5.tgz#a005332bc6aa1e7849503187ad50c41b3f3bef92"
integrity sha512-e6ElDAWSoEW1KSnsTbVwbpzaZ8CNWYw0Ok3b5AHfY2fuSH5L4l6s6k/bP7QSYqvWUeTvkFQYux7A2rOFCriAgA==
dependencies:
"@reach/router" "^1.2.1"
"@types/reach__router" "^1.2.3"
core-js "^3.0.1"
global "^4.3.2"
lodash "^4.17.15"
memoizerific "^1.11.3"
qs "^6.6.0"
"@storybook/theming@5.2.4":
version "5.2.4"
resolved "https://registry.yarnpkg.com/@storybook/theming/-/theming-5.2.4.tgz#79c99f65992082fdb4d39fb652db435dd6bebaca"
@ -2165,19 +2292,37 @@
prop-types "^15.7.2"
resolve-from "^5.0.0"
"@storybook/ui@5.2.4":
version "5.2.4"
resolved "https://registry.yarnpkg.com/@storybook/ui/-/ui-5.2.4.tgz#7116c9be0dcdcc5d5b425d998263de1e27cdc078"
integrity sha512-zsS43k1h4bWEW6oj9FNHlUL3niHoJJ8v7iqYbRtVM12rxrYhV3K8TGVG3LCuNB75i3Be0Myy+/RHA4x9kco08A==
"@storybook/theming@5.2.5":
version "5.2.5"
resolved "https://registry.yarnpkg.com/@storybook/theming/-/theming-5.2.5.tgz#9579e7944f61ded637d1d79be5fb859a617620f5"
integrity sha512-PGZNYrRgAhXFJKnktFpyyKlaDXEhtTi5XPq5ASVJrsPW6l963Mk2EMKSm4TCTxIJhs0Kx4cv2MnNZFDqHf47eg==
dependencies:
"@storybook/addons" "5.2.4"
"@storybook/api" "5.2.4"
"@storybook/channels" "5.2.4"
"@storybook/client-logger" "5.2.4"
"@storybook/components" "5.2.4"
"@storybook/core-events" "5.2.4"
"@storybook/router" "5.2.4"
"@storybook/theming" "5.2.4"
"@emotion/core" "^10.0.14"
"@emotion/styled" "^10.0.14"
"@storybook/client-logger" "5.2.5"
common-tags "^1.8.0"
core-js "^3.0.1"
deep-object-diff "^1.1.0"
emotion-theming "^10.0.14"
global "^4.3.2"
memoizerific "^1.11.3"
polished "^3.3.1"
prop-types "^15.7.2"
resolve-from "^5.0.0"
"@storybook/ui@5.2.5":
version "5.2.5"
resolved "https://registry.yarnpkg.com/@storybook/ui/-/ui-5.2.5.tgz#0c2c67216e4c808e39cdb48301cafde81b77d074"
integrity sha512-C+5KmeTtdG6xkGXPmFDHPxTcSvVohuFD1399fnzjYhfLlRJ04ix3g16rcyDTxRtrFgFidOyGHdzCypgkdaN8dQ==
dependencies:
"@storybook/addons" "5.2.5"
"@storybook/api" "5.2.5"
"@storybook/channels" "5.2.5"
"@storybook/client-logger" "5.2.5"
"@storybook/components" "5.2.5"
"@storybook/core-events" "5.2.5"
"@storybook/router" "5.2.5"
"@storybook/theming" "5.2.5"
copy-to-clipboard "^3.0.8"
core-js "^3.0.1"
core-js-pure "^3.0.1"
@ -2185,7 +2330,7 @@
fast-deep-equal "^2.0.1"
fuse.js "^3.4.4"
global "^4.3.2"
lodash "^4.17.11"
lodash "^4.17.15"
markdown-to-jsx "^6.9.3"
memoizerific "^1.11.3"
polished "^3.3.1"
@ -2204,13 +2349,13 @@
telejson "^3.0.2"
util-deprecate "^1.0.2"
"@storybook/vue@~5.2.4":
version "5.2.4"
resolved "https://registry.yarnpkg.com/@storybook/vue/-/vue-5.2.4.tgz#cc5c61612b50e77e1de18d266434dea40631bcc9"
integrity sha512-JmEGypIl9FOtIp13n4ATa1nPeRr2PMnJ3DgKSs8O8GeuX61cOtZMZ95dvgGW0vfXh8hnzqt83WTkJP7EH/qpEQ==
"@storybook/vue@~5.2.5":
version "5.2.5"
resolved "https://registry.yarnpkg.com/@storybook/vue/-/vue-5.2.5.tgz#7c8d89aa7e5d5e747b1bcf52a42fb727ba00542a"
integrity sha512-Zml08pITm/2dFfOS0ToxMZdNrA4YoJNDuKqlSUfA7gsQsD5gJDCH8EiPbPNXOZM6/h30uGSqybYVz30c7py0dg==
dependencies:
"@storybook/addons" "5.2.4"
"@storybook/core" "5.2.4"
"@storybook/addons" "5.2.5"
"@storybook/core" "5.2.5"
"@types/webpack-env" "^1.13.9"
common-tags "^1.8.0"
core-js "^3.0.1"
@ -2509,6 +2654,13 @@
dependencies:
"@types/react" "*"
"@types/react-textarea-autosize@^4.3.3":
version "4.3.4"
resolved "https://registry.yarnpkg.com/@types/react-textarea-autosize/-/react-textarea-autosize-4.3.4.tgz#9a93f751c91ad5e86387bce75e3b7e11ed195813"
integrity sha512-LLqG27BJGt8ja9x4umQXbnK9pRd0dI23X/GXBcuf476feOZ+e5QiKJYmWOHwAJC3YLl3YixDSigzfF4gzVQZ5w==
dependencies:
"@types/react" "*"
"@types/react@*":
version "16.9.2"
resolved "https://registry.yarnpkg.com/@types/react/-/react-16.9.2.tgz#6d1765431a1ad1877979013906731aae373de268"
@ -3832,10 +3984,10 @@ async-retry@^1.2.1:
dependencies:
retry "0.12.0"
async-validator@^3.1.0:
version "3.1.0"
resolved "https://registry.yarnpkg.com/async-validator/-/async-validator-3.1.0.tgz#447db5eb003cbb47e650f040037a29fc3881ce92"
integrity sha512-XyAHGwtpx3Y3aHIOaGXXFo4tiulnrh+mXBU9INxig6Q8rtmtmBxDuCxb60j7EIGbAsQg9cxfJ2jrUZ+fIqEnBQ==
async-validator@^3.2.0:
version "3.2.0"
resolved "https://registry.yarnpkg.com/async-validator/-/async-validator-3.2.0.tgz#fcbd644e7b5b7c9304d29a4752c3f06214ef0d56"
integrity sha512-QBuW7Qrg8wbh7Wtqw1QdN162GUmXDs9gayxFaXcCOf3bCqHJ/TQep0H4I63iVk7Q3kIGWU4wbAr/C0Uj64JiMw==
async@^1.4.0:
version "1.5.2"
@ -4894,10 +5046,10 @@ caniuse-lite@^1.0.30000980, caniuse-lite@^1.0.30000981, caniuse-lite@^1.0.300009
resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30000989.tgz#b9193e293ccf7e4426c5245134b8f2a56c0ac4b9"
integrity sha512-vrMcvSuMz16YY6GSVZ0dWDTJP8jqk3iFQ/Aq5iqblPwxSVVZI+zxDyTX0VPqtQsDnfdrBDcsmhgTEOh5R8Lbpw==
caniuse-lite@^1.0.30000999:
version "1.0.30000999"
resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30000999.tgz#427253a69ad7bea4aa8d8345687b8eec51ca0e43"
integrity sha512-1CUyKyecPeksKwXZvYw0tEoaMCo/RwBlXmEtN5vVnabvO0KPd9RQLcaAuR9/1F+KDMv6esmOFWlsXuzDk+8rxg==
caniuse-lite@^1.0.30001002:
version "1.0.30001002"
resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001002.tgz#ba999a737b1abd5bf0fd47efe43a09b9cadbe9b0"
integrity sha512-pRuxPE8wdrWmVPKcDmJJiGBxr6lFJq4ivdSeo9FTmGj5Rb8NX3Mby2pARG57MXF15hYAhZ0nHV5XxT2ig4bz3g==
capture-exit@^2.0.0:
version "2.0.0"
@ -5029,10 +5181,10 @@ chokidar@^2.0.2, chokidar@^2.0.4, chokidar@^2.1.5:
optionalDependencies:
fsevents "^1.2.7"
chokidar@^3.2.1:
version "3.2.1"
resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-3.2.1.tgz#4634772a1924512d990d4505957bf3a510611387"
integrity sha512-/j5PPkb5Feyps9e+jo07jUZGvkB5Aj953NrI4s8xSVScrAo/RHeILrtdb4uzR7N6aaFFxxJ+gt8mA8HfNpw76w==
chokidar@^3.2.2:
version "3.2.2"
resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-3.2.2.tgz#a433973350021e09f2b853a2287781022c0dc935"
integrity sha512-bw3pm7kZ2Wa6+jQWYP/c7bAZy3i4GwiIiMO2EeRjrE48l8vBqC/WvFhSF0xyM8fQiPEGvwMY/5bqDG7sSEOuhg==
dependencies:
anymatch "~3.1.1"
braces "~3.0.2"
@ -5040,9 +5192,9 @@ chokidar@^3.2.1:
is-binary-path "~2.1.0"
is-glob "~4.0.1"
normalize-path "~3.0.0"
readdirp "~3.1.3"
readdirp "~3.2.0"
optionalDependencies:
fsevents "~2.1.0"
fsevents "~2.1.1"
chownr@^1.1.1:
version "1.1.1"
@ -6585,16 +6737,6 @@ end-of-stream@^1.0.0, end-of-stream@^1.1.0:
dependencies:
once "^1.4.0"
enhanced-resolve@^3.4.1:
version "3.4.1"
resolved "https://registry.yarnpkg.com/enhanced-resolve/-/enhanced-resolve-3.4.1.tgz#0421e339fd71419b3da13d129b3979040230476e"
integrity sha1-BCHjOf1xQZs9oT0Smzl5BAIwR24=
dependencies:
graceful-fs "^4.1.2"
memory-fs "^0.4.0"
object-assign "^4.0.1"
tapable "^0.2.7"
enhanced-resolve@^4.1.0:
version "4.1.0"
resolved "https://registry.yarnpkg.com/enhanced-resolve/-/enhanced-resolve-4.1.0.tgz#41c7e0bfdfe74ac1ffe1e57ad6a5c6c9f3742a7f"
@ -6604,6 +6746,15 @@ enhanced-resolve@^4.1.0:
memory-fs "^0.4.0"
tapable "^1.0.0"
enhanced-resolve@^4.1.1:
version "4.1.1"
resolved "https://registry.yarnpkg.com/enhanced-resolve/-/enhanced-resolve-4.1.1.tgz#2937e2b8066cd0fe7ce0990a98f0d71a35189f66"
integrity sha512-98p2zE+rL7/g/DzMHMTF4zZlCgeVdJ7yr6xzEpJRYwFYrGi9ANdn5DnJURg6RpBkyk60XYDnWIv51VfIhfNGuA==
dependencies:
graceful-fs "^4.1.2"
memory-fs "^0.5.0"
tapable "^1.0.0"
entities@^1.1.1, entities@~1.1.1:
version "1.1.2"
resolved "https://registry.yarnpkg.com/entities/-/entities-1.1.2.tgz#bdfa735299664dfafd34529ed4f8522a275fea56"
@ -7030,7 +7181,7 @@ execa@^1.0.0:
signal-exit "^3.0.0"
strip-eof "^1.0.0"
execa@^2.0.4, execa@^2.1.0:
execa@^2.0.4:
version "2.1.0"
resolved "https://registry.yarnpkg.com/execa/-/execa-2.1.0.tgz#e5d3ecd837d2a60ec50f3da78fd39767747bbe99"
integrity sha512-Y/URAVapfbYy2Xp/gb6A0E7iR8xeqOCXsuuaoMn7A5PzrXUK84E1gyiEfq0wQd/GHA6GsoHWwhNq8anb0mleIw==
@ -7045,6 +7196,22 @@ execa@^2.0.4, execa@^2.1.0:
signal-exit "^3.0.2"
strip-final-newline "^2.0.0"
execa@^3.2.0:
version "3.2.0"
resolved "https://registry.yarnpkg.com/execa/-/execa-3.2.0.tgz#18326b79c7ab7fbd6610fd900c1b9e95fa48f90a"
integrity sha512-kJJfVbI/lZE1PZYDI5VPxp8zXPO9rtxOkhpZ0jMKha56AI9y2gGVC6bkukStQf0ka5Rh15BA5m7cCCH4jmHqkw==
dependencies:
cross-spawn "^7.0.0"
get-stream "^5.0.0"
human-signals "^1.1.1"
is-stream "^2.0.0"
merge-stream "^2.0.0"
npm-run-path "^4.0.0"
onetime "^5.1.0"
p-finally "^2.0.0"
signal-exit "^3.0.2"
strip-final-newline "^2.0.0"
exit@^0.1.2:
version "0.1.2"
resolved "https://registry.yarnpkg.com/exit/-/exit-0.1.2.tgz#0632638f8d877cc82107d30a0fff1a17cba1cd0c"
@ -7192,6 +7359,11 @@ extsprintf@^1.2.0:
resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.4.0.tgz#e2689f8f356fad62cca65a3a91c5df5f9551692f"
integrity sha1-4mifjzVvrWLMplo6kcXfX5VRaS8=
faker@^4.1.0:
version "4.1.0"
resolved "https://registry.yarnpkg.com/faker/-/faker-4.1.0.tgz#1e45bbbecc6774b3c195fad2835109c6d748cc3f"
integrity sha1-HkW7vsxndLPBlfrSg1EJxtdIzD8=
fast-deep-equal@^2.0.1:
version "2.0.1"
resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-2.0.1.tgz#7b05218ddf9667bf7f370bf7fdb2cb15fdd0aa49"
@ -7638,10 +7810,10 @@ fsevents@^1.2.7:
nan "^2.12.1"
node-pre-gyp "^0.12.0"
fsevents@~2.1.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.1.0.tgz#ce1a5f9ac71c6d75278b0c5bd236d7dfece4cbaa"
integrity sha512-+iXhW3LuDQsno8dOIrCIT/CBjeBWuP7PXe8w9shnj9Lebny/Gx1ZjVBYwexLz36Ri2jKuXMNpV6CYNh8lHHgrQ==
fsevents@~2.1.1:
version "2.1.1"
resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.1.1.tgz#74c64e21df71721845d0c44fe54b7f56b82995a9"
integrity sha512-4FRPXWETxtigtJW/gxzEDsX1LVbPAM93VleB83kZB+ellqbHMkyt2aJfuzNLRvFPnGi6bcE5SvfxgbXPeKteJw==
fstream@^1.0.0, fstream@^1.0.12:
version "1.0.12"
@ -7848,6 +8020,18 @@ glob@7.1.4, glob@^7.0.0, glob@^7.0.3, glob@^7.0.5, glob@^7.1.1, glob@^7.1.2, glo
once "^1.3.0"
path-is-absolute "^1.0.0"
glob@^7.1.5:
version "7.1.5"
resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.5.tgz#6714c69bee20f3c3e64c4dd905553e532b40cdc0"
integrity sha512-J9dlskqUXK1OeTOYBEn5s8aMukWMwWfs+rPTn/jn50Ux4MNXVhubL1wu/j2t+H4NVI+cXEcCaYellqaPVGXNqQ==
dependencies:
fs.realpath "^1.0.0"
inflight "^1.0.4"
inherits "2"
minimatch "^3.0.4"
once "^1.3.0"
path-is-absolute "^1.0.0"
global-dirs@^0.1.0:
version "0.1.1"
resolved "https://registry.yarnpkg.com/global-dirs/-/global-dirs-0.1.1.tgz#b319c0dd4607f353f3be9cca4c72fc148c49f445"
@ -8556,6 +8740,11 @@ https-proxy-agent@^3.0.0:
agent-base "^4.3.0"
debug "^3.1.0"
human-signals@^1.1.1:
version "1.1.1"
resolved "https://registry.yarnpkg.com/human-signals/-/human-signals-1.1.1.tgz#c5b1cd14f50aeae09ab6c59fe63ba3395fe4dfa3"
integrity sha512-SEQu7vl8KjNL2eoGBLF3+wAjpsNfA9XMlXAYj/3EdaNfAlxKthD1xjEQfGOUhllCGGJVNY34bRr6lPINhNjyZw==
hyperlinker@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/hyperlinker/-/hyperlinker-1.0.0.tgz#23dc9e38a206b208ee49bc2d6c8ef47027df0c0e"
@ -10580,6 +10769,14 @@ memory-fs@^0.4.0, memory-fs@^0.4.1:
errno "^0.1.3"
readable-stream "^2.0.1"
memory-fs@^0.5.0:
version "0.5.0"
resolved "https://registry.yarnpkg.com/memory-fs/-/memory-fs-0.5.0.tgz#324c01288b88652966d161db77838720845a8e3c"
integrity sha512-jA0rdU5KoQMC0e6ppoNRtpp6vjFq6+NY7r8hywnC7V+1Xj/MtHwGIbB1QaK/dunyjWteJzmkpd7ooeWg10T7GA==
dependencies:
errno "^0.1.3"
readable-stream "^2.0.1"
meow@^3.7.0:
version "3.7.0"
resolved "https://registry.yarnpkg.com/meow/-/meow-3.7.0.tgz#72cb668b425228290abbfa856892587308a801fb"
@ -11260,6 +11457,13 @@ npm-run-path@^3.0.0:
dependencies:
path-key "^3.0.0"
npm-run-path@^4.0.0:
version "4.0.0"
resolved "https://registry.yarnpkg.com/npm-run-path/-/npm-run-path-4.0.0.tgz#d644ec1bd0569187d2a52909971023a0a58e8438"
integrity sha512-8eyAOAH+bYXFPSnNnKr3J+yoybe8O87Is5rtAQ8qRczJz1ajcsjg8l2oZqP+Ppx15Ii3S1vUTjQN2h4YO2tWWQ==
dependencies:
path-key "^3.0.0"
"npmlog@0 || 1 || 2 || 3 || 4", npmlog@^4.0.0, npmlog@^4.0.2, npmlog@^4.1.2:
version "4.1.2"
resolved "https://registry.yarnpkg.com/npmlog/-/npmlog-4.1.2.tgz#08a7f2a8bf734604779a9efa4ad5cc717abb954b"
@ -11299,18 +11503,18 @@ nuxt-env@~0.1.0:
resolved "https://registry.yarnpkg.com/nuxt-env/-/nuxt-env-0.1.0.tgz#8ac50b9ff45391ad3044ea932cbd05f06a585f87"
integrity sha512-7mTao3qG0zfN0hahk3O6SuDy0KEwYmNojammWQsMwhqMn3aUjX4nMYnWDa0pua+2/rwAY9oG53jQtLgJdG7f9w==
nuxt@~2.10.1:
version "2.10.1"
resolved "https://registry.yarnpkg.com/nuxt/-/nuxt-2.10.1.tgz#d02237baea11bfaa63d65e45231c41c6a7c18d49"
integrity sha512-75QQ3x1WAcoBb7krHLzSXVK2/TKUFCHfsskd0bbdAl1KI9Xweyd6SGtdgGsdjWOlaUhijsXFqrPnfPPmrpLMzQ==
nuxt@~2.10.2:
version "2.10.2"
resolved "https://registry.yarnpkg.com/nuxt/-/nuxt-2.10.2.tgz#15ade22dfe281095865df18e6f6e861fcad1ff95"
integrity sha512-BDeio2WwwMrW4bctRYNHq1su+rwIJzuo87bAZv8Xs2/Gw5g4bPIGZTiKGx6tSZBjxnONsGDOxhFOWZ5JpQEtrQ==
dependencies:
"@nuxt/builder" "2.10.1"
"@nuxt/cli" "2.10.1"
"@nuxt/core" "2.10.1"
"@nuxt/generator" "2.10.1"
"@nuxt/builder" "2.10.2"
"@nuxt/cli" "2.10.2"
"@nuxt/core" "2.10.2"
"@nuxt/generator" "2.10.2"
"@nuxt/loading-screen" "^1.2.0"
"@nuxt/opencollective" "^0.3.0"
"@nuxt/webpack" "2.10.1"
"@nuxt/webpack" "2.10.2"
nwsapi@^2.0.7:
version "2.1.4"
@ -12233,12 +12437,12 @@ postcss-image-set-function@^3.0.1:
postcss "^7.0.2"
postcss-values-parser "^2.0.0"
postcss-import-resolver@^1.2.3:
version "1.2.3"
resolved "https://registry.yarnpkg.com/postcss-import-resolver/-/postcss-import-resolver-1.2.3.tgz#a7f8f034f2b1774c90ae768e5927816ee3d869d7"
integrity sha512-7f+RZTagq9AjLYICk5TRLbjYAqGfOngRyNkKoV7MHcSew1FTatHliQuK/lg+eXuxppLy9wAfrFx15nxURMZmEg==
postcss-import-resolver@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/postcss-import-resolver/-/postcss-import-resolver-2.0.0.tgz#95c61ac5489047bd93ff42a9cd405cfe9041e2c0"
integrity sha512-y001XYgGvVwgxyxw9J1a5kqM/vtmIQGzx34g0A0Oy44MFcy/ZboZw1hu/iN3VYFjSTRzbvd7zZJJz0Kh0AGkTw==
dependencies:
enhanced-resolve "^3.4.1"
enhanced-resolve "^4.1.1"
postcss-import@^12.0.1:
version "12.0.1"
@ -13514,10 +13718,10 @@ readdirp@^2.2.1:
micromatch "^3.1.10"
readable-stream "^2.0.2"
readdirp@~3.1.3:
version "3.1.3"
resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-3.1.3.tgz#d6e011ed5b9240a92f08651eeb40f7942ceb6cc1"
integrity sha512-ZOsfTGkjO2kqeR5Mzr5RYDbTGYneSkdNKX2fOX2P5jF7vMrd/GNnIAUtDldeHHumHUCQ3V05YfWUdxMPAsRu9Q==
readdirp@~3.2.0:
version "3.2.0"
resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-3.2.0.tgz#c30c33352b12c96dfb4b895421a49fd5a9593839"
integrity sha512-crk4Qu3pmXwgxdSgGhgA/eXiJAPQiX4GMOZZMXnqKxHX7TaoL+3gQVo/WeuAiogr07DpnfjIMpXXa+PAIvwPGQ==
dependencies:
picomatch "^2.0.4"
@ -15192,11 +15396,6 @@ table@^5.2.3:
slice-ansi "^2.1.0"
string-width "^3.0.0"
tapable@^0.2.7:
version "0.2.9"
resolved "https://registry.yarnpkg.com/tapable/-/tapable-0.2.9.tgz#af2d8bbc9b04f74ee17af2b4d9048f807acd18a8"
integrity sha512-2wsvQ+4GwBvLPLWsNfLCDYGsW6xb7aeC6utq2Qh0PFwgEy7K7dsma9Jsmb2zSQj7GvYAyUGSntLtsv++GmgL1A==
tapable@^1.0.0, tapable@^1.0.0-beta.5, tapable@^1.1.3:
version "1.1.3"
resolved "https://registry.yarnpkg.com/tapable/-/tapable-1.1.3.tgz#a1fccc06b58db61fd7a45da2da44f5f3a3e67ba2"
@ -16387,10 +16586,10 @@ webidl-conversions@^4.0.2:
resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-4.0.2.tgz#a855980b1f0b6b359ba1d5d9fb39ae941faa63ad"
integrity sha512-YQ+BmxuTgd6UXZW3+ICGfyqRyHXVlD5GtQr5+qjiNW7bF0cqrzX500HVXPBOvgXb5YnzDd+h0zqyv61KUD7+Sg==
webpack-bundle-analyzer@^3.5.2:
version "3.5.2"
resolved "https://registry.yarnpkg.com/webpack-bundle-analyzer/-/webpack-bundle-analyzer-3.5.2.tgz#ac02834f4b31de8e27d71e6c7a612301ebddb79f"
integrity sha512-g9spCNe25QYUVqHRDkwG414GTok2m7pTTP0wr6l0J50Z3YLS04+BGodTqqoVBL7QfU/U/9p/oiI5XFOyfZ7S/A==
webpack-bundle-analyzer@^3.6.0:
version "3.6.0"
resolved "https://registry.yarnpkg.com/webpack-bundle-analyzer/-/webpack-bundle-analyzer-3.6.0.tgz#39b3a8f829ca044682bc6f9e011c95deb554aefd"
integrity sha512-orUfvVYEfBMDXgEKAKVvab5iQ2wXneIEorGNsyuOyVYpjYrI7CUOhhXNDd3huMwQ3vNNWWlGP+hzflMFYNzi2g==
dependencies:
acorn "^6.0.7"
acorn-walk "^6.1.1"
@ -16484,7 +16683,7 @@ webpack-sources@^1.4.3:
source-list-map "^2.0.0"
source-map "~0.6.1"
webpack@^4.33.0, webpack@^4.38.0, webpack@^4.41.0:
webpack@^4.33.0, webpack@^4.38.0:
version "4.41.0"
resolved "https://registry.yarnpkg.com/webpack/-/webpack-4.41.0.tgz#db6a254bde671769f7c14e90a1a55e73602fc70b"
integrity sha512-yNV98U4r7wX1VJAj5kyMsu36T8RPPQntcb5fJLOsMz/pt/WrKC0Vp1bAlqPLkA1LegSwQwf6P+kAbyhRKVQ72g==
@ -16513,6 +16712,35 @@ webpack@^4.33.0, webpack@^4.38.0, webpack@^4.41.0:
watchpack "^1.6.0"
webpack-sources "^1.4.1"
webpack@^4.41.2:
version "4.41.2"
resolved "https://registry.yarnpkg.com/webpack/-/webpack-4.41.2.tgz#c34ec76daa3a8468c9b61a50336d8e3303dce74e"
integrity sha512-Zhw69edTGfbz9/8JJoyRQ/pq8FYUoY0diOXqW0T6yhgdhCv6wr0hra5DwwWexNRns2Z2+gsnrNcbe9hbGBgk/A==
dependencies:
"@webassemblyjs/ast" "1.8.5"
"@webassemblyjs/helper-module-context" "1.8.5"
"@webassemblyjs/wasm-edit" "1.8.5"
"@webassemblyjs/wasm-parser" "1.8.5"
acorn "^6.2.1"
ajv "^6.10.2"
ajv-keywords "^3.4.1"
chrome-trace-event "^1.0.2"
enhanced-resolve "^4.1.0"
eslint-scope "^4.0.3"
json-parse-better-errors "^1.0.2"
loader-runner "^2.4.0"
loader-utils "^1.2.3"
memory-fs "^0.4.1"
micromatch "^3.1.10"
mkdirp "^0.5.1"
neo-async "^2.6.1"
node-libs-browser "^2.2.1"
schema-utils "^1.0.0"
tapable "^1.1.3"
terser-webpack-plugin "^1.4.1"
watchpack "^1.6.0"
webpack-sources "^1.4.1"
webpackbar@^4.0.0:
version "4.0.0"
resolved "https://registry.yarnpkg.com/webpackbar/-/webpackbar-4.0.0.tgz#ee7a87f16077505b5720551af413c8ecd5b1f780"

View File

@ -1965,10 +1965,10 @@ date-fns@^1.27.2:
resolved "https://registry.yarnpkg.com/date-fns/-/date-fns-1.30.1.tgz#2e71bf0b119153dbb4cc4e88d9ea5acfb50dc05c"
integrity sha512-hBSVCvSmWC+QypYObzwGOd9wqdDpOt+0wl0KbU+R+uuZBS1jN8VsD1ss3irQDknRj5NvxiTF6oj/nDRnN/UQNw==
date-fns@^2.5.0:
version "2.5.0"
resolved "https://registry.yarnpkg.com/date-fns/-/date-fns-2.5.0.tgz#b939f17c2902ce81cffe449702ba22c0781b38ec"
integrity sha512-I6Tkis01//nRcmvMQw/MRE1HAtcuA5Ie6jGPb8bJZJub7494LGOObqkV3ParnsSVviAjk5C8mNKDqYVBzCopWg==
date-fns@^2.5.1:
version "2.5.1"
resolved "https://registry.yarnpkg.com/date-fns/-/date-fns-2.5.1.tgz#6bd76f01d3a438e9c481d4c18512ddac37585b4c"
integrity sha512-ZBrQmuaqH9YqIejbgu8f09ki7wdD2JxWsRTZ/+HnnLNmkI56ty0evnWzKY+ihLT0xX5VdUX0vDNZCxJJGKX2+Q==
date-now@^0.1.4:
version "0.1.4"