Merge branch 'master' of github.com:Human-Connection/Human-Connection into donation-info

This commit is contained in:
mattwr18 2019-11-12 15:18:10 +01:00
commit 3b5e40efaa
78 changed files with 3373 additions and 867 deletions

View File

@ -35,7 +35,7 @@
},
"dependencies": {
"@hapi/joi": "^16.1.7",
"@sentry/node": "^5.7.1",
"@sentry/node": "^5.8.0",
"apollo-cache-inmemory": "~1.6.3",
"apollo-client": "~2.6.4",
"apollo-link-context": "~1.0.19",
@ -47,7 +47,7 @@
"cheerio": "~1.0.0-rc.3",
"cors": "~2.8.5",
"cross-env": "~6.0.3",
"date-fns": "2.6.0",
"date-fns": "2.7.0",
"debug": "~4.1.1",
"dotenv": "~8.2.0",
"express": "^4.17.1",
@ -63,7 +63,7 @@
"jsonwebtoken": "~8.5.1",
"linkifyjs": "~2.1.8",
"lodash": "~4.17.14",
"merge-graphql-schemas": "^1.7.2",
"merge-graphql-schemas": "^1.7.3",
"metascraper": "^4.10.3",
"metascraper-audio": "^5.7.17",
"metascraper-author": "^5.7.17",
@ -100,7 +100,7 @@
},
"devDependencies": {
"@babel/cli": "~7.7.0",
"@babel/core": "~7.6.4",
"@babel/core": "~7.7.2",
"@babel/node": "~7.7.0",
"@babel/plugin-proposal-throw-expressions": "^7.2.0",
"@babel/preset-env": "~7.7.1",
@ -115,7 +115,7 @@
"eslint-config-prettier": "~6.5.0",
"eslint-config-standard": "~14.1.0",
"eslint-plugin-import": "~2.18.2",
"eslint-plugin-jest": "~23.0.2",
"eslint-plugin-jest": "~23.0.3",
"eslint-plugin-node": "~10.0.0",
"eslint-plugin-prettier": "~3.1.1",
"eslint-plugin-promise": "~4.2.1",

View File

@ -19,7 +19,7 @@ const fetch = url => {
})
}
const locales = ['en', 'de', 'fr', 'nl', 'it', 'es', 'pt', 'pl']
const locales = ['en', 'de', 'fr', 'nl', 'it', 'es', 'pt', 'pl', 'ru']
const createLocation = async (session, mapboxData) => {
const data = {
@ -32,6 +32,7 @@ const createLocation = async (session, mapboxData) => {
nameES: mapboxData.text_es,
namePT: mapboxData.text_pt,
namePL: mapboxData.text_pl,
nameRU: mapboxData.text_ru,
type: mapboxData.id.split('.')[0].toLowerCase(),
lat: mapboxData.center && mapboxData.center.length ? mapboxData.center[0] : null,
lng: mapboxData.center && mapboxData.center.length ? mapboxData.center[1] : null,
@ -48,6 +49,7 @@ const createLocation = async (session, mapboxData) => {
'l.nameES = $nameES, ' +
'l.namePT = $namePT, ' +
'l.namePL = $namePL, ' +
'l.nameRU = $nameRU, ' +
'l.type = $type'
if (data.lat && data.lng) {

View File

@ -12,6 +12,7 @@ module.exports = {
nameDE: { type: 'string' },
nameNL: { type: 'string' },
namePL: { type: 'string' },
nameRU: { type: 'string' },
isIn: {
type: 'relationship',
relationship: 'IS_IN',

View File

@ -18,9 +18,8 @@ export default {
notifications: async (_parent, args, context, _resolveInfo) => {
const { user: currentUser } = context
const session = context.driver.session()
let notifications
let whereClause
let orderByClause
let notifications, whereClause, orderByClause
switch (args.read) {
case true:
whereClause = 'WHERE notification.read = TRUE'
@ -41,13 +40,15 @@ export default {
default:
orderByClause = ''
}
const offset = args.offset && typeof args.offset === 'number' ? `SKIP ${args.offset}` : ''
const limit = args.first && typeof args.first === 'number' ? `LIMIT ${args.first}` : ''
try {
const cypher = `
MATCH (resource {deleted: false, disabled: false})-[notification:NOTIFIED]->(user:User {id:$id})
${whereClause}
RETURN resource, notification, user
${orderByClause}
${offset} ${limit}
`
const result = await session.run(cypher, { id: currentUser.id })
notifications = await result.records.map(transformReturnType)
@ -77,4 +78,10 @@ export default {
return notification
},
},
NOTIFIED: {
id: async parent => {
// serialize an ID to help the client update the cache
return `${parent.reason}/${parent.from.id}/${parent.to.id}`
},
},
}

View File

@ -9,6 +9,7 @@ type Location {
nameES: String
namePT: String
namePL: String
nameRU: String
type: String!
lat: Float
lng: Float

View File

@ -1,8 +1,9 @@
type NOTIFIED {
id: ID!
from: NotificationSource
to: User
createdAt: String
updatedAt: String
createdAt: String!
updatedAt: String!
read: Boolean
reason: NotificationReason
}
@ -23,7 +24,7 @@ enum NotificationReason {
}
type Query {
notifications(read: Boolean, orderBy: NotificationOrdering): [NOTIFIED]
notifications(read: Boolean, orderBy: NotificationOrdering, first: Int, offset: Int): [NOTIFIED]
}
type Mutation {

View File

@ -42,6 +42,7 @@ const languages = ['de', 'en', 'es', 'fr', 'it', 'pt', 'pl']
nameDE: 'Hamburg',
nameNL: 'Hamburg',
namePL: 'Hamburg',
nameRU: 'Гамбург',
}),
factory.create('Location', {
id: 'region.14880313158564380',
@ -57,6 +58,7 @@ const languages = ['de', 'en', 'es', 'fr', 'it', 'pt', 'pl']
nameDE: 'Berlin',
nameNL: 'Berlijn',
namePL: 'Berlin',
nameRU: 'Берлин',
}),
factory.create('Location', {
id: 'country.10743216036480410',
@ -70,6 +72,7 @@ const languages = ['de', 'en', 'es', 'fr', 'it', 'pt', 'pl']
nameFR: 'Allemagne',
nameIT: 'Germania',
nameEN: 'Germany',
nameRU: 'Германия',
}),
factory.create('Location', {
id: 'region.9397217726497330',
@ -85,6 +88,7 @@ const languages = ['de', 'en', 'es', 'fr', 'it', 'pt', 'pl']
nameDE: 'Paris',
nameNL: 'Parijs',
namePL: 'Paryż',
nameRU: 'Париж',
}),
factory.create('Location', {
id: 'country.9759535382641660',
@ -98,6 +102,7 @@ const languages = ['de', 'en', 'es', 'fr', 'it', 'pt', 'pl']
nameFR: 'France',
nameIT: 'Francia',
nameEN: 'France',
nameRU: 'Франция',
}),
])
await Promise.all([

View File

@ -37,19 +37,19 @@
dependencies:
"@babel/highlight" "^7.0.0"
"@babel/core@^7.1.0", "@babel/core@~7.6.4":
version "7.6.4"
resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.6.4.tgz#6ebd9fe00925f6c3e177bb726a188b5f578088ff"
integrity sha512-Rm0HGw101GY8FTzpWSyRbki/jzq+/PkNQJ+nSulrdY6gFGOsNseCqD6KHRYe2E+EdzuBdr2pxCp6s4Uk6eJ+XQ==
"@babel/core@^7.1.0", "@babel/core@~7.7.2":
version "7.7.2"
resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.7.2.tgz#ea5b99693bcfc058116f42fa1dd54da412b29d91"
integrity sha512-eeD7VEZKfhK1KUXGiyPFettgF3m513f8FoBSWiQ1xTvl1RAopLs42Wp9+Ze911I6H0N9lNqJMDgoZT7gHsipeQ==
dependencies:
"@babel/code-frame" "^7.5.5"
"@babel/generator" "^7.6.4"
"@babel/helpers" "^7.6.2"
"@babel/parser" "^7.6.4"
"@babel/template" "^7.6.0"
"@babel/traverse" "^7.6.3"
"@babel/types" "^7.6.3"
convert-source-map "^1.1.0"
"@babel/generator" "^7.7.2"
"@babel/helpers" "^7.7.0"
"@babel/parser" "^7.7.2"
"@babel/template" "^7.7.0"
"@babel/traverse" "^7.7.2"
"@babel/types" "^7.7.2"
convert-source-map "^1.7.0"
debug "^4.1.0"
json5 "^2.1.0"
lodash "^4.17.13"
@ -57,22 +57,12 @@
semver "^5.4.1"
source-map "^0.5.0"
"@babel/generator@^7.4.0", "@babel/generator@^7.6.3", "@babel/generator@^7.6.4":
version "7.6.4"
resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.6.4.tgz#a4f8437287bf9671b07f483b76e3bb731bc97671"
integrity sha512-jsBuXkFoZxk0yWLyGI9llT9oiQ2FeTASmRFE32U+aaDTfoE92t78eroO7PTpU/OrYq38hlcDM6vbfLDaOLy+7w==
"@babel/generator@^7.4.0", "@babel/generator@^7.7.2":
version "7.7.2"
resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.7.2.tgz#2f4852d04131a5e17ea4f6645488b5da66ebf3af"
integrity sha512-WthSArvAjYLz4TcbKOi88me+KmDJdKSlfwwN8CnUYn9jBkzhq0ZEPuBfkAWIvjJ3AdEV1Cf/+eSQTnp3IDJKlQ==
dependencies:
"@babel/types" "^7.6.3"
jsesc "^2.5.1"
lodash "^4.17.13"
source-map "^0.5.0"
"@babel/generator@^7.7.0":
version "7.7.0"
resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.7.0.tgz#c6d4d1f7a0d6e139cbd01aca73170b0bff5425b4"
integrity sha512-1wdJ6UxHyL1XoJQ119JmvuRX27LRih7iYStMPZOWAjQqeAabFg3dYXKMpgihma+to+0ADsTVVt6oRyUxWZw6Mw==
dependencies:
"@babel/types" "^7.7.0"
"@babel/types" "^7.7.2"
jsesc "^2.5.1"
lodash "^4.17.13"
source-map "^0.5.0"
@ -133,15 +123,6 @@
"@babel/traverse" "^7.1.0"
"@babel/types" "^7.0.0"
"@babel/helper-function-name@^7.1.0":
version "7.1.0"
resolved "https://registry.yarnpkg.com/@babel/helper-function-name/-/helper-function-name-7.1.0.tgz#a0ceb01685f73355d4360c1247f582bfafc8ff53"
integrity sha512-A95XEoCpb3TO+KZzJ4S/5uW5fNe26DjBGqf1o9ucyLyCmi1dXq/B3c8iaWTfBk3VvetUxl16e8tIrd5teOCfGw==
dependencies:
"@babel/helper-get-function-arity" "^7.0.0"
"@babel/template" "^7.1.0"
"@babel/types" "^7.0.0"
"@babel/helper-function-name@^7.7.0":
version "7.7.0"
resolved "https://registry.yarnpkg.com/@babel/helper-function-name/-/helper-function-name-7.7.0.tgz#44a5ad151cfff8ed2599c91682dda2ec2c8430a3"
@ -321,14 +302,14 @@
"@babel/traverse" "^7.7.0"
"@babel/types" "^7.7.0"
"@babel/helpers@^7.6.2":
version "7.6.2"
resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.6.2.tgz#681ffe489ea4dcc55f23ce469e58e59c1c045153"
integrity sha512-3/bAUL8zZxYs1cdX2ilEE0WobqbCmKWr/889lf2SS0PpDcpEIY8pb1CCyz0pEcX3pEb+MCbks1jIokz2xLtGTA==
"@babel/helpers@^7.7.0":
version "7.7.0"
resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.7.0.tgz#359bb5ac3b4726f7c1fde0ec75f64b3f4275d60b"
integrity sha512-VnNwL4YOhbejHb7x/b5F39Zdg5vIQpUUNzJwx0ww1EcVRt41bbGRZWhAURrfY32T5zTT3qwNOQFWpn+P0i0a2g==
dependencies:
"@babel/template" "^7.6.0"
"@babel/traverse" "^7.6.2"
"@babel/types" "^7.6.0"
"@babel/template" "^7.7.0"
"@babel/traverse" "^7.7.0"
"@babel/types" "^7.7.0"
"@babel/highlight@^7.0.0":
version "7.5.0"
@ -352,15 +333,10 @@
regenerator-runtime "^0.13.3"
v8flags "^3.1.1"
"@babel/parser@^7.0.0", "@babel/parser@^7.1.0", "@babel/parser@^7.4.3", "@babel/parser@^7.6.0", "@babel/parser@^7.6.3", "@babel/parser@^7.6.4":
version "7.6.4"
resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.6.4.tgz#cb9b36a7482110282d5cb6dd424ec9262b473d81"
integrity sha512-D8RHPW5qd0Vbyo3qb+YjO5nvUVRTXFLQ/FsDxJU2Nqz4uB5EnUN0ZQSEYpvTIbRuttig1XbHWU5oMeQwQSAA+A==
"@babel/parser@^7.7.0":
version "7.7.0"
resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.7.0.tgz#232618f6e8947bc54b407fa1f1c91a22758e7159"
integrity sha512-GqL+Z0d7B7ADlQBMXlJgvXEbtt5qlqd1YQ5fr12hTSfh7O/vgrEIvJxU2e7aSVrEUn75zTZ6Nd0s8tthrlZnrQ==
"@babel/parser@^7.0.0", "@babel/parser@^7.1.0", "@babel/parser@^7.4.3", "@babel/parser@^7.7.0", "@babel/parser@^7.7.2":
version "7.7.2"
resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.7.2.tgz#ea8334dc77416bfd9473eb470fd00d8245b3943b"
integrity sha512-DDaR5e0g4ZTb9aP7cpSZLkACEBdoLGwJDWgHtBhrGX7Q1RjhdoMOfexICj5cqTAtpowjGQWfcvfnQG7G2kAB5w==
"@babel/plugin-proposal-async-generator-functions@^7.7.0":
version "7.7.0"
@ -795,16 +771,7 @@
dependencies:
regenerator-runtime "^0.13.2"
"@babel/template@^7.1.0", "@babel/template@^7.4.0", "@babel/template@^7.4.4", "@babel/template@^7.6.0":
version "7.6.0"
resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.6.0.tgz#7f0159c7f5012230dad64cca42ec9bdb5c9536e6"
integrity sha512-5AEH2EXD8euCk446b7edmgFdub/qfH1SN6Nii3+fyXP807QRx9Q73A2N5hNwRRslC2H9sNzaFhsPubkS4L8oNQ==
dependencies:
"@babel/code-frame" "^7.0.0"
"@babel/parser" "^7.6.0"
"@babel/types" "^7.6.0"
"@babel/template@^7.7.0":
"@babel/template@^7.1.0", "@babel/template@^7.4.0", "@babel/template@^7.4.4", "@babel/template@^7.7.0":
version "7.7.0"
resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.7.0.tgz#4fadc1b8e734d97f56de39c77de76f2562e597d0"
integrity sha512-OKcwSYOW1mhWbnTBgQY5lvg1Fxg+VyfQGjcBduZFljfc044J5iDlnDSfhQ867O17XHiSCxYHUxHg2b7ryitbUQ==
@ -813,40 +780,25 @@
"@babel/parser" "^7.7.0"
"@babel/types" "^7.7.0"
"@babel/traverse@^7.0.0", "@babel/traverse@^7.1.0", "@babel/traverse@^7.4.3", "@babel/traverse@^7.4.4", "@babel/traverse@^7.5.5", "@babel/traverse@^7.6.2", "@babel/traverse@^7.6.3":
version "7.6.3"
resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.6.3.tgz#66d7dba146b086703c0fb10dd588b7364cec47f9"
integrity sha512-unn7P4LGsijIxaAJo/wpoU11zN+2IaClkQAxcJWBNCMS6cmVh802IyLHNkAjQ0iYnRS3nnxk5O3fuXW28IMxTw==
"@babel/traverse@^7.0.0", "@babel/traverse@^7.1.0", "@babel/traverse@^7.4.3", "@babel/traverse@^7.4.4", "@babel/traverse@^7.5.5", "@babel/traverse@^7.7.0", "@babel/traverse@^7.7.2":
version "7.7.2"
resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.7.2.tgz#ef0a65e07a2f3c550967366b3d9b62a2dcbeae09"
integrity sha512-TM01cXib2+rgIZrGJOLaHV/iZUAxf4A0dt5auY6KNZ+cm6aschuJGqKJM3ROTt3raPUdIDk9siAufIFEleRwtw==
dependencies:
"@babel/code-frame" "^7.5.5"
"@babel/generator" "^7.6.3"
"@babel/helper-function-name" "^7.1.0"
"@babel/helper-split-export-declaration" "^7.4.4"
"@babel/parser" "^7.6.3"
"@babel/types" "^7.6.3"
debug "^4.1.0"
globals "^11.1.0"
lodash "^4.17.13"
"@babel/traverse@^7.7.0":
version "7.7.0"
resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.7.0.tgz#9f5744346b8d10097fd2ec2eeffcaf19813cbfaf"
integrity sha512-ea/3wRZc//e/uwCpuBX2itrhI0U9l7+FsrKWyKGNyvWbuMcCG7ATKY2VI4wlg2b2TA39HHwIxnvmXvtiKsyn7w==
dependencies:
"@babel/code-frame" "^7.5.5"
"@babel/generator" "^7.7.0"
"@babel/generator" "^7.7.2"
"@babel/helper-function-name" "^7.7.0"
"@babel/helper-split-export-declaration" "^7.7.0"
"@babel/parser" "^7.7.0"
"@babel/types" "^7.7.0"
"@babel/parser" "^7.7.2"
"@babel/types" "^7.7.2"
debug "^4.1.0"
globals "^11.1.0"
lodash "^4.17.13"
"@babel/types@^7.0.0", "@babel/types@^7.3.0", "@babel/types@^7.4.0", "@babel/types@^7.4.4", "@babel/types@^7.5.5", "@babel/types@^7.6.0", "@babel/types@^7.6.3", "@babel/types@^7.7.0", "@babel/types@^7.7.1":
version "7.7.1"
resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.7.1.tgz#8b08ea368f2baff236613512cf67109e76285827"
integrity sha512-kN/XdANDab9x1z5gcjDc9ePpxexkt+1EQ2MQUiM4XnMvQfvp87/+6kY4Ko2maLXH+tei/DgJ/ybFITeqqRwDiA==
"@babel/types@^7.0.0", "@babel/types@^7.3.0", "@babel/types@^7.4.0", "@babel/types@^7.4.4", "@babel/types@^7.5.5", "@babel/types@^7.7.0", "@babel/types@^7.7.1", "@babel/types@^7.7.2":
version "7.7.2"
resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.7.2.tgz#550b82e5571dcd174af576e23f0adba7ffc683f7"
integrity sha512-YTf6PXoh3+eZgRCBzzP25Bugd2ngmpQVrk7kXX0i5N9BO7TFBtIgZYs7WtxtOGs8e6A4ZI7ECkbBCEHeXocvOA==
dependencies:
esutils "^2.0.2"
lodash "^4.17.13"
@ -860,32 +812,33 @@
exec-sh "^0.3.2"
minimist "^1.2.0"
"@graphql-toolkit/common@0.6.7":
version "0.6.7"
resolved "https://registry.yarnpkg.com/@graphql-toolkit/common/-/common-0.6.7.tgz#9a23d51913c282fddef149b53dba54c69688f1cf"
integrity sha512-givchEE8hiqhGxX3EMiD0qMIyXRKcvpr50a7KozZL5POA8q3mQE3mXmJnJYllY2NRaFXqrNyHeaxwQO6XG85tw==
"@graphql-toolkit/common@0.6.8":
version "0.6.8"
resolved "https://registry.yarnpkg.com/@graphql-toolkit/common/-/common-0.6.8.tgz#7e80f4821d8484970d768b7cb19a0bc1e7a90784"
integrity sha512-vvxLMumGhFsSU/SPbMHsHPtr1WpD98EngSVzDoH4EfiobT8O9RKCaK/Nr57nWxbk1+A0iAC3OrHYugp46au5sQ==
dependencies:
"@kamilkisiela/graphql-tools" "4.0.6"
aggregate-error "3.0.1"
lodash "4.17.15"
"@graphql-toolkit/file-loading@0.6.7":
version "0.6.7"
resolved "https://registry.yarnpkg.com/@graphql-toolkit/file-loading/-/file-loading-0.6.7.tgz#fa19bd5c5562e55d26b3026f3bfb11f14146e84f"
integrity sha512-xhNWoV+QM1m0yKS09KCZHeiULKMV1BGJLHFHXO2xR4DD+N7Z1PmrF3utNh7yW41eAeZqVt4a8TBqFM3NnUz8aA==
"@graphql-toolkit/file-loading@0.6.8":
version "0.6.8"
resolved "https://registry.yarnpkg.com/@graphql-toolkit/file-loading/-/file-loading-0.6.8.tgz#6b03c752c2c5dd917172f7070cf92626e0fd83bf"
integrity sha512-kR7EizV5COWhYhkf0eq4/EAtGhbamjq3EvNifiFoRdGzJxIVwfD4If56rFAVCp7dBmUHl4mRG8RySydwIu1xGQ==
dependencies:
"@graphql-toolkit/common" "0.6.7"
"@graphql-toolkit/common" "0.6.8"
"@kamilkisiela/graphql-tools" "4.0.6"
glob "7.1.5"
glob "7.1.6"
"@graphql-toolkit/schema-merging@0.6.7":
version "0.6.7"
resolved "https://registry.yarnpkg.com/@graphql-toolkit/schema-merging/-/schema-merging-0.6.7.tgz#cd438ef45c82f490cae56a2699f553d4492d28d2"
integrity sha512-bzW/HlQY0YLW52Qeom4gq6Cc3fb887jP5TssoY8g0MlfZzRJS2I08Sb3oWVL2rBep7LllTTGRASM56se3FJG9A==
"@graphql-toolkit/schema-merging@0.6.8":
version "0.6.8"
resolved "https://registry.yarnpkg.com/@graphql-toolkit/schema-merging/-/schema-merging-0.6.8.tgz#67c0d83f9975026b20a69fca6a01f9b7d04ebbdb"
integrity sha512-/QhyfscZLqJLOgM0fD9Dxb5ps9OYyaOPxNS2mgjvX++jbNkJW2128b3KrB0nJzFdVEiOllRoaYHGKM4w8lvhmg==
dependencies:
"@graphql-toolkit/common" "0.6.7"
"@graphql-toolkit/common" "0.6.8"
"@kamilkisiela/graphql-tools" "4.0.6"
deepmerge "4.2.2"
tslib "1.10.0"
"@hapi/address@2.x.x", "@hapi/address@^2.1.2":
version "2.1.2"
@ -1201,44 +1154,44 @@
resolved "https://registry.yarnpkg.com/@protobufjs/utf8/-/utf8-1.1.0.tgz#a777360b5b39a1a2e5106f8e858f2fd2d060c570"
integrity sha1-p3c2C1s5oaLlEG+OhY8v0tBgxXA=
"@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==
"@sentry/core@5.8.0":
version "5.8.0"
resolved "https://registry.yarnpkg.com/@sentry/core/-/core-5.8.0.tgz#bbfd2f4711491951a8e3a0e8fa8b172fdf7bff6f"
integrity sha512-aAh2KLidIXJVGrxmHSVq2eVKbu7tZiYn5ylW6yzJXFetS5z4MA+JYaSBaG2inVYDEEqqMIkb17TyWxxziUDieg==
dependencies:
"@sentry/hub" "5.7.1"
"@sentry/minimal" "5.7.1"
"@sentry/hub" "5.8.0"
"@sentry/minimal" "5.8.0"
"@sentry/types" "5.7.1"
"@sentry/utils" "5.7.1"
"@sentry/utils" "5.8.0"
tslib "^1.9.3"
"@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==
"@sentry/hub@5.8.0":
version "5.8.0"
resolved "https://registry.yarnpkg.com/@sentry/hub/-/hub-5.8.0.tgz#56aaeb7324cb66d90db838011cb0127f5558007f"
integrity sha512-VdApn1ZCNwH1wwQwoO6pu53PM/qgHG+DQege0hbByluImpLBhAj9w50nXnF/8KzV4UoMIVbzCb6jXzMRmqqp9A==
dependencies:
"@sentry/types" "5.7.1"
"@sentry/utils" "5.7.1"
"@sentry/utils" "5.8.0"
tslib "^1.9.3"
"@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==
"@sentry/minimal@5.8.0":
version "5.8.0"
resolved "https://registry.yarnpkg.com/@sentry/minimal/-/minimal-5.8.0.tgz#b7ad5113504ab67f1ef2b0f465b7ba608e6b8dc5"
integrity sha512-MIlFOgd+JvAUrBBmq7vr9ovRH1HvckhnwzHdoUPpKRBN+rQgTyZy1o6+kA2fASCbrRqFCP+Zk7EHMACKg8DpIw==
dependencies:
"@sentry/hub" "5.7.1"
"@sentry/hub" "5.8.0"
"@sentry/types" "5.7.1"
tslib "^1.9.3"
"@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==
"@sentry/node@^5.8.0":
version "5.8.0"
resolved "https://registry.yarnpkg.com/@sentry/node/-/node-5.8.0.tgz#68ec032b0e7fb840cc8ccc1b39c09ac6febc1046"
integrity sha512-hIzt1BysyQJez8ChgWpFkLcGq3t/HaLMqzrXF5vu+Uuekl5OfwsvzZ+8Dlv78rI4CvlL9a2EuI/94iqUNwhOSQ==
dependencies:
"@sentry/core" "5.7.1"
"@sentry/hub" "5.7.1"
"@sentry/core" "5.8.0"
"@sentry/hub" "5.8.0"
"@sentry/types" "5.7.1"
"@sentry/utils" "5.7.1"
"@sentry/utils" "5.8.0"
cookie "^0.3.1"
https-proxy-agent "^3.0.0"
lru_map "^0.3.3"
@ -1249,10 +1202,10 @@
resolved "https://registry.yarnpkg.com/@sentry/types/-/types-5.7.1.tgz#4c4c1d4d891b6b8c2c3c7b367d306a8b1350f090"
integrity sha512-tbUnTYlSliXvnou5D4C8Zr+7/wJrHLbpYX1YkLXuIJRU0NSi81bHMroAuHWILcQKWhVjaV/HZzr7Y/hhWtbXVQ==
"@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==
"@sentry/utils@5.8.0":
version "5.8.0"
resolved "https://registry.yarnpkg.com/@sentry/utils/-/utils-5.8.0.tgz#34683088159b9935f973b6e6cad1a1cc26bbddac"
integrity sha512-KDxUvBSYi0/dHMdunbxAxD3389pcQioLtcO6CI6zt/nJXeVFolix66cRraeQvqupdLhvOk/el649W4fCPayTHw==
dependencies:
"@sentry/types" "5.7.1"
tslib "^1.9.3"
@ -2699,10 +2652,10 @@ content-type@~1.0.4:
resolved "https://registry.yarnpkg.com/content-type/-/content-type-1.0.4.tgz#e138cc75e040c727b1966fe5e5f8c9aee256fe3b"
integrity sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA==
convert-source-map@^1.1.0, convert-source-map@^1.4.0:
version "1.6.0"
resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-1.6.0.tgz#51b537a8c43e0f04dec1993bffcdd504e758ac20"
integrity sha512-eFu7XigvxdZ1ETfbgPBohgyQ/Z++C0eEhTor0qRwBw9unw+L0/6V8wkSuGgzdThkiS5lSpdptOQPD8Ak40a+7A==
convert-source-map@^1.1.0, convert-source-map@^1.4.0, convert-source-map@^1.7.0:
version "1.7.0"
resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-1.7.0.tgz#17a2cb882d7f77d3490585e2ce6c524424a3a442"
integrity sha512-4FJkXzKXEDB1snCFZlLP4gpC3JILicCpGbzG9f9G7tGqGCzETQ2hWPrcinA9oU4wtf2biUaEH5065UnMeR33oA==
dependencies:
safe-buffer "~5.1.1"
@ -2912,10 +2865,10 @@ data-urls@^1.0.0:
whatwg-mimetype "^2.2.0"
whatwg-url "^7.0.0"
date-fns@2.6.0:
version "2.6.0"
resolved "https://registry.yarnpkg.com/date-fns/-/date-fns-2.6.0.tgz#a5bc82e6a4c3995ae124b0ba1a71aec7b8cbd666"
integrity sha512-F55YxqRdEfP/eYQmQjLN798v0AwLjmZ8nMBjdQvNwEE3N/zWVrlkkqT+9seBlPlsbkybG4JmWg3Ee3dIV9BcGQ==
date-fns@2.7.0:
version "2.7.0"
resolved "https://registry.yarnpkg.com/date-fns/-/date-fns-2.7.0.tgz#8271d943cc4636a1f27698f1b8d6a9f1ceb74026"
integrity sha512-wxYp2PGoUDN5ZEACc61aOtYFvSsJUylIvCjpjDOqM1UDaKIIuMJ9fAnMYFHV3TQaDpfTVxhwNK/GiCaHKuemTA==
debug@2.6.9, debug@^2.2.0, debug@^2.3.3, debug@^2.6.8, debug@^2.6.9:
version "2.6.9"
@ -3389,10 +3342,10 @@ eslint-plugin-import@~2.18.2:
read-pkg-up "^2.0.0"
resolve "^1.11.0"
eslint-plugin-jest@~23.0.2:
version "23.0.2"
resolved "https://registry.yarnpkg.com/eslint-plugin-jest/-/eslint-plugin-jest-23.0.2.tgz#54a59bfe77245186afe13711a297067aefefff0a"
integrity sha512-fkxcvOJm0hC/jbJqYJjtuC9mvpTJqXd0Nixx7joVQvJoBQuXk/ws3+MtRYzD/4TcKSgvr21uuSLdwSxKJKC2cg==
eslint-plugin-jest@~23.0.3:
version "23.0.3"
resolved "https://registry.yarnpkg.com/eslint-plugin-jest/-/eslint-plugin-jest-23.0.3.tgz#d3f157f7791f97713372c13259ba1dfc436eb4c1"
integrity sha512-9cNxr66zeOyz1S9AkQL4/ouilR6QHpYj8vKOQZ60fu9hAt5PJWS4KqWqfr1aqN5NFEZSPjFOla2Azn+KTWiGwg==
dependencies:
"@typescript-eslint/experimental-utils" "^2.5.0"
@ -4028,7 +3981,19 @@ glob-parent@^5.0.0:
dependencies:
is-glob "^4.0.1"
glob@7.1.5, glob@^7.0.0, glob@^7.1.1, glob@^7.1.2, glob@^7.1.3, glob@^7.1.4:
glob@7.1.6:
version "7.1.6"
resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.6.tgz#141f33b81a7c2492e125594307480c46679278a6"
integrity sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==
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"
glob@^7.0.0, glob@^7.1.1, glob@^7.1.2, glob@^7.1.3, glob@^7.1.4:
version "7.1.5"
resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.5.tgz#6714c69bee20f3c3e64c4dd905553e532b40cdc0"
integrity sha512-J9dlskqUXK1OeTOYBEn5s8aMukWMwWfs+rPTn/jn50Ux4MNXVhubL1wu/j2t+H4NVI+cXEcCaYellqaPVGXNqQ==
@ -5751,13 +5716,13 @@ merge-descriptors@1.0.1:
resolved "https://registry.yarnpkg.com/merge-descriptors/-/merge-descriptors-1.0.1.tgz#b00aaa556dd8b44568150ec9d1b953f3f90cbb61"
integrity sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E=
merge-graphql-schemas@^1.7.2:
version "1.7.2"
resolved "https://registry.yarnpkg.com/merge-graphql-schemas/-/merge-graphql-schemas-1.7.2.tgz#a35f885ce718c28c7e39863199528f7f70439f2c"
integrity sha512-klLfSqh+2FkEl88Ix4n+ldcNHw0Y5un+pgDZaTzsz81dUQOHk+ai2fNfNwHRebtYfQUTGFiiykEPL0RhJwHzag==
merge-graphql-schemas@^1.7.3:
version "1.7.3"
resolved "https://registry.yarnpkg.com/merge-graphql-schemas/-/merge-graphql-schemas-1.7.3.tgz#220445a43b969564b874c580c4005fb7ebe3d473"
integrity sha512-qXROTOo3R/pfHYpPcrY59FCojdPGPUvyuh51FVeImrxVXEWulZ8tq0NZIFO5y8GK6/pl5m3FayJIhOJp/g1PkA==
dependencies:
"@graphql-toolkit/file-loading" "0.6.7"
"@graphql-toolkit/schema-merging" "0.6.7"
"@graphql-toolkit/file-loading" "0.6.8"
"@graphql-toolkit/schema-merging" "0.6.8"
tslib "1.10.0"
merge-stream@^2.0.0:

View File

@ -5,7 +5,7 @@ The kubernetes dashboard is optional but very helpful for debugging. If you want
```bash
# in folder deployment/digital-ocean/
$ kubectl apply -f dashboard/
$ kubectl apply -f https://raw.githubusercontent.com/kubernetes/dashboard/master/aio/deploy/recommended/kubernetes-dashboard.yaml
$ kubectl apply -f https://raw.githubusercontent.com/kubernetes/dashboard/v2.0.0-beta4/aio/deploy/recommended.yaml
```
### Login to your dashboard
@ -18,7 +18,7 @@ $ kubectl proxy
Visit:
[http://localhost:8001/api/v1/namespaces/kube-system/services/https:kubernetes-dashboard:/proxy/](http://localhost:8001/api/v1/namespaces/kube-system/services/https:kubernetes-dashboard:/proxy/)
[http://localhost:8001/api/v1/namespaces/kubernetes-dashboard/services/https:kubernetes-dashboard:/proxy/](http://localhost:8001/api/v1/namespaces/kubernetes-dashboard/services/https:kubernetes-dashboard:/proxy/)
You should see a login screen.

View File

@ -1,15 +1,16 @@
# Setup Ingress and HTTPS
Follow [this quick start guide](https://docs.cert-manager.io/en/latest/tutorials/acme/quick-start/index.html) and install certmanager via helm and tiller:
[This resource was also helpful](https://docs.cert-manager.io/en/latest/getting-started/install/kubernetes.html#installing-with-helm)
```text
```bash
$ kubectl create serviceaccount tiller --namespace=kube-system
$ kubectl create clusterrolebinding tiller-admin --serviceaccount=kube-system:tiller --clusterrole=cluster-admin
$ helm init --service-account=tiller
$ helm repo add jetstack https://charts.jetstack.io
$ helm repo update
$ helm install stable/nginx-ingress
$ kubectl apply -f https://raw.githubusercontent.com/jetstack/cert-manager/release-0.6/deploy/manifests/00-crds.yaml
$ helm install --name cert-manager --namespace cert-manager stable/cert-manager
$ kubectl apply -f https://raw.githubusercontent.com/jetstack/cert-manager/release-0.11/deploy/manifests/00-crds.yaml
$ helm install --name cert-manager --namespace cert-manager --version v0.11.0 jetstack/cert-manager
```
## Create Letsencrypt Issuers and Ingress Services

View File

@ -12,20 +12,20 @@ spec:
tls:
- hosts:
# - nitro-mailserver.human-connection.org
- nitro-staging.human-connection.org
- develop.human-connection.org
secretName: tls
rules:
- host: nitro-staging.human-connection.org
- host: develop.human-connection.org
http:
paths:
- path: /
backend:
serviceName: nitro-web
serviceName: web
servicePort: 3000
# - host: nitro-mailserver.human-connection.org
# http:
# paths:
# - path: /
# backend:
# serviceName: mailserver
# servicePort: 80
- host: mailserver.human-connection.org
http:
paths:
- path: /
backend:
serviceName: mailserver
servicePort: 80

View File

@ -1,47 +1,60 @@
---
apiVersion: extensions/v1beta1
apiVersion: apps/v1
kind: Deployment
metadata:
name: nitro-backend
creationTimestamp: null
labels:
human-connection.org/commit: COMMIT
human-connection.org/selector: deployment-human-connection-backend
name: backend
namespace: human-connection
spec:
replicas: 1
minReadySeconds: 15
progressDeadlineSeconds: 60
strategy:
rollingUpdate:
maxSurge: 0
maxUnavailable: "100%"
replicas: 1
revisionHistoryLimit: 2147483647
selector:
matchLabels:
human-connection.org/selector: deployment-human-connection-backend
strategy:
rollingUpdate:
maxSurge: 0
maxUnavailable: 100%
type: RollingUpdate
template:
metadata:
annotations:
backup.velero.io/backup-volumes: uploads
creationTimestamp: null
labels:
human-connection.org/commit: COMMIT
human-connection.org/selector: deployment-human-connection-backend
name: "nitro-backend"
name: backend
spec:
containers:
- name: nitro-backend
image: humanconnection/nitro-backend:latest
imagePullPolicy: Always
ports:
- containerPort: 4000
envFrom:
- envFrom:
- configMapRef:
name: configmap
- secretRef:
name: human-connection
image: humanconnection/nitro-backend:latest
imagePullPolicy: Always
name: nitro-backend
ports:
- containerPort: 4000
protocol: TCP
resources: {}
terminationMessagePath: /dev/termination-log
terminationMessagePolicy: File
volumeMounts:
- mountPath: /nitro-backend/public/uploads
name: uploads
dnsPolicy: ClusterFirst
restartPolicy: Always
schedulerName: default-scheduler
securityContext: {}
terminationGracePeriodSeconds: 30
volumes:
- name: uploads
persistentVolumeClaim:
claimName: uploads-claim
restartPolicy: Always
terminationGracePeriodSeconds: 30
status: {}

View File

@ -1,47 +1,61 @@
---
apiVersion: extensions/v1beta1
apiVersion: apps/v1
kind: Deployment
metadata:
name: nitro-neo4j
creationTimestamp: null
labels:
human-connection.org/selector: deployment-human-connection-neo4j
name: neo4j
namespace: human-connection
spec:
progressDeadlineSeconds: 2147483647
replicas: 1
strategy:
rollingUpdate:
maxSurge: 0
maxUnavailable: "100%"
revisionHistoryLimit: 2147483647
selector:
matchLabels:
human-connection.org/selector: deployment-human-connection-neo4j
strategy:
rollingUpdate:
maxSurge: 0
maxUnavailable: 100%
type: RollingUpdate
template:
metadata:
annotations:
backup.velero.io/backup-volumes: neo4j-data
creationTimestamp: null
labels:
human-connection.org/selector: deployment-human-connection-neo4j
name: nitro-neo4j
name: neo4j
spec:
containers:
- name: nitro-neo4j
image: humanconnection/neo4j:latest
imagePullPolicy: Always
resources:
requests:
memory: "2G"
limits:
memory: "8G"
envFrom:
- envFrom:
- configMapRef:
name: configmap
image: humanconnection/neo4j:latest
imagePullPolicy: Always
name: neo4j
ports:
- containerPort: 7687
protocol: TCP
- containerPort: 7474
protocol: TCP
resources:
limits:
memory: 2G
requests:
memory: 1G
terminationMessagePath: /dev/termination-log
terminationMessagePolicy: File
volumeMounts:
- mountPath: /data/
name: neo4j-data
dnsPolicy: ClusterFirst
restartPolicy: Always
schedulerName: default-scheduler
securityContext: {}
terminationGracePeriodSeconds: 30
volumes:
- name: neo4j-data
persistentVolumeClaim:
claimName: neo4j-data-claim
restartPolicy: Always
terminationGracePeriodSeconds: 30
status: {}

View File

@ -1,37 +1,54 @@
apiVersion: extensions/v1beta1
apiVersion: apps/v1
kind: Deployment
metadata:
name: nitro-web
namespace: human-connection
spec:
replicas: 2
minReadySeconds: 15
progressDeadlineSeconds: 60
selector:
matchLabels:
human-connection.org/selector: deployment-human-connection-web
template:
metadata:
creationTimestamp: null
labels:
human-connection.org/commit: COMMIT
human-connection.org/selector: deployment-human-connection-web
name: nitro-web
name: web
namespace: human-connection
spec:
minReadySeconds: 15
progressDeadlineSeconds: 60
replicas: 2
revisionHistoryLimit: 2147483647
selector:
matchLabels:
human-connection.org/selector: deployment-human-connection-web
strategy:
rollingUpdate:
maxSurge: 1
maxUnavailable: 1
type: RollingUpdate
template:
metadata:
creationTimestamp: null
labels:
human-connection.org/commit: COMMIT
human-connection.org/selector: deployment-human-connection-web
name: web
spec:
containers:
- name: web
- env:
- name: HOST
value: 0.0.0.0
envFrom:
- configMapRef:
name: configmap
- secretRef:
name: human-connection
env:
- name: HOST
value: 0.0.0.0
image: humanconnection/nitro-web:latest
imagePullPolicy: Always
name: web
ports:
- containerPort: 3000
protocol: TCP
resources: {}
imagePullPolicy: Always
terminationMessagePath: /dev/termination-log
terminationMessagePolicy: File
dnsPolicy: ClusterFirst
restartPolicy: Always
schedulerName: default-scheduler
securityContext: {}
terminationGracePeriodSeconds: 30
status: {}

View File

@ -1,34 +1,51 @@
---
apiVersion: extensions/v1beta1
apiVersion: apps/v1
kind: Deployment
metadata:
creationTimestamp: null
labels:
human-connection.org/selector: deployment-human-connection-mailserver
name: mailserver
namespace: human-connection
spec:
replicas: 1
minReadySeconds: 15
progressDeadlineSeconds: 60
replicas: 1
revisionHistoryLimit: 2147483647
selector:
matchLabels:
human-connection.org/selector: deployment-human-connection-mailserver
strategy:
rollingUpdate:
maxSurge: 1
maxUnavailable: 1
type: RollingUpdate
template:
metadata:
creationTimestamp: null
labels:
human-connection.org/selector: deployment-human-connection-mailserver
name: "mailserver"
name: mailserver
spec:
containers:
- name: mailserver
image: djfarrelly/maildev
imagePullPolicy: Always
ports:
- containerPort: 80
- containerPort: 25
envFrom:
- envFrom:
- configMapRef:
name: configmap
- secretRef:
name: human-connection
image: djfarrelly/maildev
imagePullPolicy: Always
name: mailserver
ports:
- containerPort: 80
protocol: TCP
- containerPort: 25
protocol: TCP
resources: {}
terminationMessagePath: /dev/termination-log
terminationMessagePolicy: File
dnsPolicy: ClusterFirst
restartPolicy: Always
schedulerName: default-scheduler
securityContext: {}
terminationGracePeriodSeconds: 30
status: {}

View File

@ -1,7 +1,7 @@
apiVersion: v1
kind: Service
metadata:
name: nitro-backend
name: backend
namespace: human-connection
labels:
human-connection.org/selector: deployment-human-connection-backend

View File

@ -1,7 +1,7 @@
apiVersion: v1
kind: Service
metadata:
name: nitro-neo4j
name: neo4j
namespace: human-connection
labels:
human-connection.org/selector: deployment-human-connection-neo4j

View File

@ -1,7 +1,7 @@
apiVersion: v1
kind: Service
metadata:
name: nitro-web
name: web
namespace: human-connection
labels:
human-connection.org/selector: deployment-human-connection-web

View File

@ -24,11 +24,11 @@
"bcryptjs": "^2.4.3",
"codecov": "^3.6.1",
"cross-env": "^6.0.3",
"cypress": "^3.6.0",
"cypress": "^3.6.1",
"cypress-cucumber-preprocessor": "^1.16.2",
"cypress-file-upload": "^3.4.0",
"cypress-file-upload": "^3.5.0",
"cypress-plugin-retries": "^1.4.0",
"date-fns": "^2.6.0",
"date-fns": "^2.7.0",
"dotenv": "^8.2.0",
"faker": "Marak/faker.js#master",
"graphql-request": "^1.8.2",

View File

@ -2,5 +2,5 @@
sed -i "s/<COMMIT>/${TRAVIS_COMMIT}/g" $TRAVIS_BUILD_DIR/scripts/patches/patch-deployment.yaml
sed -i "s/<COMMIT>/${TRAVIS_COMMIT}/g" $TRAVIS_BUILD_DIR/scripts/patches/patch-configmap.yaml
kubectl --namespace=human-connection patch configmap configmap -p "$(cat $TRAVIS_BUILD_DIR/scripts/patches/patch-configmap.yaml)"
kubectl --namespace=human-connection patch deployment nitro-backend -p "$(cat $TRAVIS_BUILD_DIR/scripts/patches/patch-deployment.yaml)"
kubectl --namespace=human-connection patch deployment nitro-web -p "$(cat $TRAVIS_BUILD_DIR/scripts/patches/patch-deployment.yaml)"
kubectl --namespace=human-connection patch deployment backend -p "$(cat $TRAVIS_BUILD_DIR/scripts/patches/patch-deployment.yaml)"
kubectl --namespace=human-connection patch deployment web -p "$(cat $TRAVIS_BUILD_DIR/scripts/patches/patch-deployment.yaml)"

View File

@ -13,6 +13,6 @@ tar xf doctl-1.14.0-linux-amd64.tar.gz
chmod +x ./doctl
sudo mv ./doctl /usr/local/bin/doctl
doctl auth init --access-token $DOCTL_ACCESS_TOKEN
doctl auth init --access-token $DIGITALOCEAN_ACCESS_TOKEN
mkdir -p ~/.kube/
doctl kubernetes cluster kubeconfig show nitro-staging > ~/.kube/config
doctl k8s cluster kubeconfig show develop > ~/.kube/config

View File

@ -0,0 +1,168 @@
import { config, mount, createLocalVue } from '@vue/test-utils'
import Vuex from 'vuex'
import VTooltip from 'v-tooltip'
import Styleguide from '@human-connection/styleguide'
import AvatarMenu from './AvatarMenu.vue'
import Filters from '~/plugins/vue-filters'
const localVue = createLocalVue()
localVue.use(Styleguide)
localVue.use(Vuex)
localVue.use(Filters)
localVue.use(VTooltip)
config.stubs['nuxt-link'] = '<span><slot /></span>'
config.stubs['router-link'] = '<span><slot /></span>'
describe('AvatarMenu.vue', () => {
let propsData, getters, wrapper, mocks
beforeEach(() => {
propsData = {}
mocks = {
$route: {
path: '',
},
$router: {
resolve: jest.fn(() => {
return { href: '/profile/u343/matt' }
}),
},
$t: jest.fn(a => a),
}
getters = {
'auth/user': () => {
return { id: 'u343', name: 'Matt' }
},
}
})
const Wrapper = () => {
const store = new Vuex.Store({
getters,
})
return mount(AvatarMenu, { propsData, localVue, store, mocks })
}
describe('mount', () => {
beforeEach(() => {
wrapper = Wrapper()
})
it('renders the HcAvatar component', () => {
wrapper.find('.avatar-menu-trigger').trigger('click')
expect(wrapper.find('.ds-avatar').exists()).toBe(true)
})
describe('given a userName', () => {
it('displays the userName', () => {
expect(wrapper.find('b').text()).toEqual('Matt')
})
})
describe('no userName', () => {
beforeEach(() => {
getters = {
'auth/user': () => {
return { id: 'u343' }
},
}
wrapper = Wrapper()
wrapper.find('.avatar-menu-trigger').trigger('click')
})
it('displays anonymous user', () => {
expect(wrapper.find('b').text()).toEqual('profile.userAnonym')
})
})
describe('menu items', () => {
beforeEach(() => {
getters = {
'auth/user': () => {
return { id: 'u343', slug: 'matt' }
},
'auth/isModerator': () => false,
'auth/isAdmin': () => false,
}
wrapper = Wrapper()
wrapper.find('.avatar-menu-trigger').trigger('click')
})
describe('role user', () => {
it('displays a link to user profile', () => {
const profileLink = wrapper
.findAll('.ds-menu-item span')
.at(wrapper.vm.routes.findIndex(route => route.path === '/profile/u343/matt'))
expect(profileLink.exists()).toBe(true)
})
it('displays a link to the notifications page', () => {
const notificationsLink = wrapper
.findAll('.ds-menu-item span')
.at(wrapper.vm.routes.findIndex(route => route.path === '/notifications'))
expect(notificationsLink.exists()).toBe(true)
})
it('displays a link to the settings page', () => {
const settingsLink = wrapper
.findAll('.ds-menu-item span')
.at(wrapper.vm.routes.findIndex(route => route.path === '/settings'))
expect(settingsLink.exists()).toBe(true)
})
})
describe('role moderator', () => {
beforeEach(() => {
getters = {
'auth/user': () => {
return { id: 'u343', slug: 'matt' }
},
'auth/isModerator': () => true,
'auth/isAdmin': () => false,
}
wrapper = Wrapper()
wrapper.find('.avatar-menu-trigger').trigger('click')
})
it('displays a link to moderation page', () => {
const moderationLink = wrapper
.findAll('.ds-menu-item span')
.at(wrapper.vm.routes.findIndex(route => route.path === '/moderation'))
expect(moderationLink.exists()).toBe(true)
})
it('displays a total of 4 links', () => {
const allLinks = wrapper.findAll('.ds-menu-item')
expect(allLinks).toHaveLength(4)
})
})
describe('role admin', () => {
beforeEach(() => {
getters = {
'auth/user': () => {
return { id: 'u343', slug: 'matt' }
},
'auth/isModerator': () => true,
'auth/isAdmin': () => true,
}
wrapper = Wrapper()
wrapper.find('.avatar-menu-trigger').trigger('click')
})
it('displays a link to admin page', () => {
const adminLink = wrapper
.findAll('.ds-menu-item span')
.at(wrapper.vm.routes.findIndex(route => route.path === '/admin'))
expect(adminLink.exists()).toBe(true)
})
it('displays a total of 5 links', () => {
const allLinks = wrapper.findAll('.ds-menu-item')
expect(allLinks).toHaveLength(5)
})
})
})
})
})

View File

@ -0,0 +1,17 @@
import { storiesOf } from '@storybook/vue'
import { withA11y } from '@storybook/addon-a11y'
import StoryRouter from 'storybook-vue-router'
import AvatarMenu from '~/components/AvatarMenu/AvatarMenu'
import helpers from '~/storybook/helpers'
helpers.init()
storiesOf('AvatarMenu', module)
.addDecorator(withA11y)
.addDecorator(helpers.layout)
.addDecorator(StoryRouter())
.add('dropdown', () => ({
components: { AvatarMenu },
store: helpers.store,
template: '<avatar-menu placement="top" />',
}))

View File

@ -0,0 +1,146 @@
<template>
<dropdown class="avatar-menu" offset="8" :placement="placement">
<template #default="{ toggleMenu }">
<a
class="avatar-menu-trigger"
:href="
$router.resolve({
name: 'profile-id-slug',
params: { id: user.id, slug: user.slug },
}).href
"
@click.prevent="toggleMenu"
>
<hc-avatar :user="user" />
<ds-icon size="xx-small" name="angle-down" />
</a>
</template>
<template #popover="{ closeMenu }">
<div class="avatar-menu-popover">
{{ $t('login.hello') }}
<b>{{ userName }}</b>
<template v-if="user.role !== 'user'">
<ds-text color="softer" size="small" style="margin-bottom: 0">
{{ user.role | camelCase }}
</ds-text>
</template>
<hr />
<ds-menu :routes="routes" :matcher="matcher">
<ds-menu-item
slot="menuitem"
slot-scope="item"
:route="item.route"
:parents="item.parents"
@click.native="closeMenu(false)"
>
<ds-icon :name="item.route.icon" />
{{ item.route.name }}
</ds-menu-item>
</ds-menu>
<hr />
<nuxt-link class="logout-link" :to="{ name: 'logout' }">
<ds-icon name="sign-out" />
{{ $t('login.logout') }}
</nuxt-link>
</div>
</template>
</dropdown>
</template>
<script>
import { mapGetters } from 'vuex'
import Dropdown from '~/components/Dropdown'
import HcAvatar from '~/components/Avatar/Avatar.vue'
export default {
components: {
Dropdown,
HcAvatar,
},
props: {
placement: { type: String, default: 'top-end' },
},
computed: {
...mapGetters({
user: 'auth/user',
isModerator: 'auth/isModerator',
isAdmin: 'auth/isAdmin',
}),
routes() {
if (!this.user.slug) {
return []
}
let routes = [
{
name: this.$t('profile.name'),
path: `/profile/${this.user.id}/${this.user.slug}`,
icon: 'user',
},
{
name: this.$t('notifications.pageLink'),
path: '/notifications',
icon: 'bell',
},
{
name: this.$t('settings.name'),
path: `/settings`,
icon: 'cogs',
},
]
if (this.isModerator) {
routes.push({
name: this.$t('moderation.name'),
path: `/moderation`,
icon: 'balance-scale',
})
}
if (this.isAdmin) {
routes.push({
name: this.$t('admin.name'),
path: `/admin`,
icon: 'shield',
})
}
return routes
},
userName() {
const { name } = this.user || {}
return name || this.$t('profile.userAnonym')
},
},
methods: {
matcher(url, route) {
if (url.indexOf('/profile') === 0) {
// do only match own profile
return this.$route.path === url
}
return this.$route.path.indexOf(url) === 0
},
},
}
</script>
<style lang="scss">
.avatar-menu {
margin: $space-xxx-small 0px 0px $space-xx-small;
}
.avatar-menu-trigger {
user-select: none;
display: flex;
align-items: center;
padding-left: $space-xx-small;
}
.avatar-menu-popover {
padding-top: $space-x-small;
padding-bottom: $space-x-small;
hr {
color: $color-neutral-90;
background-color: $color-neutral-90;
}
.logout-link {
color: $text-color-base;
padding-top: $space-xx-small;
&:hover {
color: $text-color-link-active;
}
}
}
</style>

View File

@ -0,0 +1,78 @@
import { mount, createLocalVue } from '@vue/test-utils'
import VTooltip from 'v-tooltip'
import Styleguide from '@human-connection/styleguide'
import DropdownFilter from './DropdownFilter.vue'
const localVue = createLocalVue()
localVue.use(Styleguide)
localVue.use(VTooltip)
describe('DropdownFilter.vue', () => {
let propsData, wrapper, mocks
beforeEach(() => {
propsData = {}
mocks = {
$t: jest.fn(a => a),
}
})
const Wrapper = () => {
return mount(DropdownFilter, { propsData, localVue, mocks })
}
describe('mount', () => {
beforeEach(() => {
wrapper = Wrapper()
})
describe('selected', () => {
it('displays selected filter', () => {
propsData.selected = 'Read'
wrapper = Wrapper()
expect(wrapper.find('.dropdown-filter label').text()).toEqual(propsData.selected)
})
})
describe('menu items', () => {
let allLink
beforeEach(() => {
propsData.filterOptions = [
{ label: 'All', value: null },
{ label: 'Read', value: true },
{ label: 'Unread', value: false },
]
wrapper = Wrapper()
wrapper.find('.dropdown-filter').trigger('click')
allLink = wrapper
.findAll('.dropdown-menu-item')
.at(propsData.filterOptions.findIndex(option => option.label === 'All'))
})
it('displays a link for All', () => {
expect(allLink.text()).toEqual('All')
})
it('displays a link for Read', () => {
const readLink = wrapper
.findAll('.dropdown-menu-item')
.at(propsData.filterOptions.findIndex(option => option.label === 'Read'))
expect(readLink.text()).toEqual('Read')
})
it('displays a link for Unread', () => {
const unreadLink = wrapper
.findAll('.dropdown-menu-item')
.at(propsData.filterOptions.findIndex(option => option.label === 'Unread'))
expect(unreadLink.text()).toEqual('Unread')
})
it('clicking on menu item emits filterNotifications', () => {
allLink.trigger('click')
expect(wrapper.emitted().filterNotifications[0]).toEqual(
propsData.filterOptions.filter(option => option.label === 'All'),
)
})
})
})
})

View File

@ -0,0 +1,30 @@
import { storiesOf } from '@storybook/vue'
import { withA11y } from '@storybook/addon-a11y'
import { action } from '@storybook/addon-actions'
import DropdownFilter from '~/components/DropdownFilter/DropdownFilter'
import helpers from '~/storybook/helpers'
helpers.init()
const filterOptions = [
{ label: 'All', value: null },
{ label: 'Read', value: true },
{ label: 'Unread', value: false },
]
storiesOf('DropdownFilter', module)
.addDecorator(withA11y)
.addDecorator(helpers.layout)
.add('filter dropdown', () => ({
components: { DropdownFilter },
data: () => ({
filterOptions,
selected: filterOptions[0].label,
}),
methods: {
filterNotifications: action('filterNotifications'),
},
template: `<dropdown-filter
@filterNotifications="filterNotifications"
:filterOptions="filterOptions"
:selected="selected"
/>`,
}))

View File

@ -0,0 +1,78 @@
<template>
<dropdown offset="8">
<a
:v-model="selected"
slot="default"
slot-scope="{ toggleMenu }"
name="dropdown"
class="dropdown-filter"
href="#"
@click.prevent="toggleMenu()"
>
<ds-icon style="margin-right: 2px;" name="filter" />
<label for="dropdown">{{ selected }}</label>
<ds-icon style="margin-left: 2px" size="xx-small" name="angle-down" />
</a>
<ds-menu
slot="popover"
slot-scope="{ toggleMenu }"
class="dropdown-menu-popover"
:routes="filterOptions"
>
<ds-menu-item
slot="menuitem"
slot-scope="item"
class="dropdown-menu-item"
:route="item.route"
:parents="item.parents"
@click.stop.prevent="filterNotifications(item.route, toggleMenu)"
>
{{ item.route.label }}
</ds-menu-item>
</ds-menu>
</dropdown>
</template>
<script>
import Dropdown from '~/components/Dropdown'
export default {
components: {
Dropdown,
},
props: {
selected: { type: String, default: '' },
filterOptions: { type: Array, default: () => [] },
},
methods: {
filterNotifications(option, toggleMenu) {
this.$emit('filterNotifications', option)
toggleMenu()
},
},
}
</script>
<style lang="scss">
.dropdown-filter {
user-select: none;
display: flex;
align-items: center;
height: 100%;
padding: $space-xx-small;
color: $text-color-soft;
}
.dropdown-menu {
user-select: none;
display: flex;
align-items: center;
height: 100%;
padding: $space-xx-small;
color: $text-color-soft;
}
.dropdown-menu-popover {
a {
padding: $space-x-small $space-small;
padding-right: $space-base;
}
}
</style>

View File

@ -0,0 +1,54 @@
import { shallowMount, createLocalVue } from '@vue/test-utils'
import Styleguide from '@human-connection/styleguide'
import Empty from './Empty.vue'
const localVue = createLocalVue()
localVue.use(Styleguide)
describe('Empty.vue', () => {
let propsData, wrapper
beforeEach(() => {
propsData = {}
})
const Wrapper = () => {
return shallowMount(Empty, { propsData, localVue })
}
describe('shallowMount', () => {
beforeEach(() => {
wrapper = Wrapper()
})
it('renders an image with an alert icon as default', () => {
expect(wrapper.find('img[alt="Empty"]').attributes().src).toBe('/img/empty/alert.svg')
})
describe('receives icon prop', () => {
it('renders an image with that icon', () => {
propsData.icon = 'messages'
wrapper = Wrapper()
expect(wrapper.find('img[alt="Empty"]').attributes().src).toBe(
`/img/empty/${propsData.icon}.svg`,
)
})
})
describe('receives message prop', () => {
it('renders that message', () => {
propsData.message = 'this is a custom message for Empty component'
wrapper = Wrapper()
expect(wrapper.find('.hc-empty-message').text()).toEqual(propsData.message)
})
})
describe('receives margin prop', () => {
it('sets margin to that margin', () => {
propsData.margin = 'xxx-small'
wrapper = Wrapper()
expect(wrapper.find('.hc-empty').attributes().margin).toEqual(propsData.margin)
})
})
})
})

View File

@ -0,0 +1,24 @@
import { storiesOf } from '@storybook/vue'
import { withA11y } from '@storybook/addon-a11y'
import HcEmpty from '~/components/Empty/Empty'
import helpers from '~/storybook/helpers'
helpers.init()
storiesOf('Empty', module)
.addDecorator(withA11y)
.addDecorator(helpers.layout)
.add(
'tasks icon with message',
() => ({
components: { HcEmpty },
template: '<hc-empty icon="tasks" message="Sorry, there are no ... available." />',
}),
{
notes: "Possible icons include 'messages', 'events', 'alert', 'tasks', 'docs', and 'file'",
},
)
.add('default icon, no message', () => ({
components: { HcEmpty },
template: '<hc-empty />',
}))

View File

@ -26,7 +26,7 @@ export default {
*/
icon: {
type: String,
required: true,
default: 'alert',
validator: value => {
return value.match(/(messages|events|alert|tasks|docs|file)/)
},

View File

@ -1,10 +1,12 @@
import { shallowMount, createLocalVue } from '@vue/test-utils'
import { config, shallowMount, createLocalVue } from '@vue/test-utils'
import Styleguide from '@human-connection/styleguide'
import Hashtag from './Hashtag'
const localVue = createLocalVue()
localVue.use(Styleguide)
config.stubs['nuxt-link'] = '<span><slot /></span>'
describe('Hashtag', () => {
let id

View File

@ -69,10 +69,9 @@ export default {
}
</script>
<style>
<style lang="scss">
.notification.read {
opacity: 0.6; /* Real browsers */
filter: alpha(opacity = 60); /* MSIE */
opacity: $opacity-soft;
}
.notifications-card {
min-width: 500px;

View File

@ -3,8 +3,8 @@ import NotificationList from './NotificationList'
import Notification from '../Notification/Notification'
import Vuex from 'vuex'
import Filters from '~/plugins/vue-filters'
import Styleguide from '@human-connection/styleguide'
import { notifications } from '~/components/utils/Notifications'
const localVue = createLocalVue()
@ -38,40 +38,7 @@ describe('NotificationList.vue', () => {
stubs = {
NuxtLink: RouterLinkStub,
}
propsData = {
notifications: [
{
read: false,
from: {
__typename: 'Post',
id: 'post-1',
title: 'some post title',
slug: 'some-post-title',
contentExcerpt: 'this is a post content',
author: {
id: 'john-1',
slug: 'john-doe',
name: 'John Doe',
},
},
},
{
read: false,
from: {
__typename: 'Post',
id: 'post-2',
title: 'another post title',
slug: 'another-post-title',
contentExcerpt: 'this is yet another post content',
author: {
id: 'john-1',
slug: 'john-doe',
name: 'John Doe',
},
},
},
],
}
propsData = { notifications }
})
describe('shallowMount', () => {
@ -110,15 +77,11 @@ describe('NotificationList.vue', () => {
describe('click on a notification', () => {
beforeEach(() => {
wrapper
.findAll('.notification-mention-post')
.at(1)
.trigger('click')
wrapper.find('.notification-mention-post').trigger('click')
})
it("emits 'markAsRead' with the id of the notification source", () => {
expect(wrapper.emitted('markAsRead')).toBeTruthy()
expect(wrapper.emitted('markAsRead')[0]).toEqual(['post-2'])
expect(wrapper.emitted('markAsRead')[0]).toEqual(['post-1'])
})
})
})

View File

@ -20,7 +20,7 @@ export default {
props: {
notifications: {
type: Array,
required: true,
default: () => [],
},
},
methods: {

View File

@ -50,7 +50,7 @@ describe('NotificationMenu.vue', () => {
beforeEach(() => {
data = () => {
return {
displayedNotifications: [
notifications: [
{
id: 'notification-41',
read: true,
@ -85,7 +85,7 @@ describe('NotificationMenu.vue', () => {
beforeEach(() => {
data = () => {
return {
displayedNotifications: [
notifications: [
{
id: 'notification-41',
read: false,

View File

@ -1,8 +1,8 @@
<template>
<ds-button v-if="!notificationsCount" class="notifications-menu" disabled icon="bell">
<ds-button v-if="!notifications.length" class="notifications-menu" disabled icon="bell">
{{ unreadNotificationsCount }}
</ds-button>
<dropdown v-else class="notifications-menu" :placement="placement">
<dropdown v-else class="notifications-menu" offset="8" :placement="placement">
<template slot="default" slot-scope="{ toggleMenu }">
<ds-button :primary="!!unreadNotificationsCount" icon="bell" @click.prevent="toggleMenu">
{{ unreadNotificationsCount }}
@ -10,7 +10,12 @@
</template>
<template slot="popover">
<div class="notifications-menu-popover">
<notification-list :notifications="displayedNotifications" @markAsRead="markAsRead" />
<notification-list :notifications="notifications" @markAsRead="markAsRead" />
</div>
<div class="notifications-link-container">
<nuxt-link :to="{ name: 'notifications' }">
{{ $t('notifications.pageLink') }}
</nuxt-link>
</div>
</template>
</dropdown>
@ -21,6 +26,7 @@ import Dropdown from '~/components/Dropdown'
import { NOTIFICATIONS_POLL_INTERVAL } from '~/constants/notifications'
import { notificationQuery, markAsReadMutation } from '~/graphql/User'
import NotificationList from '../NotificationList/NotificationList'
import unionBy from 'lodash/unionBy'
export default {
name: 'NotificationMenu',
@ -30,7 +36,6 @@ export default {
},
data() {
return {
displayedNotifications: [],
notifications: [],
}
},
@ -41,36 +46,21 @@ export default {
async markAsRead(notificationSourceId) {
const variables = { id: notificationSourceId }
try {
const {
data: { markAsRead },
} = await this.$apollo.mutate({
await this.$apollo.mutate({
mutation: markAsReadMutation(this.$i18n),
variables,
})
if (!(markAsRead && markAsRead.read === true)) return
this.displayedNotifications = this.displayedNotifications.map(n => {
return this.equalNotification(n, markAsRead) ? markAsRead : n
})
} catch (err) {
this.$toast.error(err.message)
}
},
equalNotification(a, b) {
return a.from.id === b.from.id && a.createdAt === b.createdAt && a.reason === b.reason
},
},
computed: {
notificationsCount() {
return (this.displayedNotifications || []).length
},
unreadNotificationsCount() {
let countUnread = 0
if (this.displayedNotifications) {
this.displayedNotifications.forEach(notification => {
if (!notification.read) countUnread++
})
}
return countUnread
const result = this.notifications.reduce((count, notification) => {
return notification.read ? count : count + 1
}, 0)
return result
},
},
apollo: {
@ -78,17 +68,17 @@ export default {
query() {
return notificationQuery(this.$i18n)
},
variables() {
return {
read: false,
orderBy: 'updatedAt_desc',
}
},
pollInterval: NOTIFICATIONS_POLL_INTERVAL,
update(data) {
const newNotifications = data.notifications.filter(newN => {
return !this.displayedNotifications.find(oldN => this.equalNotification(newN, oldN))
})
this.displayedNotifications = newNotifications
.concat(this.displayedNotifications)
.sort((a, b) => {
return new Date(b.createdAt) - new Date(a.createdAt)
})
return data.notifications
update({ notifications }) {
return unionBy(notifications, this.notifications, notification => notification.id).sort(
(a, b) => new Date(b.createdAt) - new Date(a.createdAt),
)
},
error(error) {
this.$toast.error(error.message)
@ -98,7 +88,7 @@ export default {
}
</script>
<style>
<style lang="scss">
.notifications-menu {
display: flex;
align-items: center;
@ -106,5 +96,16 @@ export default {
.notifications-menu-popover {
max-width: 500px;
margin-bottom: $size-height-base;
}
.notifications-link-container {
background-color: $background-color-softer-active;
text-align: center;
position: fixed;
bottom: 0;
left: 0;
right: 0;
height: $size-height-base;
padding: $space-x-small;
}
</style>

View File

@ -0,0 +1,174 @@
import { config, mount, createLocalVue, RouterLinkStub } from '@vue/test-utils'
import Styleguide from '@human-connection/styleguide'
import VTooltip from 'v-tooltip'
import Vuex from 'vuex'
import NotificationsTable from './NotificationsTable'
import Filters from '~/plugins/vue-filters'
import { notifications } from '~/components/utils/Notifications'
const localVue = createLocalVue()
localVue.use(Styleguide)
localVue.use(Filters)
localVue.use(VTooltip)
localVue.use(Vuex)
localVue.filter('truncate', string => string)
config.stubs['client-only'] = '<span><slot /></span>'
describe('NotificationsTable.vue', () => {
let wrapper, mocks, propsData, stubs
const postNotification = notifications[0]
const commentNotification = notifications[1]
beforeEach(() => {
mocks = {
$t: jest.fn(string => string),
}
stubs = {
NuxtLink: RouterLinkStub,
}
propsData = {}
})
describe('mount', () => {
const Wrapper = () => {
const store = new Vuex.Store({
getters: {
'auth/isModerator': () => false,
'auth/user': () => {
return {}
},
},
})
return mount(NotificationsTable, {
propsData,
mocks,
localVue,
store,
stubs,
})
}
beforeEach(() => {
wrapper = Wrapper()
})
describe('no notifications', () => {
it('renders HcEmpty component', () => {
expect(wrapper.find('.hc-empty').exists()).toBe(true)
})
})
describe('given notifications', () => {
beforeEach(() => {
propsData.notifications = notifications
wrapper = Wrapper()
})
it('renders a table', () => {
expect(wrapper.find('.ds-table').exists()).toBe(true)
})
describe('renders 4 columns', () => {
it('for icon', () => {
expect(wrapper.vm.fields.icon).toBeTruthy()
})
it('for user', () => {
expect(wrapper.vm.fields.user).toBeTruthy()
})
it('for post', () => {
expect(wrapper.vm.fields.post).toBeTruthy()
})
it('for content', () => {
expect(wrapper.vm.fields.content).toBeTruthy()
})
})
describe('Post', () => {
let firstRowNotification
beforeEach(() => {
firstRowNotification = wrapper.findAll('tbody tr').at(0)
})
it('renders the author', () => {
const username = firstRowNotification.find('.username')
expect(username.text()).toEqual(postNotification.from.author.name)
})
it('renders the reason for the notification', () => {
const dsTexts = firstRowNotification.findAll('.ds-text')
const reason = dsTexts.filter(
element => element.text() === 'notifications.reason.mentioned_in_post',
)
expect(reason.exists()).toBe(true)
})
it('renders a link to the Post', () => {
const postLink = firstRowNotification.find('a.notification-mention-post')
expect(postLink.text()).toEqual(postNotification.from.title)
})
it("renders the Post's content", () => {
const boldTags = firstRowNotification.findAll('b')
const content = boldTags.filter(
element => element.text() === postNotification.from.contentExcerpt,
)
expect(content.exists()).toBe(true)
})
})
describe('Comment', () => {
let secondRowNotification
beforeEach(() => {
secondRowNotification = wrapper.findAll('tbody tr').at(1)
})
it('renders the author', () => {
const username = secondRowNotification.find('.username')
expect(username.text()).toEqual(commentNotification.from.author.name)
})
it('renders the reason for the notification', () => {
const dsTexts = secondRowNotification.findAll('.ds-text')
const reason = dsTexts.filter(
element => element.text() === 'notifications.reason.mentioned_in_comment',
)
expect(reason.exists()).toBe(true)
})
it('renders a link to the Post', () => {
const postLink = secondRowNotification.find('a.notification-mention-post')
expect(postLink.text()).toEqual(commentNotification.from.post.title)
})
it("renders the Post's content", () => {
const boldTags = secondRowNotification.findAll('b')
const content = boldTags.filter(
element => element.text() === commentNotification.from.contentExcerpt,
)
expect(content.exists()).toBe(true)
})
})
describe('unread status', () => {
it('does not have class `notification-status`', () => {
expect(wrapper.find('.notification-status').exists()).toBe(false)
})
it('clicking on a Post link emits `markNotificationAsRead`', () => {
wrapper.find('a.notification-mention-post').trigger('click')
expect(wrapper.emitted().markNotificationAsRead[0][0]).toEqual(postNotification.from.id)
})
it('adds class `notification-status` when read is true', () => {
postNotification.read = true
wrapper = Wrapper()
expect(wrapper.find('.notification-status').exists()).toBe(true)
})
})
})
})
})

View File

@ -0,0 +1,86 @@
import { storiesOf } from '@storybook/vue'
import { withA11y } from '@storybook/addon-a11y'
import { action } from '@storybook/addon-actions'
import NotificationsTable from '~/components/NotificationsTable/NotificationsTable'
import helpers from '~/storybook/helpers'
import { post } from '~/components/PostCard/PostCard.story.js'
import { user } from '~/components/User/User.story.js'
helpers.init()
export const notifications = [
{
read: true,
reason: 'mentioned_in_post',
createdAt: '2019-10-29T15:36:02.106Z',
from: {
__typename: 'Post',
...post,
},
__typename: 'NOTIFIED',
index: 9,
},
{
read: false,
reason: 'commented_on_post',
createdAt: '2019-10-29T15:38:25.199Z',
from: {
__typename: 'Comment',
id: 'b6b38937-3efc-4d5e-b12c-549e4d6551a5',
createdAt: '2019-10-29T15:38:25.184Z',
updatedAt: '2019-10-29T15:38:25.184Z',
disabled: false,
deleted: false,
content:
'<p><a class="mention" href="/profile/u1" data-mention-id="u1" target="_blank">@peter-lustig</a> </p><p>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Turpis egestas pretium aenean pharetra magna ac placerat. Tempor id eu nisl nunc mi ipsum faucibus vitae. Nibh praesent tristique magna sit amet purus gravida quis blandit. Magna eget est lorem ipsum dolor. In fermentum posuere urna nec. Eleifend donec pretium vulputate sapien nec sagittis aliquam. Augue interdum velit euismod in pellentesque. Id diam maecenas ultricies mi eget mauris pharetra. Donec pretium vulputate sapien nec. Dolor morbi non arcu risus quis varius quam quisque. Blandit turpis cursus in hac habitasse. Est ultricies integer quis auctor elit sed vulputate mi sit. Nunc consequat interdum varius sit amet mattis vulputate enim. Semper feugiat nibh sed pulvinar. Eget felis eget nunc lobortis mattis aliquam. Ultrices vitae auctor eu augue. Tellus molestie nunc non blandit massa enim nec dui. Pharetra massa massa ultricies mi quis hendrerit dolor. Nisl suscipit adipiscing bibendum est ultricies integer.</p>',
contentExcerpt:
'<p><a href="/profile/u1" target="_blank">@peter-lustig</a> </p><p>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Turpis egestas pretium aenean pharetra …</p>',
...post,
author: user,
},
__typename: 'NOTIFIED',
index: 1,
},
{
read: false,
reason: 'mentioned_in_comment',
createdAt: '2019-10-29T15:38:13.422Z',
from: {
__typename: 'Comment',
id: 'b91f4d4d-b178-4e42-9764-7fbcbf097f4c',
createdAt: '2019-10-29T15:38:13.41Z',
updatedAt: '2019-10-29T15:38:13.41Z',
disabled: false,
deleted: false,
content:
'<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Turpis egestas pretium aenean pharetra magna ac placerat. Tempor id eu nisl nunc mi ipsum faucibus vitae. Nibh praesent tristique magna sit amet purus gravida quis blandit. Magna eget est lorem ipsum dolor. In fermentum posuere urna nec. Eleifend donec pretium vulputate sapien nec sagittis aliquam. Augue interdum velit euismod in pellentesque. Id diam maecenas ultricies mi eget mauris pharetra. Donec pretium vulputate sapien nec. Dolor morbi non arcu risus quis varius quam quisque. Blandit turpis cursus in hac habitasse. Est ultricies integer quis auctor elit sed vulputate mi sit. Nunc consequat interdum varius sit amet mattis vulputate enim. Semper feugiat nibh sed pulvinar. Eget felis eget nunc lobortis mattis aliquam. Ultrices vitae auctor eu augue. Tellus molestie nunc non blandit massa enim nec dui. Pharetra massa massa ultricies mi quis hendrerit dolor. Nisl suscipit adipiscing bibendum est ultricies integer.</p><p><a class="mention" href="/profile/u1" data-mention-id="u1" target="_blank">@peter-lustig</a> </p><p></p>',
contentExcerpt:
'<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Turpis egestas pretium aenean pharetra magna ac …</p>',
...post,
author: user,
},
__typename: 'NOTIFIED',
index: 2,
},
]
storiesOf('NotificationsTable', module)
.addDecorator(withA11y)
.addDecorator(helpers.layout)
.add('with notifications', () => ({
components: { NotificationsTable },
store: helpers.store,
data: () => ({
notifications,
}),
methods: {
markNotificationAsRead: action('markNotificationAsRead'),
},
template: `<notifications-table
@markNotificationAsRead="markNotificationAsRead"
:notifications="notifications"
/>`,
}))
.add('without notifications', () => ({
components: { NotificationsTable },
store: helpers.store,
template: `<notifications-table />`,
}))

View File

@ -0,0 +1,110 @@
<template>
<ds-table v-if="notifications && notifications.length" :data="notifications" :fields="fields">
<template #icon="scope">
<ds-icon
v-if="scope.row.from.post"
name="comment"
v-tooltip="{ content: $t('notifications.comment'), placement: 'right' }"
/>
<ds-icon
v-else
name="bookmark"
v-tooltip="{ content: $t('notifications.post'), placement: 'right' }"
/>
</template>
<template #user="scope">
<ds-space margin-bottom="base">
<client-only>
<hc-user
:user="scope.row.from.author"
:date-time="scope.row.from.createdAt"
:trunc="35"
:class="{ 'notification-status': scope.row.read }"
/>
</client-only>
</ds-space>
<ds-text :class="{ 'notification-status': scope.row.read, reason: true }">
{{ $t(`notifications.reason.${scope.row.reason}`) }}
</ds-text>
</template>
<template #post="scope">
<nuxt-link
class="notification-mention-post"
:class="{ 'notification-status': scope.row.read }"
:to="{
name: 'post-id-slug',
params: params(scope.row.from),
hash: hashParam(scope.row.from),
}"
@click.native="markNotificationAsRead(scope.row.from.id)"
>
<b>{{ scope.row.from.title || scope.row.from.post.title | truncate(50) }}</b>
</nuxt-link>
</template>
<template #content="scope">
<b :class="{ 'notification-status': scope.row.read }">
{{ scope.row.from.contentExcerpt | removeHtml }}
</b>
</template>
</ds-table>
<hc-empty v-else icon="alert" :message="$t('notifications.empty')" />
</template>
<script>
import HcUser from '~/components/User/User'
import HcEmpty from '~/components/Empty/Empty'
export default {
components: {
HcUser,
HcEmpty,
},
props: {
notifications: { type: Array, default: () => [] },
},
computed: {
fields() {
return {
icon: {
label: ' ',
width: '5',
},
user: {
label: this.$t('notifications.user'),
width: '45%',
},
post: {
label: this.$t('notifications.post'),
width: '25%',
},
content: {
label: this.$t('notifications.content'),
width: '25%',
},
}
},
},
methods: {
isComment(notificationSource) {
return notificationSource.__typename === 'Comment'
},
params(notificationSource) {
const post = this.isComment(notificationSource) ? notificationSource.post : notificationSource
return {
id: post.id,
slug: post.slug,
}
},
hashParam(notificationSource) {
return this.isComment(notificationSource) ? `#commentId-${notificationSource.id}` : ''
},
markNotificationAsRead(notificationSourceId) {
this.$emit('markNotificationAsRead', notificationSourceId)
},
},
}
</script>
<style lang="scss">
.notification-status {
opacity: $opacity-soft;
}
</style>

View File

@ -0,0 +1,72 @@
import { mount, createLocalVue } from '@vue/test-utils'
import Styleguide from '@human-connection/styleguide'
import Paginate from './Paginate'
const localVue = createLocalVue()
localVue.use(Styleguide)
describe('Paginate.vue', () => {
let propsData, wrapper, Wrapper, nextButton, backButton
beforeEach(() => {
propsData = {}
})
Wrapper = () => {
return mount(Paginate, { propsData, localVue })
}
describe('mount', () => {
beforeEach(() => {
wrapper = Wrapper()
})
describe('next button', () => {
beforeEach(() => {
propsData.hasNext = true
wrapper = Wrapper()
nextButton = wrapper.findAll('.ds-button').at(0)
})
it('is disabled by default', () => {
propsData = {}
wrapper = Wrapper()
nextButton = wrapper.findAll('.ds-button').at(0)
expect(nextButton.attributes().disabled).toEqual('disabled')
})
it('is not disabled if hasNext is true', () => {
expect(nextButton.attributes().disabled).toBeUndefined()
})
it('emits next when clicked', async () => {
await nextButton.trigger('click')
expect(wrapper.emitted().next).toHaveLength(1)
})
})
describe('back button', () => {
beforeEach(() => {
propsData.hasPrevious = true
wrapper = Wrapper()
backButton = wrapper.findAll('.ds-button').at(1)
})
it('is disabled by default', () => {
propsData = {}
wrapper = Wrapper()
backButton = wrapper.findAll('.ds-button').at(1)
expect(backButton.attributes().disabled).toEqual('disabled')
})
it('is not disabled if hasPrevious is true', () => {
expect(backButton.attributes().disabled).toBeUndefined()
})
it('emits back when clicked', async () => {
await backButton.trigger('click')
expect(wrapper.emitted().back).toHaveLength(1)
})
})
})
})

View File

@ -0,0 +1,28 @@
import { storiesOf } from '@storybook/vue'
import { withA11y } from '@storybook/addon-a11y'
import { action } from '@storybook/addon-actions'
import Paginate from '~/components/Paginate/Paginate'
import helpers from '~/storybook/helpers'
helpers.init()
storiesOf('Paginate', module)
.addDecorator(withA11y)
.addDecorator(helpers.layout)
.add('basic pagination', () => ({
components: { Paginate },
data: () => ({
hasNext: true,
hasPrevious: false,
}),
methods: {
back: action('back'),
next: action('next'),
},
template: `<paginate
:hasNext="hasNext"
:hasPrevious="hasPrevious"
@back="back"
@next="next"
/>`,
}))

View File

@ -0,0 +1,26 @@
<template>
<ds-flex direction="row-reverse">
<ds-flex-item width="50px">
<ds-button @click="next" :disabled="!hasNext" icon="arrow-right" primary />
</ds-flex-item>
<ds-flex-item width="50px">
<ds-button @click="back" :disabled="!hasPrevious" icon="arrow-left" primary />
</ds-flex-item>
</ds-flex>
</template>
<script>
export default {
props: {
hasNext: { type: Boolean, default: false },
hasPrevious: { type: Boolean, default: false },
},
methods: {
back() {
this.$emit('back')
},
next() {
this.$emit('next')
},
},
}
</script>

View File

@ -5,7 +5,7 @@ import helpers from '~/storybook/helpers'
helpers.init()
const post = {
export const post = {
id: 'd23a4265-f5f7-4e17-9f86-85f714b4b9f8',
title: 'Very nice Post Title',
contentExcerpt: '<p>My post content</p>',

View File

@ -5,7 +5,7 @@ import helpers from '~/storybook/helpers'
helpers.init()
const user = {
export const user = {
id: 'u6',
slug: 'louie',
name: 'Louie',

View File

@ -70,7 +70,7 @@
</ds-flex-item>
</ds-flex>
<ds-flex v-if="!itsMe" gutter="x-small" style="margin-bottom: 0;">
<ds-flex-item :width="{ base: 3 }">
<ds-flex-item>
<hc-follow-button
:follow-id="user.id"
:is-followed="user.followedByCurrentUser"
@ -78,11 +78,6 @@
@update="updateFollow"
/>
</ds-flex-item>
<ds-flex-item :width="{ base: 1 }">
<ds-button fullwidth>
<ds-icon name="user-times" />
</ds-button>
</ds-flex-item>
</ds-flex>
<!--<ds-space margin-bottom="x-small" />-->
</div>

View File

@ -0,0 +1,43 @@
export const notifications = [
{
read: false,
reason: 'mentioned_in_post',
from: {
__typename: 'Post',
id: 'post-1',
title: 'some post title',
slug: 'some-post-title',
contentExcerpt: 'this is a post content',
author: {
id: 'john-1',
slug: 'john-doe',
name: 'John Doe',
},
},
},
{
read: false,
reason: 'mentioned_in_comment',
from: {
__typename: 'Comment',
id: 'comment-2',
contentExcerpt: 'this is yet another post content',
post: {
id: 'post-1',
title: 'some post on a comment',
slug: 'some-post-on-a-comment',
contentExcerpt: 'this is a post content',
author: {
id: 'john-1',
slug: 'john-doe',
name: 'John Doe',
},
},
author: {
id: 'jane-1',
slug: 'jane-doe',
name: 'Jane Doe',
},
},
},
]

View File

@ -51,8 +51,9 @@ export const notificationQuery = i18n => {
${commentFragment(lang)}
${postFragment(lang)}
query {
notifications(read: false, orderBy: updatedAt_desc) {
query($read: Boolean, $orderBy: NotificationOrdering, $first: Int, $offset: Int) {
notifications(read: $read, orderBy: $orderBy, first: $first, offset: $offset) {
id
read
reason
createdAt
@ -81,6 +82,7 @@ export const markAsReadMutation = i18n => {
mutation($id: ID!) {
markAsRead(id: $id) {
id
read
reason
createdAt

View File

@ -71,52 +71,7 @@
<notification-menu placement="top" />
</client-only>
<client-only>
<dropdown class="avatar-menu" offset="8">
<template slot="default" slot-scope="{ toggleMenu }">
<a
class="avatar-menu-trigger"
:href="
$router.resolve({
name: 'profile-id-slug',
params: { id: user.id, slug: user.slug },
}).href
"
@click.prevent="toggleMenu"
>
<hc-avatar :user="user" />
<ds-icon size="xx-small" name="angle-down" />
</a>
</template>
<template slot="popover" slot-scope="{ closeMenu }">
<div class="avatar-menu-popover">
{{ $t('login.hello') }}
<b>{{ userName }}</b>
<template v-if="user.role !== 'user'">
<ds-text color="softer" size="small" style="margin-bottom: 0">
{{ user.role | camelCase }}
</ds-text>
</template>
<hr />
<ds-menu :routes="routes" :matcher="matcher">
<ds-menu-item
slot="menuitem"
slot-scope="item"
:route="item.route"
:parents="item.parents"
@click.native="closeMenu(false)"
>
<ds-icon :name="item.route.icon" />
{{ item.route.name }}
</ds-menu-item>
</ds-menu>
<hr />
<nuxt-link class="logout-link" :to="{ name: 'logout' }">
<ds-icon name="sign-out" />
{{ $t('login.logout') }}
</nuxt-link>
</div>
</template>
</dropdown>
<avatar-menu placement="top" />
</client-only>
</template>
</div>
@ -143,22 +98,20 @@ import { mapGetters, mapActions } from 'vuex'
import LocaleSwitch from '~/components/LocaleSwitch/LocaleSwitch'
import SearchInput from '~/components/SearchInput.vue'
import Modal from '~/components/Modal'
import NotificationMenu from '~/components/notifications/NotificationMenu/NotificationMenu'
import Dropdown from '~/components/Dropdown'
import HcAvatar from '~/components/Avatar/Avatar.vue'
import NotificationMenu from '~/components/NotificationMenu/NotificationMenu'
import seo from '~/mixins/seo'
import FilterPosts from '~/components/FilterPosts/FilterPosts.vue'
import CategoryQuery from '~/graphql/CategoryQuery.js'
import PageFooter from '~/components/PageFooter/PageFooter'
import AvatarMenu from '~/components/AvatarMenu/AvatarMenu'
export default {
components: {
Dropdown,
LocaleSwitch,
SearchInput,
Modal,
NotificationMenu,
HcAvatar,
AvatarMenu,
FilterPosts,
PageFooter,
},
@ -172,49 +125,10 @@ export default {
},
computed: {
...mapGetters({
user: 'auth/user',
isLoggedIn: 'auth/isLoggedIn',
isModerator: 'auth/isModerator',
isAdmin: 'auth/isAdmin',
quickSearchResults: 'search/quickResults',
quickSearchPending: 'search/quickPending',
}),
userName() {
const { name } = this.user || {}
return name || this.$t('profile.userAnonym')
},
routes() {
if (!this.user.slug) {
return []
}
let routes = [
{
name: this.$t('profile.name'),
path: `/profile/${this.user.slug}`,
icon: 'user',
},
{
name: this.$t('settings.name'),
path: `/settings`,
icon: 'cogs',
},
]
if (this.isModerator) {
routes.push({
name: this.$t('moderation.name'),
path: `/moderation`,
icon: 'balance-scale',
})
}
if (this.isAdmin) {
routes.push({
name: this.$t('admin.name'),
path: `/admin`,
icon: 'shield',
})
}
return routes
},
showFilterPostsDropdown() {
const [firstRoute] = this.$route.matched
return firstRoute && firstRoute.name === 'index'
@ -239,13 +153,6 @@ export default {
})
})
},
matcher(url, route) {
if (url.indexOf('/profile') === 0) {
// do only match own profile
return this.$route.path === url
}
return this.$route.path.indexOf(url) === 0
},
toggleMobileMenuView() {
this.toggleMobileMenu = !this.toggleMobileMenu
},
@ -289,45 +196,6 @@ export default {
.main-navigation-right .desktop-view {
float: right;
}
.avatar-menu {
margin: 2px 0px 0px 5px;
}
.avatar-menu-trigger {
user-select: none;
display: flex;
align-items: center;
padding-left: $space-xx-small;
}
.avatar-menu-popover {
padding-top: 0.5rem;
padding-bottom: 0.5rem;
hr {
color: $color-neutral-90;
background-color: $color-neutral-90;
}
.logout-link {
margin-left: -$space-small;
margin-right: -$space-small;
margin-top: -$space-xxx-small;
margin-bottom: -$space-x-small;
padding: $space-x-small $space-small;
// subtract menu border with from padding
padding-left: $space-small - 2;
color: $text-color-base;
&:hover {
color: $text-color-link-active;
}
}
nav {
margin-left: -$space-small;
margin-right: -$space-small;
margin-top: -$space-xx-small;
margin-bottom: -$space-xx-small;
a {
padding-left: 12px;
}
}
}
@media only screen and (min-width: 960px) {
.mobile-hamburger-menu {
display: none;

View File

@ -180,7 +180,18 @@
"mentioned_in_comment": "Hat dich in einem Kommentar erwähnt …",
"commented_on_post": "Hat deinen Beitrag kommentiert …"
},
"comment": "Kommentar"
"comment": "Kommentar",
"title": "Benachrichtigungen",
"pageLink": "Alle Benachrichtigungen",
"post": "Beitrag",
"user": "Benutzer",
"content": "Inhalt",
"filterLabel": {
"all": "Alle",
"read": "Gelesen ",
"unread": "Ungelesen"
},
"empty": "Sorry, du hast im Moment keine Benachrichtigungen."
},
"search": {
"placeholder": "Suchen",

View File

@ -181,7 +181,18 @@
"mentioned_in_comment": "Mentioned you in a comment …",
"commented_on_post": "Commented on your post …"
},
"comment": "Comment"
"comment": "Comment",
"title": "Notifications",
"pageLink": "All notifications",
"post": "Post",
"user": "User",
"content": "Content",
"filterLabel": {
"all": "All",
"read": "Read",
"unread": "Unread"
},
"empty": "Sorry, you don't have any notifications at the moment."
},
"search": {
"placeholder": "Search",

View File

@ -1,4 +1,4 @@
import { enUS, de, nl, fr, es, it, pt, pl } from 'date-fns/locale'
import { enUS, de, nl, fr, es, it, pt, pl, ru } from 'date-fns/locale'
import find from 'lodash/find'
const locales = [
@ -58,6 +58,13 @@ const locales = [
enabled: true,
dateFnsLocale: pl,
},
{
name: 'Русский',
code: 'ru',
iso: 'ru-RU',
enabled: true,
dateFnsLocale: ru,
},
]
export default locales

View File

@ -1,10 +1,106 @@
{
"components": {
"password-reset": {
"request": {
"title": "Redefinir sua senha",
"form": {
"description": "Um e-mail de redefinição de senha será enviado ao endereço de e-mail fornecido.",
"submit": "Solicitar e-mail",
"submitted": "Um e-mail com mais instruções foi enviado para <b>{email}</b>"
}
},
"change-password": {
"success": "A alteração da sua senha foi bem-sucedida!",
"error": "A alteração da sua senha falhou. Talvez o código de segurança não estava correto?",
"help": "Em caso de problemas, sinta-se à vontade para pedir ajuda, enviando um e-mail para:"
}
},
"enter-nonce": {
"form": {
"nonce": "Digite seu código",
"description": "Abra a sua caixa de entrada e digite o código que lhe enviamos.",
"next": "Continue",
"validations": {
"length": "deve ter 6 caracteres"
}
}
},
"registration": {
"signup": {
"unavailable": "Infelizmente, o registo público para usuário não está disponível neste servidor.",
"title": "Junte-se à Human Connection!",
"form": {
"description": "Para começar, digite seu endereço de e-mail:",
"terms-and-condition": "Eu concordo com os <a href=\"/terms-and-conditions\"><ds-text bold color=\"primary\" > Termos e condições</ds-text></a>.",
"data-privacy": "Eu li e entendi o <a href=\"https://human-connection.org/datenschutz/\" target=\"_blank\"><ds-text bold color=\"primary\" >Política de Privacidade</ds-text></a> ",
"minimum-age": "Tenho 18 anos ou mais.",
"invitation-code": "O seu código de convite é: <b>{code}</b>",
"errors": {
"email-exists": "Já existe uma conta de usuário com este endereço de e-mail!",
"invalid-invitation-token": "Parece que o convite já foi usado. Os links para convites só podem ser usados uma vez."
},
"submit": "Criar uma conta",
"success": "Um e-mail com um link para completar o seu registo foi enviado para <b>{email}</b>"
}
},
"create-user-account": {
"title": "Criar uma conta de usuário",
"success": "A sua conta foi criada!",
"error": "Nenhuma conta de usuário pode ser criada!",
"help": " Talvez a confirmação tenha sido inválida? Em caso de problemas, sinta-se à vontade para pedir ajuda, enviando um e-mail para:"
}
}
},
"store": {
"posts": {
"orderBy": {
"newest": {
"label": "Mais recentes"
},
"oldest": {
"label": "Mais antigos"
}
}
}
},
"maintenance": {
"title": "Human Connection está em manutenção",
"explanation": "No momento estamos em manutenção, por favor tente novamente mais tarde.",
"questions": "Qualquer dúvida, envie um e-mail para"
},
"index": {
"no-results": "Nenhuma contribuição encontrada.",
"change-filter-settings": "Altere suas configurações de filtro para obter mais resultados."
},
"filter-menu": {
"title": "Sua bolha de filtro",
"hashtag-search": "Procurando por #{hashtag}",
"clearSearch": "Limpar pesquisa"
},
"filter-posts": {
"categories": {
"header": "Categorias de Conteúdo",
"all": "Todos"
},
"general": {
"header": "Filtrar por …"
},
"followers": {
"label": "Usuários que eu sigo"
},
"language": {
"header": "Idiomas",
"all": "Todos"
}
},
"site": {
"thanks": "Obrigado(a)!",
"error-occurred": "Ocorreu um erro.",
"made": "Feito com &#10084;",
"imprint": "Impressão",
"termsAc": "Termos e Condições",
"termsAndConditions": "Termos e Condições",
"data-privacy": "Proteção de Dados",
"changelog": "Mudanças e Histórico",
"changelog": "Mudanças",
"contact": "Contato",
"tribunal": "tribunal de registo",
"register": "número de registo",
@ -14,7 +110,8 @@
"bank": "conta bancária",
"germany": "Alemanha",
"code-of-conduct": "Codigo de Conduto",
"login": "Voltar para o Login"
"back-to-login": "Voltar para o Login",
"faq": "FAQ"
},
"login": {
"copy": "Se você já tem uma conta no Human Connection, por favor faça o login.",
@ -22,15 +119,30 @@
"logout": "Sair",
"email": "Seu email",
"password": "Sua senha",
"forgotPassword": "Esqueceu a sua senha?",
"no-account": "Ainda não tem uma conta?",
"register": "Cadastrar-se",
"moreInfo": "O que é o Human Connection?",
"moreInfoURL": "https://human-connection.org/en/",
"hello": "Olá",
"forgotPassword": "Esqueceu a sua senha?"
"success": "Você está conectado!",
"failure": "Endereço de e-mail ou senha incorretos."
},
"password-reset": {
"form": {
"description": "Um e-mail de redefinição de senha será enviado para o endereço de e-mail fornecido.",
"submit": "Solicitar email",
"submitted": "Um e-mail com mais instruções foi enviado para <b>{email}</b>"
"editor": {
"placeholder": " Escreva algo inspirador…",
"mention": {
"noUsersFound": "Nenhum usuário encontrado"
},
"hashtag": {
"noHashtagsFound": "Nenhuma hashtag encontrada",
"addHashtag": "Nova hashtag",
"addLetter": "Digite uma letra"
},
"embed": {
"data_privacy_warning": "Aviso de Privacidade de Dados!",
"data_privacy_info": "Seus dados ainda não foram compartilhados com terceiros. Se continuar assistindo este vídeo, o seguinte fornecedor irá provavelmente recolher dados do utilizador:",
"play_now": "Assista agora",
"always_allow": "Sempre permita conteúdo incorporado por provedores de terceiros (esta configuração pode ser alterada a qualquer momento)"
}
},
"profile": {
@ -39,36 +151,174 @@
"follow": "Seguir",
"followers": "Seguidores",
"following": "Seguindo",
"shouted": "Aclamou",
"shouted": "Recomendou",
"commented": "Comentou",
"userAnonym": "Anonymous"
"userAnonym": "Anônimo",
"socialMedia": "Onde mais posso encontrar",
"network": {
"title": "Rede",
"following": "está seguindo:",
"followingNobody": "não segue ninguém.",
"followedBy": "é seguido por:",
"followedByNobody": "não é seguido por ninguém.",
"andMore": "e {number} mais …"
},
"invites": {
"title": "Convidar alguém para Human Connection!",
"description": "Digite o endereço de e-mail para o convite.",
"emailPlaceholder": "E-mail para convidar"
}
},
"notifications": {
"reason": {
"mentioned_in_post": "Mencionou você em uma publicação …",
"mentioned_in_comment": "Mencionou você em um comentário …",
"commented_on_post": "Comentou na sua publicação …"
},
"comment": "Comentário"
},
"search": {
"placeholder": "Pesquisar",
"hint": "O que você está pesquisando??",
"failed": "Nada foi encontrado"
},
"notifications": {
"reason": {
"mentioned_in_post": "Mencinou você em um post …",
"mentioned_in_comment": "Mentionou você em um comentário …",
"commented_on_post": "Comentou no seu post …"
},
"comment": "Comentário",
"title": "Notificações",
"pageLink": "Todas as notificações",
"post": "Post",
"user": "Usuário",
"content": "Conteúdo",
"filterLabel": {
"all": "Todos",
"read": "Lido",
"unread": "Não lido"
},
"empty": "Desculpe, não tem nenhuma notificação neste momento."
},
"settings": {
"name": "Configurações",
"data": {
"name": "Seus dados",
"labelName": "Seu nome",
"namePlaceholder": "Anonymous",
"labelCity": "Sua cidade ou estado",
"labelBio": "Sobre você"
"labelName": "Seu Nome",
"labelSlug": "Seu nome de usuário exclusivo",
"namePlaceholder": "Femanon Funny",
"labelCity": "Sua cidade ou região",
"labelBio": "Sobre você",
"success": "Seus dados foram atualizados com sucesso!"
},
"email": {
"validation": {
"same-email": "Este é o seu endereço de e-mail atual"
},
"name": "Seu email",
"labelEmail": "Alterar o seu endereço de e-mail",
"labelNewEmail": "Novo endereço de e-mail",
"labelNonce": "Digite o seu código",
"success": "Um novo endereço de e-mail foi registrado.",
"submitted": "Um e-mail para verificar o seu endereço foi enviado para <b>{email}</b>.",
"change-successful": "O seu endereço de e-mail foi alterado com sucesso.",
"verification-error": {
"message": "O seu e-mail não pode ser alterado.",
"explanation": "Isto pode ter diferentes causas:",
"reason": {
"invalid-nonce": "O código de confirmação esta inválido?",
"no-email-request": "Você tem certeza de que solicitou uma alteração no seu endereço de e-mail?"
},
"support": "Se o problema persistir, por favor contacte-nos por e-mail"
}
},
"validation": {
"slug": {
"regex": "Os caracteres permitidos são apenas letras minúsculas, números, sublinhados e hífens.",
"alreadyTaken": "Este nome de usuário já está registrado."
}
},
"security": {
"name": "Segurança"
"name": "Segurança",
"change-password": {
"button": "Alterar senha",
"success": "Senha alterada com sucesso!",
"label-old-password": "Sua senha antiga",
"label-new-password": "Sua nova senha",
"label-new-password-confirm": "Confirme sua nova senha",
"message-old-password-required": "Digite sua senha antiga",
"message-new-password-required": "Digite uma nova senha",
"message-new-password-confirm-required": "Confirme sua nova senha",
"message-new-password-missmatch": "Digite a mesma senha novamente",
"passwordSecurity": "Segurança da senha",
"passwordStrength0": "Senha muito insegura",
"passwordStrength1": "Senha insegura",
"passwordStrength2": "Senha medíocre",
"passwordStrength3": "Senha forte",
"passwordStrength4": "Senha muito forte"
}
},
"invites": {
"name": "Convites"
},
"download": {
"name": "Baixar dados"
"name": "Baixar Dados"
},
"delete": {
"name": "Apagar conta"
"deleteUserAccount": {
"name": "Deletar dados",
"contributionsCount": "Deletar minhas {count} publicações",
"commentedCount": "Deletar meus {count} comentários",
"accountDescription": "Esteja ciente de que o suas Publicações e Comentários são importantes para a nossa comunidade. Se você ainda optar por excluí-los, você tem que marcá-los abaixo.",
"accountWarning": "Você <b>NÃO PODE GERENCIAR</b> e <b>NÃO PODE RECUPERAR</b> sua conta, Publicações, ou Comentários após excluir sua conta!",
"success": "Conta eliminada com sucesso!",
"pleaseConfirm": "<b class='is-danger'>Ação destrutiva!</b> Digitar <b>{confirm}</b> para confirmar"
},
"embeds": {
"name": "Fornecedores de terceiros",
"info-description": "Se você concordar, as publicações da seguinte lista de provedores incluirão automaticamente código de terceiros de outros provedores (terceiros) na forma de vídeos, imagens ou texto incorporados.",
"description": "Você concordou que nas contribuições da seguinte lista de provedores, o código estrangeiro de outros provedores (terceiros) na forma de vídeos, imagens ou texto incorporados são automaticamente incorporados",
"statustext": "No momento, isto é uma incorporação automática:",
"statuschange": "Modificar configuração",
"false": "Desligado",
"true": "Admitido",
"button-tofalse": "desligar",
"button-totrue": "permitir permanentemente",
"third-party-false": "Integra automaticamente <b style='color:red'>no </b> serviços de terceiros.",
"third-party-true": "A inclusão de serviços de terceiros é <b style='color:red'>permanentemente permitida</b> e armazenadas para sessões futuras."
},
"organizations": {
"name": "Minhas Organizações"
},
"languages": {
"name": "Linguagens"
},
"social-media": {
"name": "Mídias sociais",
"placeholder": "Sua url de mídia social",
"requireUnique": "Você já adicionou esta url",
"submit": "Adicionar link",
"successAdd": "Mídias sociais adicionadas. Perfil de usuário atualizado!",
"successDelete": "Mídias sociais removidas. Perfil de usuário atualizado!"
},
"blocked-users": {
"name": "Usuários bloqueados",
"explanation": {
"intro": "Se outro usuário foi bloqueado por você, isto é o que acontece:",
"your-perspective": "As mensagens da pessoa bloqueada não aparecerão mais no seu feed de notícias.",
"their-perspective": "Vice versa: A pessoa bloqueada também não verá mais suas mensagens em seu feed de notícias.",
"search": "Publicações de pessoas bloqueadas desaparecem dos resultados da sua pesquisa.",
"notifications": "Usuários bloqueados não receberão mais notificações se forem mencionados em suas mensagens.",
"closing": "Isso deve ser suficiente por enquanto para que os usuários bloqueados não possam mais incomodá-lo."
},
"columns": {
"name": "Nome",
"slug": "Slug"
},
"empty": "Até agora, você não bloqueou ninguém.",
"how-to": "Você pode bloquear outros usuários em suas páginas de perfil através do menu de conteúdo.",
"block": "Bloquear usuário",
"unblock": "Desbloquear usuário"
}
},
"admin": {
@ -76,20 +326,34 @@
"dashboard": {
"name": "Painel de controle",
"users": "Usuários",
"posts": "Postagens",
"posts": "Publicações",
"comments": "Comentários",
"notifications": "Notificações",
"organizations": "Organizações",
"projects": "Projetos",
"invites": "Convites",
"follows": "Segue",
"shouts": "Aclamações"
"shouts": "Recomendar"
},
"organizations": {
"name": "Organizações"
},
"users": {
"name": "Usuários"
"name": "Usuários",
"form": {
"placeholder": "e-mail, nome ou descrição"
},
"table": {
"columns": {
"number": "N.º",
"name": "Nome",
"email": "E-mail",
"slug": "Slug",
"role": "Função",
"createdAt": "Criado em"
}
},
"empty": "Nenhum usuário encontrado"
},
"pages": {
"name": "Páginas"
@ -100,44 +364,81 @@
"categories": {
"name": "Categorias",
"categoryName": "Nome",
"postCount": "Postagens"
"postCount": "Publicações"
},
"tags": {
"name": "Etiquetas",
"hashtags": {
"name": "Hashtags",
"number": "Não.",
"nameOfHashtag": "Nome",
"tagCountUnique": "Usuários",
"tagCount": "Postagens"
"tagCount": "Publicações"
},
"settings": {
"name": "Configurações"
},
"invites": {
"name": "Convidar usuários",
"title": "Convidar pessoas",
"description": "Convites são uma maneira maravilhosa de ter seus amigos em sua rede …"
}
},
"post": {
"name": "Postar",
"name": "Publicação",
"pinned": "Anúncio",
"moreInfo": {
"name": "Mais informações"
"name": "Mais informações",
"title": "Mais informações",
"description": "Aqui você pode encontrar mais informações sobre este tópico.",
"titleOfCategoriesSection": "Categorias",
"titleOfHashtagsSection": "Hashtags",
"titleOfRelatedContributionsSection": "Publicações relacionadas"
},
"takeAction": {
"name": "Tomar uma ação"
"name": "Tomar providências"
},
"menu": {
"edit": "Editar publicação",
"delete": "Excluir publicação"
},
"comment": {
"submit": "Commentar"
"submit": "Comentário",
"submitted": "Comentário Enviado",
"updated": "Alterações salvas"
},
"edited": "editado"
},
"comment": {
"content": {
"unavailable-placeholder": "… este comentário não está mais disponível"
},
"menu": {
"edit": "Editar Comentário",
"delete": "Apagar Comentário",
"pin": "Fixar publicação",
"pinnedSuccessfully": "Publicação fixada com successo!",
"unpin": "Desafixar publicação",
"unpinnedSuccessfully": "Publicação desafixada com successo!"
},
"show": {
"more": "mostrar mais",
"less": "mostrar menos"
},
"edited": "editado"
},
"quotes": {
"african": {
"quote": "Muitas pessoas pequenas, em muitos lugares pequenos, fazem muitas coisas pequenas, que podem mudar a face do mundo.",
"quote": "Muitas pessoas pequenas em muitos lugares pequenos fazem muitas coisas pequenas, que podem alterar a face do mundo.",
"author": "Provérbio africano"
}
},
"common": {
"post": "Postagem ::: Postagens",
"post": "Publicação::: Publicações",
"comment": "Comentário ::: Comentários",
"letsTalk": "Vamos Conversar",
"versus": "Contra",
"moreInfo": "Mais informações",
"takeAction": "Tomar uma ação",
"shout": "Aclamação ::: Aclamações",
"shout": "Recomendar ::: Recomendações",
"user": "Usuário ::: Usuários",
"category": "Categoria ::: Categorias",
"organization": "Organização ::: Organizações",
@ -146,7 +447,11 @@
"name": "Nome",
"loadMore": "Carregar mais",
"loading": "Carregando",
"reportContent": "Denunciar"
"reportContent": "Denunciar",
"validations": {
"email": "deve ser um endereço de e-mail válido",
"url": "deve ser uma URL válida"
}
},
"actions": {
"loading": "Carregando",
@ -160,12 +465,19 @@
"moderation": {
"name": "Moderação",
"reports": {
"empty": "Parabéns, nada a moderar.",
"empty": "Parabéns, nada para moderar.",
"name": "Denúncias",
"reporter": "Denunciado por"
"reasonCategory": "Categoria",
"reasonDescription": "Descrição",
"createdAt": "Data",
"submitter": "denunciado por",
"disabledBy": "desativado por"
}
},
"disable": {
"submit": "Desativar",
"cancel": "Cancelar",
"success": "Desativado com sucesso!",
"user": {
"title": "Desativar usuário",
"type": "Usuário",
@ -182,52 +494,230 @@
"message": "Você realmente deseja desativar o comentário de \" <b> {name} </b> \"?"
}
},
"delete": {
"submit": "Excluir",
"cancel": "Cancelar",
"contribution": {
"title": "Excluir publicação",
"type": "Contribuição",
"message": "Você realmente deseja excluir a publicação \"<b>{name}</b>\"?",
"success": "Publicação excluída com êxito!"
},
"comment": {
"title": "Excluir Comentário",
"type": "Comentário",
"message": "Você realmente deseja excluir o comentário \"<b>{name}</b>\"?",
"success": "Comentário excluído com sucesso!"
}
},
"report": {
"submit": "Enviar denúncia",
"cancel": "Cancelar",
"success": "Obrigado por reportar!",
"user": {
"title": "Denunciar usuário",
"type": "Usuário",
"message": "Você realmente deseja denunciar o usuário \" <b> {name} </b> \"?"
"message": "Você realmente deseja denunciar o usuário \" <b> {name} </b> \"?",
"error": "Você já denunciou o usuário!"
},
"contribution": {
"title": "Denunciar Contribuição",
"type": "Contribuição",
"message": "Você realmente deseja denunciar a contribuição \" <b> {name} </b> \"?"
"message": "Você realmente deseja denunciar a contribuição \" <b> {name} </b> \"?",
"error": "Você já denunciou a contribuição!"
},
"comment": {
"title": "Denunciar Comentário",
"type": "Comentário",
"message": "Você realmente deseja denunciar o comentário de \"<b>{name}</b>\"?"
"message": "Você realmente deseja denunciar o comentário de \"<b>{name}</b>\"?",
"error": "Você já denunciou o comentário!"
},
"reason": {
"category": {
"label": "Selecione uma categoria:",
"placeholder": "Categoria …",
"options": {
"discrimination_etc": "Mensagens, comentários, afirmações ou insultos discriminatórios.",
"pornographic_content_links": "Publicação ou vinculação de material claramente pornográfico.",
"glorific_trivia_of_cruel_inhuman_acts": "Glorificação ou banalização de atos de violência cruel ou desumana.",
"doxing": "A divulgação de informações pessoais de terceiros sem o seu consentimento ou ameaça de (\"doxing\").",
"intentional_intimidation_stalking_persecution": "Intimidação intencional, assédio ou perseguição.",
"advert_products_services_commercial": "Publicidade de produtos e serviços com intenção comercial.",
"criminal_behavior_violation_german_law": "Comportamento criminoso ou violação da lei alemã.",
"other": "Outros …"
},
"invalid": "Selecione uma categoria válida"
},
"description": {
"label": "Por favor, explique: Por que você gostaria de denunciar isso?",
"placeholder": "Informações adicionais …"
}
},
"contribution": {
"title": "Título",
"edit": "Editar Contribuição",
"delete": "Apagar Contribuição",
"teaserImage": {
"cropperConfirm": "Confirmar"
}
},
"comment": {
"content": {
"unavailable-placeholder": "… este commenttário não está disponível"
},
"menu": {
"edit": "Editar Comentário",
"delete": "Apagar Comentário"
},
"show": {
"more": "mostrar mais",
"less": "mostrar menos"
},
"edited": "editado"
},
"followButton": {
"follow": "Seguir",
"following": "Seguindo"
},
"shoutButton": {
"shouted": "Aclamou"
"shouted": "Recomendou"
},
"release": {
"submit": "Liberar",
"cancel": "Cancelar",
"success": "Liberado com sucesso!",
"user": {
"title": "Liberar usuário",
"type": "Usuário",
"message": "Você realmente quer liberar o usuário \"<b>{name}</b>\"?",
"error": "Você já denunciou o usuário!"
},
"contribution": {
"title": "Liberar contribuição ",
"type": "Contribuição",
"message": "Você realmente quer liberar a contribuição \"<b>{name}</b>\"?",
"error": "Você já denunciou a contribuição!"
},
"comment": {
"title": "Liberar Comentário ",
"type": "Comentário",
"message": "Você realmente quer liberar o comentário de \"<b>{name}</b>\"?",
"error": "Você já denunciou o comentário!"
}
},
"user": {
"avatar": {
"submitted": "Carregado com sucesso!"
}
},
"contribution": {
"title": "Título",
"newPost": "Criar uma nova publicação",
"filterFollow": "Filtrar contribuições de usuários que eu sigo",
"filterALL": "Ver todas as contribuições",
"success": "Salvo!",
"languageSelectLabel": "Idioma",
"categories": {
"infoSelectedNoOfMaxCategories": "{chosen} of {max} categorias selecionadas"
},
"emotions-label": {
"funny": "Engraçado",
"happy": "Feliz",
"surprised": "Surpreso",
"cry": "Chorando",
"angry": "Irritado"
},
"category": {
"name": {
"freedom-of-speech": "Liberdade de expressão",
"consumption-sustainability": "Consumo e Sustentabilidade",
"global-peace-nonviolence": "Paz Mundial e Não-Violência",
"just-for-fun": "Só por diversão",
"happiness-values": "Felicidade e Valores",
"health-wellbeing": "Saúde e Bem-estar",
"environment-nature": "Meio Ambiente e Natureza",
"animal-protection": "Proteção Animal",
"human-rights-justice": "Direitos Humanos e Justiça",
"education-sciences": "Educação e Ciências",
"cooperation-development": "Cooperação e Desenvolvimento",
"democracy-politics": "Democracia e Política",
"economy-finances": "Economia e Finanças",
"energy-technology": "Energia e tecnologia",
"it-internet-data-privacy": "TI, Internet e Privacidade de Dados",
"art-culture-sport": "Arte, Cultura e Esporte"
}
},
"teaserImage": {
"cropperConfirm": "Confirmar"
}
},
"code-of-conduct": {
"subheader": "para a rede social da Human Connection gGmbH",
"preamble": {
"title": "Introdução",
"description": "A Human Connection é uma rede de conhecimento e ação social sem fins lucrativos da próxima geração. Feito por pessoas - para pessoas. Open Source, justo e transparente. Para uma mudança local e global positiva em todas as áreas da vida. Redesenhamos completamente a troca pública de conhecimentos, idéias e projetos. As funções da Human Connection reúnem as pessoas - offline e online - para que possamos fazer do mundo um lugar melhor."
},
"purpose": {
"title": "Propósito",
"description": "Com este código de conduta, regulamentamos os princípios essenciais para o comportamento em nossa rede social. A Carta dos Direitos Humanos das Nações Unidas é a nossa orientação e forma o coração da nossa compreensão dos valores. O código de conduta serve como princípios orientadores para a nossa aparência pessoal e interação uns com os outros. Qualquer pessoa ativa como usuário da Human Connection Network, que escreve artigos, comentários ou se conecta com outros usuários, incluindo aqueles fora da rede, reconhece estas regras de conduta como obrigatórias."
},
"expected-behaviour": {
"title": "Comportamentos esperados",
"description": "Os seguintes comportamentos são esperados e solicitados a todos os membros da comunidade:",
"list": {
"0": "Exercitar ponderação e respeito no seu discurso e ações.",
"1": "Tente a colaboração antes do conflito.",
"2": "Evite comportamentos e discursos humilhantes, discriminatórios ou assediadores.",
"3": "Esteja atento ao que o rodeia e aos outros participantes. Alerte os líderes comunitários se você perceber uma situação perigosa, alguém em perigo ou violações deste Código de Conduta, mesmo que pareçam inconsequentes."
}
},
"unacceptable-behaviour": {
"title": "Comportamentos Inaceitáveis",
"description": "Os seguintes comportamentos são inaceitáveis dentro da nossa comunidade:",
"list": {
"0": "Mensagens, comentários, afirmações ou insultos discriminatórios, particularmente aqueles relacionados a gênero, orientação sexual, raça, religião, orientação política ou filosófica ou deficiência.",
"1": "Publicar ou vincular material claramente pornográfico.",
"2": "Glorificação ou banalização de atos de violência cruel ou desumana.",
"3": "A divulgação de informações pessoais de terceiros sem o seu consentimento ou ameaça de (\"doxing\").",
"4": "Intimidação intencional, assédio ou perseguição.",
"5": "Publicidade de produtos e serviços com intenção comercial.",
"6": "Comportamento criminoso ou violação da lei alemã.",
"7": "Apoiar ou incentivar tal conduta."
}
},
"consequences": {
"title": "Consequências de um comportamento inaceitável",
"description": "Se um membro da comunidade apresentar um comportamento inaceitável, os operadores, moderadores e administradores responsáveis da rede podem tomar medidas adequadas, incluindo, entre outras:",
"list": {
"0": "Pedido de suspensão imediata de uma conduta inaceitável",
"1": "Bloquear ou excluir comentários",
"2": "Exclusão temporária da respectiva publicação ou contribuição",
"3": "Bloquear ou eliminar conteúdo",
"4": "Retirada temporária de permissão de escrita",
"5": "Exclusão temporária da rede",
"6": "Exclusão definitiva da rede",
"7": "Violações da lei alemã podem ser denunciadas",
"8": "Divulgação ou incentivo a estes comportamentos."
}
},
"get-help": "Se você for vítima ou testemunhar um comportamento inaceitável, ou tiver qualquer outra preocupação, por favor notifique um organizador da comunidade o mais rápido possível e inclua o link ou mencione o conteúdo correspondente:"
},
"termsAndConditions": {
"newTermsAndConditions": "Novos Termos e Condições",
"termsAndConditionsConfirmed": "Eu li e confirmei os <a href=\"/terms-and-conditions\" target=\"_blank\">Terms and Conditions</a>.",
"termsAndConditionsNewConfirmText": "Por favor, leia os novos termos de uso agora!",
"termsAndConditionsNewConfirm": "Eu li e concordo com os novos termos de condições.",
"agree": "Eu concordo!",
"terms-of-service": {
"title": "Termos do Serviço",
"description": "As seguintes condições de utilização constituem a base para a utilização da nossa rede. Ao registar-se, deve aceitar os termos de utilização e informaremos mais tarde sobre quaisquer alterações que possam ocorrer. A Human Connection Network é operada na Alemanha e, portanto, está sujeita à lei alemã. O local de jurisdição é Kirchheim / Teck. Para mais detalhes, veja a nossa impressão: <a href=\"https://human-connection.org/imprint\" target=\"_blank\" >https://human-connection.org/imprint</a> "
},
"use-and-license" : {
"title": "Uso e Licença",
"description": "Se qualquer conteúdo que você publicar para nós for protegido por direitos de propriedade intelectual, você nos concede uma licença não exclusiva, transferível, sublicenciável e mundial para usar tal conteúdo para postar em nossa rede. Esta licença expira quando você exclui seu conteúdo ou toda a sua conta. Lembre-se de que outros podem compartilhar seu conteúdo e nós não podemos excluí-lo."
},
"privacy-statement" : {
"title": "Política de Privacidade",
"description": "Nossa rede é uma rede social de conhecimento e ação. Portanto, é particularmente importante para nós que o máximo de conteúdo possível seja acessível ao público. No decurso do desenvolvimento da nossa rede, haverá cada vez mais a possibilidade de decidir sobre a visibilidade dos dados pessoais. Iremos informá-lo sobre estas novas funcionalidades. Caso contrário, você deve sempre pensar sobre quais dados pessoais você divulga sobre si mesmo (ou outros). Isto aplica-se em particular ao conteúdo das mensagens e comentários, uma vez que estes têm um carácter largamente público. Mais tarde, haverá possibilidades de limitar a visibilidade do seu perfil. Parte dos termos de serviço é a nossa declaração de privacidade, que o informa sobre as operações individuais de processamento de dados na nossa rede: <a href=\"https://human-connection.org/datenschutz/#netzwerk\" target=\"_blank\"> https://human-connection.org/datenschutz/#netzwerk</a> bzw. <a href=\"https://human-connection.org/datenschutz/\" target=\"_blank\">https://human-connection.org/datenschutz/</a> Nossa declaração de privacidade é adaptada à situação legal e às características de nossa rede e é sempre válida na versão mais atual."
},
"code-of-conduct" : {
"title": "Código de Conduta",
"description": "Nosso código de conduta serve como um manual de aparência pessoal e interação entre si. Quem quer que seja ativo como utilizador na rede Human Connection, escreva artigos, comentários ou faça contato com outros utilizadores, mesmo fora da rede, reconhece estas regras de conduta como sendo vinculativas. <a href=\"https://alpha.human-connection.org/code-of-conduct\" target=\"_blank\"> https://alpha.human-connection.org/code-of-conduct</a>"
},
"moderation" : {
"title": "Moderação",
"description": "Até que nossas possibilidades financeiras nos permitam implementar o sistema de moderação comunitária, moderamos com um sistema simplificado e com pessoal próprio ou possivelmente voluntário. Nós treinamos esses moderadores e por isso só eles tomam as decisões apropriadas. Estes moderadores realizam o seu trabalho de forma anônima. Você pode denunciar mensagens, comentários e usuários para nós (por exemplo, se eles fornecem informações em seu perfil ou têm imagens que violam estes Termos de Uso). Se você relatar algo para nós, você precisa dar uma razão e pode dar uma breve explicação. Em seguida, analisaremos o que você denunciou e o sancionaremos, se necessário, por exemplo, bloqueando contribuições, comentários ou usuários. Infelizmente, você e a pessoa em questão não receberão qualquer feedback da nossa parte neste momento, mas isto está na fase de planeamento. Independentemente disso, reservamo-nos o direito de impor sanções em princípio por razões que podem ou não estar listadas no nosso Código de Conduta ou nestes termos de serviço."
},
"errors-and-feedback" : {
"title": "Erros e Feedback",
"description": "Fazemos todos os esforços para manter a nossa rede e dados seguros e disponíveis. Cada nova versão do software passa por testes automatizados e manuais. No entanto, podem ocorrer erros imprevistos. Portanto, somos gratos por quaisquer erros reportados. Você é bem-vindo para relatar quaisquer erros que você descobrir enviando um e-mail para o Suporte em support@human-connection.org."
},
"help-and-questions" : {
"title": "Ajuda e Perguntas",
"description": "Para ajuda e perguntas, nós compilamos uma coleção abrangente de perguntas e respostas frequentes (FAQ) para você. Você pode encontrá-las aqui: <a href=\"https://support.human-connection.org/kb/\" target=\"_blank\" > https://support.human-connection.org/kb/ </a>"
},
"addition" : {
"title": "Além disso, realizamos regularmente eventos onde você também pode compartilhar suas impressões e fazer perguntas. Você pode encontrar uma visão geral atual aqui:",
"description": "<a href=\"https://human-connection.org/events/\" target=\"_blank\" > https://human-connection.org/events/ </a>"
}
}
}

717
webapp/locales/ru.json Normal file
View File

@ -0,0 +1,717 @@
{
"actions": {
"cancel": "Отменить",
"create": "Создать",
"delete": "Удалить",
"edit": "Редактировать",
"loading": "погрузочный",
"loadMore": "Загрузить больше",
"save": "Сохранить"
},
"admin": {
"categories": {
"categoryName": "Имя",
"name": "Категории",
"postCount": "Сообщения"
},
"dashboard": {
"comments": "Комментарии",
"follows": "Следит",
"invites": "Приглашения",
"name": "Приборная панель",
"notifications": "Уведомления",
"organizations": "Организаций",
"posts": "сообщения",
"projects": "Проекты",
"shouts": "Оглашения",
"users": "Пользователи"
},
"hashtags": {
"name": "Хэштеги",
"nameOfHashtag": "Имя",
"number": "Но.",
"tagCount": "Сообщений",
"tagCountUnique": "Пользователи"
},
"invites": {
"description": "Приглашения — это замечательный способ завести своих друзей в своей сети ...",
"name": "Пригласить пользователей",
"title": "Пригласить людей"
},
"name": "Администратор",
"notifications": {
"name": "Уведомления"
},
"organizations": {
"name": "Организаций"
},
"pages": {
"name": "Страницы"
},
"settings": {
"name": "Настройки"
},
"tags": {
"name": "Теги",
"tagCount": "Сообщения",
"tagCountUnique": "Пользователи"
},
"users": {
"empty": "Не найдено пользователей",
"form": {
"placeholder": "Электронная почта, имя или описание"
},
"name": "Пользователи",
"table": {
"columns": {
"createdAt": "Создано в",
"email": "Эл. почта",
"name": "Имя",
"number": "Но.",
"role": "Роль",
"slug": "Slug"
}
}
}
},
"code-of-conduct": {
"consequences": {
"description": "Если участник сообщества проявляет неприемлемое поведение, ответственные операторы, модераторы и администраторы сети могут принять соответствующие меры, включая, но не ограничиваясь:",
"list": {
"0": "Просьба о немедленном прекращении неприемлемого поведения",
"1": "запирание или удаление контента",
"2": "Временное исключение из соответствующей должности или вклада",
"3": "блокирование или удаление контента",
"4": "Временное снятие разрешений на запись",
"5": "Временное исключение из сети",
"6": "Окончательное исключение из сети",
"7": "Можно сообщить о нарушениях немецкого законодательства.",
"8": "Адвокатура или поощрение такого поведения."
},
"title": "Последствия неприемлемого поведения"
},
"expected-behaviour": {
"description": "Следующее поведение ожидается и требуется от всех членов сообщества:",
"list": {
"0": "Будь внимательны и уважительны к тому, что ты пишешь и делаешь.",
"1": "Попытайтесь подойти к другим, прежде чем возникнет конфликт.",
"2": "Унижающего достоинство, дискриминационного или преследующего поведения и выражений.",
"3": "Будь внимательны к своей среде. Сообщи о поддержке в опасных ситуациях, когда человек нуждается или нарушает настоящий Кодекс поведения, даже если он кажется незначительным."
},
"title": "Ожидаемое поведение"
},
"get-help": "Если ты стал жертвой или свидетелем неприемлемого поведения или у вас возникли какие-либо другие проблемы, пожалуйста, как можно скорее сообщите об этом организатору сообщества и укажите ссылку на соответствующий контент:",
"preamble": {
"description": "Human Connection-это некоммерческая сеть социальных знаний и действий следующего поколения. Из людей для людей. Открытый исходный код, справедливый и прозрачный. Для позитивных локальных и глобальных изменений во всех сферах жизни. Мы полностью перестраиваем публичный обмен знаниями, идеями и проектами. Функции Human Connection объединяют людей в автономном режиме и в интернете так что мы можем сделать мир лучше.",
"title": "Преамбула"
},
"purpose": {
"description": "С помощью этих правил поведения мы регулируем основные принципы поведения в нашей социальной сети. При этом Устав ООН по правам человека является нашей ориентацией и лежит в основе нашего понимания ценностей. Правила поведения служат руководящими принципами для личного выступления и общения друг с другом. Любой, кто является активным пользователем в сети Human Connection, публикует сообщения, комментирует или контактирует с другими пользователями, в том числе за пределами сети, признает эти правила поведения обязательными.",
"title": "Цель"
},
"subheader": "для социальной сети \"Human Connection gGmbH\"",
"unacceptable-behaviour": {
"description": "В нашем сообществе неприемлемы следующие типы поведения:",
"list": {
"0": "Дискриминационные сообщения, комментарии, высказывания или оскорбления, в частности, касающиеся пола, сексуальной ориентации, расы, религии, политической или мировоззренческой ориентации, или инвалидности.",
"1": "Публикация или ссылка явно порнографический материал.",
"2": "Прославление или умаление жестоких, или бесчеловечных актов насилия.",
"3": "Публикация персональных данных других лиц без их согласия или угрозы (\"Доксинг\").",
"4": "Преднамеренное запугивание, сталкинг или преследование.",
"5": "Рекламировать продукты и услуги с коммерческим намерением.",
"6": "Уголовного поведение или нарушении немецкое право.",
"7": "Одобрение или поощрение этого поведения."
},
"title": "Недопустимое поведение"
}
},
"comment": {
"content": {
"unavailable-placeholder": "...этот комментарий больше не доступен"
},
"delete": "Удалить комментарий",
"edit": "редакти́ровать Комментарий",
"edited": "Отредактированы",
"menu": {
"delete": "Удалить комментарий",
"edit": "Редактировать комментарий"
},
"show": {
"less": "показать меньше",
"more": "показать больше"
}
},
"common": {
"category": "Категория ::: Категории",
"comment": "Комментарий ::: Комментарии",
"letsTalk": "Давай поговорим",
"loading": "идёт загрузка",
"loadMore": "Загрузить больше",
"moreInfo": "Больше информации",
"name": "Имя",
"organization": "Организация ::: Организации",
"post": "Сообщение ::: Сообщения",
"project": "Проект ::: Проекты",
"reportContent": "Отчет",
"shout": "Оглашения ::: Оглашении",
"tag": "Тег ::: Теги",
"takeAction": "принять меры",
"user": "Пользователь ::: Пользователи",
"validations": {
"email": "должен быть действительный адрес электронной почты",
"url": "должен быть действительным URL"
},
"versus": "Против"
},
"components": {
"enter-nonce": {
"form": {
"description": "Откройте папку \"Входящие\" и введите код, который мы тебя отправили.",
"next": "Продолжить",
"nonce": "Введите свой код",
"validations": {
"length": "должна состоять из 6 символов."
}
}
},
"password-reset": {
"change-password": {
"error": "Смена пароля не удалась. Может быть, код безопасности был неправильным?",
"help": "В случае возникновения проблем, не стесняйся обращаться за помощью, отправив нам письмо по адресу:",
"success": "Смена пароля прошла успешно!"
},
"request": {
"form": {
"description": "На указанный адрес электронной почты будет отправлено сообщение для сброса пароля.",
"submit": "Запросить электронную почту",
"submitted": "На адрес <b>{email}<\/b>было отправлено электронное письмо с дальнейшими инструкциями"
},
"title": "Сбросить пароль"
}
},
"registration": {
"create-user-account": {
"error": "Невозможно создать учетную запись пользователя!",
"help": "Может быть, подтверждение было недействительным? В случае возникновения проблем, не стесняйтесь обращаться за помощью, отправив нам письмо по электронной почте:",
"success": "Твоя учетная запись создана!",
"title": "Создать учетную запись пользователя"
},
"signup": {
"form": {
"data-privacy": "Я прочитал и понял <a href=\"https:\/\/human-connection.org\/datenschutz\/\" target=\"_blank\"><ds-text bold color=\"primary\" >Заявление о конфиденциальности<\/ds-text><\/a>",
"description": "Чтобы начать работу, введи свой адрес электронной почты:",
"errors": {
"email-exists": "Уже есть учетная запись пользователя с этим адресом электронной почты!",
"invalid-invitation-token": "Похоже, что приглашение уже использовалось. Ссылки на приглашения можно использовать только один раз."
},
"invitation-code": "Твой код приглашения: <b>{code}<\/b>",
"minimum-age": "Мне 18 лет или старше.",
"submit": "Создать учетную запись",
"success": "Письмо со ссылкой для завершения регистрации было отправлено на <b> {email} <\/b>",
"terms-and-condition": "Подтверждаю, на <a href=\"\/terms-and-conditions\"><ds-text bold color=\"primary\" >Условия и положения<\/ds-text><\/a>.ю"
},
"title": "Присоединяйся к Human Connection!",
"unavailable": "К сожалению, публичная регистрация учетных записей пользователей на этом сервере сейчас недоступна."
}
}
},
"contribution": {
"categories": {
"infoSelectedNoOfMaxCategories": "{chosen} из {max} выбранных категорий"
},
"category": {
"name": {
"animal-protection": "Защита животных",
"art-culture-sport": "Искусство, культура и спорт",
"consumption-sustainability": "Потребление И Устойчивость",
"cooperation-development": "Сотрудничество и развитие",
"democracy-politics": "Демократия и политика",
"economy-finances": "Экономика и финансы",
"education-sciences": "Образование и наука",
"energy-technology": "Энергия и технологии",
"environment-nature": "Окружающая среда и природа",
"freedom-of-speech": "Свобода слова",
"global-peace-nonviolence": "Глобальный мир и ненасилие",
"happiness-values": "Счастье и Ценности",
"health-wellbeing": "Здоровье и благополучие",
"human-rights-justice": "Права Человека и Справедливость",
"it-internet-data-privacy": "ИТ, интернет и конфиденциальность",
"just-for-fun": "Просто для удовольствия"
}
},
"delete": "Удалить вклад",
"edit": "редакти́ровать вклад",
"emotions-label": {
"angry": "Сердитый",
"cry": "Плакать",
"funny": "Смешно́й",
"happy": "Счастливый",
"surprised": "Удивленный"
},
"filterALL": "Просмотреть все вклады",
"filterFollow": "Фильтровать сообщения пользователей, на которых я слежу",
"languageSelectLabel": "Язык",
"newPost": "Создать новое сообщение",
"success": "Сохранено!",
"teaserImage": {
"cropperConfirm": "Подтвердить"
},
"title": "Заглавие"
},
"delete": {
"cancel": "Отменить",
"comment": {
"message": "Ты уверены, что хочешь удалить комментарий \"<b>{name}<\/b>\"?",
"success": "Комментарий успешно удален!",
"title": "Удалить комментарий",
"type": "Комментарий"
},
"contribution": {
"message": "Ты уверены, что хочешь удалить сообщение \"<b>{name}<\/b>\"?",
"success": "Сообщение успешно удалено!",
"title": "Удаленный вклад",
"type": "Вклад"
},
"submit": "Удалить"
},
"disable": {
"cancel": "Отменить",
"comment": {
"message": "ты действительно хочешь отключить комментарий от «<b>{name}<\/b>»?",
"title": "Отключить комментарий",
"type": "Комментарий"
},
"contribution": {
"message": "Вы действительно хотите отключить вклад «<b>{name}<\/b>»?",
"title": "Отключить вклад",
"type": "Вклад"
},
"submit": "Отключить",
"success": "Успешно отключен",
"user": {
"message": "ты действительно хочешь отключить пользователя «<b>{name}<\/b>»?",
"title": "Отключить пользователя",
"type": "Пользователь"
}
},
"editor": {
"embed": {
"always_allow": "Всегда отображать содержимое сторонних производителей (эту настройку можно изменить в любое время).",
"data_privacy_info": "Твои данные еще не были переданы третьим лицам. Если ты воспроизводишь это видео сейчас, следующий провайдер, вероятно, зарегистрирует твои данные пользователя:",
"data_privacy_warning": "Внимание Конфиденциальность данных!",
"play_now": "Смотреть сейчас"
},
"hashtag": {
"addHashtag": "Новый хэштег",
"addLetter": "Введите букву",
"noHashtagsFound": "Хэштеги не найдены"
},
"mention": {
"noUsersFound": "Пользователи не найдены"
},
"placeholder": "Оставь свои вдохновляющие мысли ..."
},
"filter-menu": {
"clearSearch": "Опорожнить поиск",
"hashtag-search": "Поиск по #{hashtag}",
"title": "Твой фильтр-пузырь"
},
"filter-posts": {
"categories": {
"all": "Все",
"header": "Категории контента"
},
"followers": {
"label": "Пользователи, за которыми я слежу"
},
"general": {
"header": "Фильтровать по …"
}
},
"followButton": {
"follow": "Следовать",
"following": "Следующий"
},
"index": {
"change-filter-settings": "Измени настройки фильтра, чтобы получить больше результатов.",
"no-results": "Вклады не найдены."
},
"login": {
"copy": "Если у тебя уже есть учетная запись Human Connection, войдите здесь.",
"email": "Твой адрес электронной почты",
"failure": "Неверный адрес электронной почты или пароль.",
"forgotPassword": "Забыл пароль?",
"hello": "Привет",
"login": "Вход",
"logout": "Выйти",
"moreInfo": "Что такое Human Connection",
"moreInfoHint": "на страницу презентации",
"moreInfoURL": "https:\/\/human-connection.org\/en\/",
"no-account": "У вас нет аккаунта?",
"password": "Твой пароль",
"register": "Зарегистрироваться",
"success": "Ты вошёл в систему!"
},
"maintenance": {
"explanation": "В данный момент мы проводим плановое техническое обслуживание, пожалуйста, повтори попытку позже.",
"questions": "Любые вопросы или проблемы, отправь по электронной почте по адресу",
"title": "Human Connection находится в технического обслуживания"
},
"moderation": {
"name": "Модерация",
"reports": {
"createdAt": "Дата",
"disabledBy": "отключены",
"empty": "Поздравляю, модерировать нечего.",
"name": "Отчеты",
"reasonCategory": "Категория",
"reasonDescription": "Описание",
"reporter": "сообщила",
"submitter": "сообщила"
}
},
"notifications": {
"comment": "Комментарий",
"reason": {
"commented_on_post": "Прокомментировал твой вклад...",
"mentioned_in_comment": "Упоминал тебе в комментарии....",
"mentioned_in_post": "Упоминал тебе в сообщении...."
}
},
"post": {
"comment": {
"submit": "Комментируй",
"submitted": "Комментарий отправлен",
"updated": "Сохраненные изменения"
},
"edited": "Отредактированы",
"menu": {
"delete": "Удалить вклад",
"edit": "Редактировать вклад",
"pin": "Закрепить Сообщение",
"pinnedSuccessfully": "Сообщение успешно закреплен!",
"unpin": "Не прикрепи́ть Сообщение больше",
"unpinnedSuccessfully": "Сообщение успешно не закреплено!"
},
"moreInfo": {
"description": "Здесь ты найдешь больше информации по теме.",
"name": "Больше информации",
"title": "Больше информация",
"titleOfCategoriesSection": "Категории",
"titleOfHashtagsSection": "Хэштеги",
"titleOfRelatedContributionsSection": "Похожие вклады"
},
"name": "Пост",
"pinned": "Объявление",
"takeAction": {
"name": "Действовать"
}
},
"profile": {
"commented": "Прокомментированный",
"follow": "Следовать",
"followers": "Последователей",
"following": "Следующий",
"invites": {
"description": "Введи адрес электронной почты для приглашения.",
"emailPlaceholder": "Электронная почта для приглашения",
"title": "Пригласи кого-нибудь в Human Connection!"
},
"memberSince": "член с тех пор",
"name": "Мой профайл",
"network": {
"andMore": "и {number} больше…",
"followedBy": "за ним следуют:",
"followedByNobody": "никому не следует.",
"following": "Следует:",
"followingNobody": "не следует ни за кем.",
"title": "Сеть"
},
"shouted": "оглашали",
"socialMedia": "Где еще я могу найти",
"userAnonym": "Анонимный"
},
"quotes": {
"african": {
"author": "Африканская пословица",
"quote": "Многие маленькие люди во многих маленьких местах делают много маленьких вещей, которые могут изменить лицо мира."
}
},
"release": {
"cancel": "Отменить",
"comment": {
"error": "Ты уже сообщил о комментариях!",
"message": "Ты уверены, что хочешь поделиться комментарием \"<b>{name}<\/b>\"?",
"title": "Выпускать Комментарий",
"type": "Комментарий"
},
"contribution": {
"error": "Ты уже сообщил о вкладе!",
"message": "Ты уверены, что хочешь поделиться постом \"<b>{name}<\/b>\"?",
"title": "Опубликовать вклад",
"type": "Вклад"
},
"submit": "Выпускать",
"success": "Выпущен успешно!",
"user": {
"error": "Ты уже сообщил о пользователе!",
"message": "Ты уверены, что хочешь поделиться пользователем \"<b>{name}<\/b>\"?",
"title": "Выпускать пользователя",
"type": "Пользователь"
}
},
"report": {
"cancel": "Отменить",
"comment": {
"error": "Ты уже сообщил о комментарии!",
"message": "Ты действительно хочешь сообщить комментарий от « <b> {name} <\/b> »?",
"title": "Пожаловаться на комментарий",
"type": "Комментарий"
},
"contribution": {
"error": "Ты уже сообщил о посте!",
"message": "Ты действительно хочешь сообщить о вкладе «<b>{name}<\/b>»?",
"title": "Отчет Вклад",
"type": "Вклад"
},
"reason": {
"category": {
"invalid": "Пожалуйста, выберите действительную категорию",
"label": "Выбери категорию:",
"options": {
"advert_products_services_commercial": "Рекламировать продукты и услуги с коммерческим намерением.",
"criminal_behavior_violation_german_law": "Уголовного поведение или нарушении немецкое право.",
"discrimination_etc": "Дискриминационные вклады, комментарии, заявления или оскорбления.",
"doxing": "Публикация персональных данных других лиц без их согласия или угрозы (\"Доксинг\").",
"glorific_trivia_of_cruel_inhuman_acts": "Прославление или умаление жестоких, или бесчеловечных актов насилия.",
"intentional_intimidation_stalking_persecution": "Преднамеренное запугивание, сталкинг или преследование.",
"other": "Другие...",
"pornographic_content_links": "Публикация или ссылка явно порнографический материал."
},
"placeholder": "Категория ...."
},
"description": {
"label": "Пожалуйста, объясни: Зачем ты хочешь сообщить об этом?",
"placeholder": "Дополнительная информация ..."
}
},
"submit": "Отправить жалобу",
"success": "Спасибо за сообщение!",
"user": {
"error": "Ты уже сообщил о пользователе!",
"message": "ты действительно хочешь сообщить пользователя «<b>{name}<\/b>»?",
"title": "Пожаловаться на пользователя",
"type": "Пользователь"
}
},
"search": {
"failed": "Ничего не найдено",
"hint": "Что ты ищешь?",
"placeholder": "Поиск"
},
"settings": {
"blocked-users": {
"block": "Блокировать пользователя",
"columns": {
"name": "Имя",
"slug": "Псевдоним"
},
"empty": "До сих пор ты никого не блокировал.",
"explanation": {
"closing": "На данный момент этого должно быть достаточно, чтобы заблокированные пользователи больше не беспокоили тебя.",
"intro": "Если ты заблокировал другого пользователя, произойдет следующее:",
"notifications": "Люди, которых ты блокируешь, больше не будут получать уведомления, когда они упоминаются в твоих сообщениях.",
"search": "Сообщения от заблокированных пользователей исчезают из результатов поиска.",
"their-perspective": "И наоборот, то же самое: заблокированный человек больше не видит твоих сообщения в своем обзоре.",
"your-perspective": "В твоем обзоре сообщений больше не отображаются сообщения заблокированного человека."
},
"how-to": "Ты можешь заблокировать других пользователей на странице их профиля с помощью меню содержимого.",
"name": "Заблокированные пользователи",
"unblock": "Разблокировать пользователей"
},
"data": {
"labelBio": "О тебя",
"labelCity": "Твой город или регион",
"labelName": "Твое имя",
"labelSlug": "Твой уникальное имя пользователя",
"name": "твой данные",
"namePlaceholder": "Маша Медведкина",
"success": "Твои данные были успешно обновлены!"
},
"delete": {
"name": "Удалить аккаунт"
},
"deleteUserAccount": {
"accountDescription": "Помни, что твои сообщение и комментарии важны для нашего сообщества. Если ты все равно хочешь удалить их, ты должны помечать их ниже.",
"accountWarning": "Ты можешь удалить свой аккаунт, сообщения или комментарии после их удаления <b>НИ УПРАВЛЯТЬ<\/b>, <b>НИ ВОССТАНАВЛИВАТЬ!<\/b>",
"commentedCount": "Удалить мои {count} комментарии",
"contributionsCount": "Удалить мои {count} сообщения",
"name": "Удалить данные",
"pleaseConfirm": "<b class='is-danger'>Разрушительное действие!<\/b> Введите <b>{confirm}<\/b> для подтверждения.",
"success": "Аккаунт успешно удален!"
},
"download": {
"name": "Скачать данные"
},
"email": {
"change-successful": "Твой адрес электронной почты был успешно изменен.",
"labelEmail": "Изменить адрес электронной почты",
"labelNewEmail": "Новый адрес электронной почты",
"labelNonce": "Введите свой код",
"name": "Твой адрес электронной почты",
"submitted": "Электронное письмо с подтверждением твоего адреса отправлено на <b>{email}<\/b>.",
"success": "Новый адрес электронной почты был зарегистрирован.",
"validation": {
"same-email": "Это твой текущий адрес электронной почты."
},
"verification-error": {
"explanation": "Это может иметь разные причины:",
"message": "Твой адрес электронной почты не может быть подтвержден.",
"reason": {
"invalid-nonce": "Код подтверждения неверен?",
"no-email-request": "Ты уверены, что запросил изменение своего адреса электронной почты?"
},
"support": "Если проблема сохраняется, пожалуйста, свяжешься с нами по электронной почте"
}
},
"embeds": {
"info-description": "Вот список сторонних провайдеров, чьё содержимое может отображаться в виде иностранного кода, например, в виде встроенных видео:",
"name": "Сторонние поставщики",
"status": {
"change": {
"allow": "Конечно.",
"deny": "Лучше не",
"question": "Ты хочешь, чтобы встроенный сторонний код всегда отображался для тебя?"
},
"description": "По умолчанию настройки для тебя будет встроенный сторонний код",
"disabled": {
"off": "сначала не отображается",
"on": "отображается сразу"
}
}
},
"invites": {
"name": "Приглашения"
},
"languages": {
"name": "Языки"
},
"name": "Настройки",
"organizations": {
"name": "Мои организации"
},
"security": {
"change-password": {
"button": "Изменить пароль",
"label-new-password": "Твой новый пароль",
"label-new-password-confirm": "Подтверди свой новый пароль",
"label-old-password": "Твой старый пароль",
"message-new-password-confirm-required": "Подтверди свой новый пароль",
"message-new-password-missmatch": "Введите тот же пароль еще раз",
"message-new-password-required": "Введи новый пароль",
"message-old-password-required": "Введи свой старый пароль",
"passwordSecurity": "Безопасность пароля",
"passwordStrength0": "Очень небезопасный пароль",
"passwordStrength1": "Небезопасный пароль",
"passwordStrength2": "Посредственный пароль",
"passwordStrength3": "Надежный пароль",
"passwordStrength4": "Очень надежный пароль",
"success": "Пароль успешно изменен!"
},
"name": "Безопасность"
},
"social-media": {
"name": "Социальные Медиа",
"placeholder": "Твой URL социальной сети",
"requireUnique": "Эта ссылка уже существует",
"submit": "Добавить ссылку",
"successAdd": "Добавлены Социальные Медиа. Профиль обновлен!",
"successDelete": "Социальные медиа удалены. Профиль обновлен!"
},
"validation": {
"slug": {
"alreadyTaken": "Это имя пользователя уже занято.",
"regex": "Допускаются только строчные буквы, цифры, подчеркивания или дефисы."
}
}
},
"shoutButton": {
"shouted": "оглашали"
},
"site": {
"back-to-login": "Вернуться на страницу входа",
"bank": "банковский счет",
"changelog": "Изменения",
"code-of-conduct": "Кодекс поведения",
"contact": "Контакт",
"data-privacy": "Конфиденциальность данных",
"director": "Управляющий директор",
"error-occurred": "Произошла ошибка.",
"faq": "ЧАСТО ЗАДАВАЕМЫЕ ВОПРОСЫ (FAQ)",
"germany": "Германия",
"imprint": "Импрессум",
"made": "Сделано с #10084;",
"register": "Номер регистрации",
"responsible": "ответственный за содержание этой страницы (§ 55 Abs. 2 RStV)",
"taxident": "UST-ID. в соответствии с §27a Закона о налоге с продаж Германии:",
"termsAndConditions": "Условия и положения",
"thanks": "Спасибо!",
"tribunal": "Суд регистрации"
},
"store": {
"posts": {
"orderBy": {
"newest": {
"label": "Новейший"
},
"oldest": {
"label": "Старейший"
}
}
}
},
"termsAndConditions": {
"addition": {
"description": "<a href=\"https:\/\/human-connection.org\/events\/\" target=\"_blank\" > https:\/\/human-connection.org\/events\/ <\/a>",
"title": "Кроме того, мы регулярно проводим мероприятия, где ты также можешь\nподелиться своими впечатлениями и задать вопросы. Здесь ты можешь найти текущий обзор :"
},
"agree": "Я согласен!",
"code-of-conduct": {
"description": "Наш кодекс поведения служит руководством для личного появления и взаимодействия друг с другом. Тот, кто является активным пользователем в Сети Human Connection, пишет статьи, комментирует или вступает в контакт с другими пользователями, даже за пределами сети, признает эти правила поведения обязательными. <a href=\"https:\/\/alpha.human-connection.org\/code-of-conduct\" target=\"_blank\"> https:\/\/alpha.human-connection.org\/code-of-conduct<\/a>",
"title": "Кодекс поведения"
},
"errors-and-feedback": {
"description": "Мы прилагаем все усилия для обеспечения безопасности и доступности нашей сети и данных. Каждый новый выпуск программного обеспечения проходит как автоматическое, так и ручное тестирование. Однако могут возникнуть непредвиденные ошибки. Поэтому мы благодарны за любые обнаруженные ошибки. ты можешь сообщить о любых обнаруженных ошибках, отправив электронное письмо в службу поддержки по адресу support@human-connection.org",
"title": "Ошибки и обратная связь"
},
"help-and-questions": {
"description": "Для справки и вопросов мы собрали для вас исчерпывающую подборку часто задаваемых вопросов и ответов (FAQ). Ты можешь\nнайти их здесь:<a href=\"https:\/\/support.human-connection.org\/kb\/\" target=\"_blank\" > https:\/\/support.human-connection.org\/kb\/ <\/a>",
"title": "Помощь и вопросы"
},
"moderation": {
"description": "Пока наши финансовые возможности позволяют нам реализовать это сообщество-система Модерации, модерировать мы с упрощенной системой и собственными или, при необходимости, добровольных сотрудниках. Мы обучаем этих модераторов, и по этой причине они тоже принимают соответствующие решения. Эти модераторы выполняют свою деятельность анонимно. ты можешь сообщать нам о сообщениях, комментариях и пользователях (например, если они предоставляют информацию в своем профиле или имеют изображения, которые нарушают настоящие Условия использования). Если ты сообщаешь нам что-то, ты можешь указать причину сообщения и дать еще одно краткое объяснение. Давайте посмотрим на то Сообщается и санкционировать в случае необходимости, например, путем блокировки сообщения, комментарии или пользователей. К сожалению, ты, а также пострадавший в настоящее время не получаешь от нас обратной связи, но это в планировании. Несмотря на это, мы оставляем за собой право на санкции по причинам, которые не могут или не могут быть указаны в нашем кодексе поведения или настоящих Условиях использования.",
"title": "ведение"
},
"newTermsAndConditions": "Новые условия и положения",
"privacy-statement": {
"description": "Наша сеть — это социальная сеть знаний и действий. Поэтому для нас особенно важно, чтобы как можно больше контента было общедоступным. В процессе развития нашей сети будет намного больше возможностей, чтобы решить вопрос о видимости сами указанные личные данные. Об этих новых функциях мы сообщим. В противном случае ты должны всегда думать о том, какие личные данные ты раскрываешь о себе (или других). Это особенно актуально для содержания сообщений и комментариев, поскольку они имеют в основном общедоступный характер. В профиле позже появятся способы ограничения самой видимости. Часть условий использования - это наша политика конфиденциальности, которая информирует тебя о каждой обработке данных в нашей сети: \n<a href=\"https:\/\/human-connection.org\/datenschutz\/#netzwerk\" target=\"_blank\">https:\/\/human-connection.org\/datenschutz\/#netzwerk<\/a>\n или. \n<a href=\"https:\/\/human-connection.org\/datenschutz\/\" target=\"_blank\">https:\/\/human-connection.org\/datenschutz<\/a>\nНаша политика конфиденциальности корректируется в соответствии с законодательством и характеристиками нашей сети и действует в текущей версии.",
"title": "Заявление о конфиденциальности"
},
"terms-of-service": {
"description": "Следующие условия использования являются основой для использования нашей сети. При Регистрации ты должны признать их и мы сообщим Тебе позже через происходящий при необходимости Изменений. Сеть Human Connection работает в Германии и поэтому регулируется немецким законодательством. Суд Kirchheim \/ Teck Stand. Подробности смотри в наших выходных данных: <a href=\"https:\/\/human-connection.org\/impressum\" target=\"_blank\">https:\/\/human-connection.org\/impressum<\/a>",
"title": "Условия обслуживания"
},
"termsAndConditionsConfirmed": "Я прочитал и подтвердил <a href=\"\/terms-and-conditions\" target=\"_blank\">Условия и положения<\/a>.",
"termsAndConditionsNewConfirm": "Я прочитал и согласен с новыми условиями.",
"termsAndConditionsNewConfirmText": "Пожалуйста, ознакомляешься с новыми условиями использования прямо сейчас!",
"use-and-license": {
"description": "Если контент, который ты нанимаешь у нас, защищен правами на интеллектуальную собственность, ты предоставляешь нам неисключительную, передаваемую, сублицензируемую и всемирную лицензию на использование этого контента для развертывания в нашей сети. Эта лицензия заканчивается, как только вт удаляешь свой контент или всю учетную запись. Имей в виду, что другие могут продолжать делиться вашим контентом, и мы не можем его удалить.",
"title": "Использование и лицензия"
}
},
"user": {
"avatar": {
"submitted": "Загрузка успешная"
}
}
}

View File

@ -65,7 +65,7 @@
"cookie-universal-nuxt": "~2.0.18",
"cropperjs": "^1.5.5",
"cross-env": "~6.0.3",
"date-fns": "2.6.0",
"date-fns": "2.7.0",
"express": "~4.17.1",
"graphql": "~14.5.8",
"jsonwebtoken": "~8.5.1",
@ -95,14 +95,15 @@
"@babel/core": "~7.7.2",
"@babel/plugin-syntax-dynamic-import": "^7.2.0",
"@babel/preset-env": "~7.7.1",
"@storybook/addon-a11y": "^5.2.5",
"@storybook/addon-actions": "^5.2.5",
"@storybook/vue": "~5.2.5",
"@storybook/addon-a11y": "^5.2.6",
"@storybook/addon-actions": "^5.2.6",
"@storybook/addon-notes": "^5.2.5",
"@storybook/vue": "~5.2.6",
"@vue/cli-shared-utils": "~4.0.5",
"@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.2.1",
"async-validator": "^3.2.2",
"babel-core": "~7.0.0-bridge.0",
"babel-eslint": "~10.0.3",
"babel-jest": "~24.9.0",
@ -120,7 +121,7 @@
"eslint-plugin-prettier": "~3.1.1",
"eslint-plugin-promise": "~4.2.1",
"eslint-plugin-standard": "~4.0.1",
"eslint-plugin-vue": "~5.2.3",
"eslint-plugin-vue": "~6.0.0",
"faker": "^4.1.0",
"flush-promises": "^1.0.2",
"fuse.js": "^3.4.5",
@ -131,11 +132,12 @@
"prettier": "~1.18.2",
"sass-loader": "~8.0.0",
"storybook-design-token": "^0.4.1",
"storybook-vue-router": "^1.0.7",
"style-loader": "~0.23.1",
"style-resources-loader": "~1.2.1",
"style-resources-loader": "~1.3.2",
"vue-jest": "~3.0.5",
"vue-loader": "~15.7.2",
"vue-svg-loader": "~0.14.0",
"vue-svg-loader": "~0.15.0",
"vue-template-compiler": "^2.6.10"
}
}

View File

@ -5,7 +5,7 @@
</template>
<script>
import HcEmpty from '~/components/Empty.vue'
import HcEmpty from '~/components/Empty/Empty'
export default {
components: {

View File

@ -5,7 +5,7 @@
</template>
<script>
import HcEmpty from '~/components/Empty.vue'
import HcEmpty from '~/components/Empty/Empty'
export default {
components: {

View File

@ -5,7 +5,7 @@
</template>
<script>
import HcEmpty from '~/components/Empty.vue'
import HcEmpty from '~/components/Empty/Empty'
export default {
components: {

View File

@ -5,7 +5,7 @@
</template>
<script>
import HcEmpty from '~/components/Empty.vue'
import HcEmpty from '~/components/Empty/Empty'
export default {
components: {

View File

@ -60,7 +60,7 @@
<script>
import DonationInfo from '~/components/DonationInfo/DonationInfo.vue'
import FilterMenu from '~/components/FilterMenu/FilterMenu.vue'
import HcEmpty from '~/components/Empty'
import HcEmpty from '~/components/Empty/Empty'
import HcPostCard from '~/components/PostCard/PostCard.vue'
import HcLoadMore from '~/components/LoadMore.vue'
import MasonryGrid from '~/components/MasonryGrid/MasonryGrid.vue'

View File

@ -7,12 +7,18 @@
<script>
import LoginForm from '~/components/LoginForm/LoginForm.vue'
import { VERSION } from '~/constants/terms-and-conditions-version.js'
import { mapGetters } from 'vuex'
export default {
layout: 'no-header',
components: {
LoginForm,
},
computed: {
...mapGetters({
user: 'auth/user',
}),
},
asyncData({ store, redirect }) {
if (store.getters['auth/user'].termsAndConditionsAgreedVersion === VERSION) {
redirect('/')
@ -20,6 +26,7 @@ export default {
},
methods: {
handleSuccess() {
this.$i18n.set(this.user.locale || 'en')
this.$router.replace(this.$route.query.path || '/')
},
},

View File

@ -130,7 +130,7 @@
</template>
<script>
import HcEmpty from '~/components/Empty.vue'
import HcEmpty from '~/components/Empty/Empty'
import HcRelativeDateTime from '~/components/RelativeDateTime'
import { reportListQuery } from '~/graphql/Moderation.js'

View File

@ -0,0 +1,150 @@
import { config, shallowMount, mount, createLocalVue } from '@vue/test-utils'
import NotificationsPage from './index.vue'
import Styleguide from '@human-connection/styleguide'
import VTooltip from 'v-tooltip'
import DropdownFilter from '~/components/DropdownFilter/DropdownFilter'
import NotificationsTable from '~/components/NotificationsTable/NotificationsTable'
import Paginate from '~/components/Paginate/Paginate'
const localVue = createLocalVue()
localVue.use(Styleguide)
localVue.use(VTooltip)
config.stubs['client-only'] = '<span><slot /></span>'
describe('PostIndex', () => {
let wrapper, Wrapper, mocks, propsData
beforeEach(() => {
propsData = {}
mocks = {
$t: string => string,
$toast: {
error: jest.fn(string => string),
},
$i18n: {
locale: () => 'en',
},
$apollo: {
mutate: jest.fn().mockResolvedValueOnce({
data: { markAsRead: { id: 'notificationSourceId', read: true } },
}),
queries: {
notifications: {
refresh: jest.fn().mockResolvedValueOnce(),
},
},
},
}
})
describe('shallowMount', () => {
beforeEach(() => {
Wrapper = () => {
return shallowMount(NotificationsPage, {
mocks,
localVue,
propsData,
})
}
wrapper = Wrapper()
})
it('renders a Notications header', () => {
expect(wrapper.find('ds-heading-stub').exists()).toBe(true)
})
it('renders a `dropdown-filter` component', () => {
expect(wrapper.find('dropdown-filter-stub').exists()).toBe(true)
})
it('renders a `notifications-table` component', () => {
expect(wrapper.find('notifications-table-stub').exists()).toBe(true)
})
})
describe('mount', () => {
beforeEach(() => {
Wrapper = () => {
return mount(NotificationsPage, {
mocks,
localVue,
propsData,
})
}
})
describe('filterNotifications', () => {
beforeEach(() => {
propsData.filterOptions = [
{ label: 'All', value: null },
{ label: 'Read', value: true },
{ label: 'Unread', value: false },
]
wrapper = Wrapper()
wrapper.find(DropdownFilter).vm.$emit('filterNotifications', propsData.filterOptions[1])
})
it('sets `notificationRead` to value of received option', () => {
expect(wrapper.vm.notificationRead).toEqual(propsData.filterOptions[1].value)
})
it('set label to the label of the received option', () => {
expect(wrapper.vm.selected).toEqual(propsData.filterOptions[1].label)
})
it('refreshes the notificaitons', () => {
expect(mocks.$apollo.queries.notifications.refresh).toHaveBeenCalledTimes(1)
})
})
describe('markNotificationAsRead', () => {
beforeEach(() => {
wrapper = Wrapper()
wrapper.find(NotificationsTable).vm.$emit('markNotificationAsRead', 'notificationSourceId')
})
it('calls markNotificationAsRead mutation', () => {
expect(mocks.$apollo.mutate).toHaveBeenCalledWith(
expect.objectContaining({ variables: { id: 'notificationSourceId' } }),
)
})
describe('error handling', () => {
beforeEach(() => {
mocks.$apollo.mutate = jest.fn().mockRejectedValueOnce({ message: 'Some error message' })
wrapper = Wrapper()
wrapper
.find(NotificationsTable)
.vm.$emit('markNotificationAsRead', 'notificationSourceId')
})
it('shows an error message if there is an error', () => {
expect(mocks.$toast.error).toHaveBeenCalledWith('Some error message')
})
})
})
describe('Paginate', () => {
beforeEach(() => {
wrapper = Wrapper()
})
describe('next: given a user is on the first page', () => {
it('adds offset to pageSize to skip first x notifications and display next page', () => {
wrapper.find(Paginate).vm.$emit('next')
expect(wrapper.vm.offset).toEqual(12)
})
})
describe('back: given a user is on the third page', () => {
it('sets offset when back is emitted', () => {
wrapper.setData({ offset: 24 })
wrapper.find(Paginate).vm.$emit('back')
expect(wrapper.vm.offset).toEqual(12)
})
})
})
})
})

View File

@ -0,0 +1,119 @@
<template>
<ds-card space="small">
<ds-flex class="notifications-page-flex">
<ds-flex-item :width="{ lg: '85%' }">
<ds-heading tag="h3">{{ $t('notifications.title') }}</ds-heading>
</ds-flex-item>
<ds-flex-item width="110px">
<client-only>
<dropdown-filter
@filterNotifications="filterNotifications"
:filterOptions="filterOptions"
:selected="selected"
/>
</client-only>
</ds-flex-item>
</ds-flex>
<ds-space />
<notifications-table
@markNotificationAsRead="markNotificationAsRead"
:notifications="notifications"
/>
<paginate :hasNext="hasNext" :hasPrevious="hasPrevious" @back="back" @next="next" />
</ds-card>
</template>
<script>
import NotificationsTable from '~/components/NotificationsTable/NotificationsTable'
import DropdownFilter from '~/components/DropdownFilter/DropdownFilter'
import Paginate from '~/components/Paginate/Paginate'
import { notificationQuery, markAsReadMutation } from '~/graphql/User'
export default {
components: {
DropdownFilter,
NotificationsTable,
Paginate,
},
data() {
const pageSize = 12
return {
offset: 0,
notifications: [],
nofiticationRead: null,
pageSize,
first: pageSize,
hasNext: false,
selected: this.$t('notifications.filterLabel.all'),
}
},
computed: {
hasPrevious() {
return this.offset > 0
},
filterOptions() {
return [
{ label: this.$t('notifications.filterLabel.all'), value: null },
{ label: this.$t('notifications.filterLabel.read'), value: true },
{ label: this.$t('notifications.filterLabel.unread'), value: false },
]
},
},
methods: {
filterNotifications(option) {
this.notificationRead = option.value
this.selected = option.label
this.$apollo.queries.notifications.refresh()
},
async markNotificationAsRead(notificationSourceId) {
try {
await this.$apollo.mutate({
mutation: markAsReadMutation(this.$i18n),
variables: { id: notificationSourceId },
})
} catch (error) {
this.$toast.error(error.message)
}
},
back() {
this.offset = Math.max(this.offset - this.pageSize, 0)
},
next() {
this.offset += this.pageSize
},
},
apollo: {
notifications: {
query() {
return notificationQuery(this.$i18n)
},
variables() {
const { first, offset } = this
return {
read: this.notificationRead,
orderBy: 'updatedAt_desc',
first,
offset,
}
},
update({ notifications }) {
if (!notifications) return []
this.hasNext = notifications.length >= this.pageSize
if (notifications.length <= 0 && this.offset > 0) return this.notifications // edge case, avoid a blank page
return notifications.map((notification, index) =>
Object.assign({}, notification, { index: this.offset + index }),
)
},
fetchPolicy: 'cache-and-network',
error(error) {
this.$toast.error(error.message)
},
},
},
}
</script>
<style lang="scss">
.notifications-page-flex {
justify-content: space-between;
}
</style>

View File

@ -36,7 +36,7 @@
</template>
<script>
import HcEmpty from '~/components/Empty.vue'
import HcEmpty from '~/components/Empty/Empty'
import HcPostCard from '~/components/PostCard/PostCard.vue'
import HcCategory from '~/components/Category'
import HcHashtag from '~/components/Hashtag/Hashtag'

View File

@ -5,7 +5,7 @@
</template>
<script>
import HcEmpty from '~/components/Empty.vue'
import HcEmpty from '~/components/Empty/Empty'
export default {
components: {

View File

@ -278,7 +278,7 @@ import HcFollowButton from '~/components/FollowButton.vue'
import HcCountTo from '~/components/CountTo.vue'
import HcBadges from '~/components/Badges.vue'
import HcLoadMore from '~/components/LoadMore.vue'
import HcEmpty from '~/components/Empty.vue'
import HcEmpty from '~/components/Empty/Empty'
import ContentMenu from '~/components/ContentMenu'
import HcUpload from '~/components/Upload'
import HcAvatar from '~/components/Avatar/Avatar.vue'

View File

@ -12,7 +12,7 @@
<script>
import Signup from '~/components/Registration/Signup'
import HcEmpty from '~/components/Empty.vue'
import HcEmpty from '~/components/Empty/Empty'
export default {
layout: 'no-header',

View File

@ -5,7 +5,7 @@
</template>
<script>
import HcEmpty from '~/components/Empty.vue'
import HcEmpty from '~/components/Empty/Empty'
export default {
components: {

View File

@ -5,7 +5,7 @@
</template>
<script>
import HcEmpty from '~/components/Empty.vue'
import HcEmpty from '~/components/Empty/Empty'
export default {
components: {

View File

@ -5,7 +5,7 @@
</template>
<script>
import HcEmpty from '~/components/Empty.vue'
import HcEmpty from '~/components/Empty/Empty'
export default {
components: {

View File

@ -5,7 +5,7 @@
</template>
<script>
import HcEmpty from '~/components/Empty.vue'
import HcEmpty from '~/components/Empty/Empty'
export default {
components: {

View File

@ -84,6 +84,7 @@ export const actions = {
role
about
locationName
locale
contributionsCount
commentedCount
allowEmbedIframes

View File

@ -13,6 +13,7 @@ const currentUser = {
email: 'user@example.org',
avatar: 'https://s3.amazonaws.com/uifaces/faces/twitter/mutu_krish/128.jpg',
role: 'user',
locale: 'de',
}
const successfulLoginResponse = { data: { login: token } }
const successfulCurrentUserResponse = { data: { currentUser } }
@ -126,6 +127,7 @@ describe('actions', () => {
email: 'user@example.org',
avatar: 'https://s3.amazonaws.com/uifaces/faces/twitter/mutu_krish/128.jpg',
role: 'user',
locale: 'de',
},
],
]),

View File

@ -1,4 +1,5 @@
import '@storybook/addon-actions/register'
import '@storybook/addon-a11y/register'
import 'storybook-design-token/register'
import '@storybook/addon-notes/register-panel'
// import '@storybook/addon-links/register'

View File

@ -33,10 +33,13 @@ const helpers = {
namespaced: true,
getters: {
isModerator() {
return false
return true
},
isAdmin() {
return true
},
user(state) {
return { id: '1', name: 'admin' }
return { id: '1', name: 'admin', slug: 'admin' }
},
},
},

View File

@ -2070,17 +2070,17 @@
source-map-support "^0.5.7"
tslib "^1.9.3"
"@storybook/addon-a11y@^5.2.5":
version "5.2.5"
resolved "https://registry.yarnpkg.com/@storybook/addon-a11y/-/addon-a11y-5.2.5.tgz#e593b2b15573eb7d8ca9bb15130622af5fa82475"
integrity sha512-T7uK5B4Cp+bkC5BGVxSeSzXB8/AZA5uYPi8xqf6KQYizhrTsXZBrNwx2Lkbq1QP4Pcs8T2y3EG5/GikMIGoCPw==
"@storybook/addon-a11y@^5.2.6":
version "5.2.6"
resolved "https://registry.yarnpkg.com/@storybook/addon-a11y/-/addon-a11y-5.2.6.tgz#8aa603cac1eaa92ef53c51b842e502101dc5d074"
integrity sha512-LlY5TaZNDxl5MP8u2qCJmg8GhvbtYGXmWJv0GMof0cw1fuLMEBHKAa5vK2oWQdPjGpoSAYN80dqn3TyCqsoGnQ==
dependencies:
"@storybook/addons" "5.2.5"
"@storybook/api" "5.2.5"
"@storybook/client-logger" "5.2.5"
"@storybook/components" "5.2.5"
"@storybook/core-events" "5.2.5"
"@storybook/theming" "5.2.5"
"@storybook/addons" "5.2.6"
"@storybook/api" "5.2.6"
"@storybook/client-logger" "5.2.6"
"@storybook/components" "5.2.6"
"@storybook/core-events" "5.2.6"
"@storybook/theming" "5.2.6"
axe-core "^3.3.2"
common-tags "^1.8.0"
core-js "^3.0.1"
@ -2093,17 +2093,17 @@
redux "^4.0.1"
util-deprecate "^1.0.2"
"@storybook/addon-actions@^5.2.5":
version "5.2.5"
resolved "https://registry.yarnpkg.com/@storybook/addon-actions/-/addon-actions-5.2.5.tgz#e8279907367392387d5c3c6af6031f9da2be9816"
integrity sha512-81N+M1GX4XB7Mirhhu3kiZJkjspfk2e1ysoJtwULjWeZfo2CLYLUAil4onr08Os2LH4RLJaj2hpS3hLflBio4g==
"@storybook/addon-actions@^5.2.6":
version "5.2.6"
resolved "https://registry.yarnpkg.com/@storybook/addon-actions/-/addon-actions-5.2.6.tgz#4fe411fc3bdb1d44058f23fbc8eb8d1bac29d521"
integrity sha512-CwTJPqe3NcEU7oqS5KoiCX9FXYmI2Dyp1Sh6r90JmXZ8B49ZXm6BDLX0gS3TooD6/AcdU8xdBcSvN0CkxQ5QGA==
dependencies:
"@storybook/addons" "5.2.5"
"@storybook/api" "5.2.5"
"@storybook/client-api" "5.2.5"
"@storybook/components" "5.2.5"
"@storybook/core-events" "5.2.5"
"@storybook/theming" "5.2.5"
"@storybook/addons" "5.2.6"
"@storybook/api" "5.2.6"
"@storybook/client-api" "5.2.6"
"@storybook/components" "5.2.6"
"@storybook/core-events" "5.2.6"
"@storybook/theming" "5.2.6"
core-js "^3.0.1"
fast-deep-equal "^2.0.1"
global "^4.3.2"
@ -2113,6 +2113,25 @@
react-inspector "^3.0.2"
uuid "^3.3.2"
"@storybook/addon-notes@^5.2.5":
version "5.2.6"
resolved "https://registry.yarnpkg.com/@storybook/addon-notes/-/addon-notes-5.2.6.tgz#bf74ff4f8018e315a4c07c3d5e90cd9154ce6e8e"
integrity sha512-CfWOkoPFI1ZAWQYnwFVqGmeCeXnVQGoFyDSVc3NcIFF1lsk2aagGV+ifJMJuDTXIKu0FClKpvMcENWt+bBpA+w==
dependencies:
"@storybook/addons" "5.2.6"
"@storybook/api" "5.2.6"
"@storybook/client-logger" "5.2.6"
"@storybook/components" "5.2.6"
"@storybook/core-events" "5.2.6"
"@storybook/router" "5.2.6"
"@storybook/theming" "5.2.6"
core-js "^3.0.1"
global "^4.3.2"
markdown-to-jsx "^6.10.3"
memoizerific "^1.11.3"
prop-types "^15.7.2"
util-deprecate "^1.0.2"
"@storybook/addons@5.1.9":
version "5.1.9"
resolved "https://registry.yarnpkg.com/@storybook/addons/-/addons-5.1.9.tgz#ecf218d08508b97ca5e6e0f1ed361081385bd3ff"
@ -2125,15 +2144,15 @@
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==
"@storybook/addons@5.2.6":
version "5.2.6"
resolved "https://registry.yarnpkg.com/@storybook/addons/-/addons-5.2.6.tgz#c1278137acb3502e068b0b0d07a8371c607e9c02"
integrity sha512-5MF64lsAhIEMxTbVpYROz5Wez595iwSw45yXyP8gWt12d+EmFO5tdy7cYJCxcMuVhDfaCI78tFqS9orr1atVyA==
dependencies:
"@storybook/api" "5.2.5"
"@storybook/channels" "5.2.5"
"@storybook/client-logger" "5.2.5"
"@storybook/core-events" "5.2.5"
"@storybook/api" "5.2.6"
"@storybook/channels" "5.2.6"
"@storybook/client-logger" "5.2.6"
"@storybook/core-events" "5.2.6"
core-js "^3.0.1"
global "^4.3.2"
util-deprecate "^1.0.2"
@ -2161,16 +2180,16 @@
telejson "^2.2.1"
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==
"@storybook/api@5.2.6":
version "5.2.6"
resolved "https://registry.yarnpkg.com/@storybook/api/-/api-5.2.6.tgz#43d3c20b90e585e6c94b36e29845d39704ae2135"
integrity sha512-X/di44/SAL68mD6RHTX2qdWwhjRW6BgcfPtu0dMd38ErB3AfsfP4BITXs6kFOeSM8kWiaQoyuw0pOBzA8vlYug==
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"
"@storybook/channels" "5.2.6"
"@storybook/client-logger" "5.2.6"
"@storybook/core-events" "5.2.6"
"@storybook/router" "5.2.6"
"@storybook/theming" "5.2.6"
core-js "^3.0.1"
fast-deep-equal "^2.0.1"
global "^4.3.2"
@ -2184,13 +2203,13 @@
telejson "^3.0.2"
util-deprecate "^1.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==
"@storybook/channel-postmessage@5.2.6":
version "5.2.6"
resolved "https://registry.yarnpkg.com/@storybook/channel-postmessage/-/channel-postmessage-5.2.6.tgz#60aaef0e80300c9812a571ca3ce0f28e2c404f04"
integrity sha512-y+63wWiEc/Q4s4MZ3KJ//5A8j5VLufxuLvPxwv9FuS4z8lmN0fqeGJn857qIlFGbZhzsQaoRdmfsCQpBBgUneg==
dependencies:
"@storybook/channels" "5.2.5"
"@storybook/client-logger" "5.2.5"
"@storybook/channels" "5.2.6"
"@storybook/client-logger" "5.2.6"
core-js "^3.0.1"
global "^4.3.2"
telejson "^3.0.2"
@ -2202,24 +2221,24 @@
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==
"@storybook/channels@5.2.6":
version "5.2.6"
resolved "https://registry.yarnpkg.com/@storybook/channels/-/channels-5.2.6.tgz#e2837508864dc4d5b5e03f078886f0ce113762ea"
integrity sha512-/UsktYsXuvb1efjVPCEivhh5ywRhm7hl73pQnpJLJHRqyLMM2I5nGPFELTTNuU9yWy7sP9QL5gRqBBPe1sqjZQ==
dependencies:
core-js "^3.0.1"
"@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==
"@storybook/client-api@5.2.6":
version "5.2.6"
resolved "https://registry.yarnpkg.com/@storybook/client-api/-/client-api-5.2.6.tgz#5760cb4302d82ce9210a63f3f55b1e05f04759c1"
integrity sha512-upynf4ER2fkThNnE+mBlfRFFJxTiOh60fho1ODFcBun9BbvRD2wOHLvw7+WigIhb99HM20vk8f2dhv3I5Udzlg==
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"
"@storybook/addons" "5.2.6"
"@storybook/channel-postmessage" "5.2.6"
"@storybook/channels" "5.2.6"
"@storybook/client-logger" "5.2.6"
"@storybook/core-events" "5.2.6"
"@storybook/router" "5.2.6"
common-tags "^1.8.0"
core-js "^3.0.1"
eventemitter3 "^4.0.0"
@ -2237,10 +2256,10 @@
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==
"@storybook/client-logger@5.2.6":
version "5.2.6"
resolved "https://registry.yarnpkg.com/@storybook/client-logger/-/client-logger-5.2.6.tgz#cfc4536e9b724b086f7509c2bb34c221016713c9"
integrity sha512-hJvPD267cCwLIRMOISjDH8h9wbwOcXIJip29UlJbU9iMtZtgE+YelmlpmZJvqcDfUiXWWrOh7tP76mj8EAfwIQ==
dependencies:
core-js "^3.0.1"
@ -2268,13 +2287,13 @@
recompose "^0.30.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==
"@storybook/components@5.2.6":
version "5.2.6"
resolved "https://registry.yarnpkg.com/@storybook/components/-/components-5.2.6.tgz#cddb60227720aea7cae34fe782d0370bcdbd4005"
integrity sha512-C7OS90bZ1ZvxlWUZ3B2MPFFggqAtUo7X8DqqS3IwsuDUiK9dD/KS0MwPgOuFDnOTW1R5XqmQd/ylt53w3s/U5g==
dependencies:
"@storybook/client-logger" "5.2.5"
"@storybook/theming" "5.2.5"
"@storybook/client-logger" "5.2.6"
"@storybook/theming" "5.2.6"
"@types/react-syntax-highlighter" "10.1.0"
"@types/react-textarea-autosize" "^4.3.3"
core-js "^3.0.1"
@ -2300,32 +2319,32 @@
dependencies:
core-js "^3.0.1"
"@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==
"@storybook/core-events@5.2.6":
version "5.2.6"
resolved "https://registry.yarnpkg.com/@storybook/core-events/-/core-events-5.2.6.tgz#34c9aae256e7e5f4a565b81f1e77dda8bccc6752"
integrity sha512-W8kLJ7tc0aAxs11CPUxUOCReocKL4MYGyjTg8qwk0USLzPUb/FUQWmhcm2ilFz6Nz8dXLcKrXdRVYTmiMsgAeg==
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==
"@storybook/core@5.2.6":
version "5.2.6"
resolved "https://registry.yarnpkg.com/@storybook/core/-/core-5.2.6.tgz#60c092607158d7d28db59f7e67da4f7e12703fb2"
integrity sha512-q7Ful7TCm9nmjgLsJFqIwVv395NlaOXgGajyaQCQlCKB2V+jgs7GDmdCNNdWAOue4eAsFU6wQSP9lWtq0yzK4w==
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.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"
"@storybook/addons" "5.2.6"
"@storybook/channel-postmessage" "5.2.6"
"@storybook/client-api" "5.2.6"
"@storybook/client-logger" "5.2.6"
"@storybook/core-events" "5.2.6"
"@storybook/node-logger" "5.2.6"
"@storybook/router" "5.2.6"
"@storybook/theming" "5.2.6"
"@storybook/ui" "5.2.6"
airbnb-js-shims "^1 || ^2"
ansi-to-html "^0.6.11"
autoprefixer "^9.4.9"
@ -2381,10 +2400,10 @@
webpack-dev-middleware "^3.7.0"
webpack-hot-middleware "^2.25.0"
"@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==
"@storybook/node-logger@5.2.6":
version "5.2.6"
resolved "https://registry.yarnpkg.com/@storybook/node-logger/-/node-logger-5.2.6.tgz#e353aff14375bef9e922c217a0afb50f93e2ceb1"
integrity sha512-Z3mn9CUSiG7kR2OBoz4lNeoeBS094h5d9wufZSp5S+M47L6KEXmTgNcuePKj+t8Z8KT/Ph8B63bjChseKp3DNw==
dependencies:
chalk "^2.4.2"
core-js "^3.0.1"
@ -2403,10 +2422,10 @@
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==
"@storybook/router@5.2.6":
version "5.2.6"
resolved "https://registry.yarnpkg.com/@storybook/router/-/router-5.2.6.tgz#5180d3785501699283c6c3717986c877f84fead5"
integrity sha512-/FZd3fYg5s2QzOqSIP8UMOSnCIFFIlli/jKlOxvm3WpcpxgwQOY4lfHsLO+r9ThCLs2UvVg2R/HqGrOHqDFU7A==
dependencies:
"@reach/router" "^1.2.1"
"@types/reach__router" "^1.2.3"
@ -2434,14 +2453,14 @@
prop-types "^15.7.2"
resolve-from "^5.0.0"
"@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==
"@storybook/theming@5.2.6":
version "5.2.6"
resolved "https://registry.yarnpkg.com/@storybook/theming/-/theming-5.2.6.tgz#e04170b3e53dcfc791b2381c8a39192ae88cd291"
integrity sha512-Xa9R/H8DDgmvxsCHloJUJ2d9ZQl80AeqHrL+c/AKNpx05s9lV74DcinusCf0kz72YGUO/Xt1bAjuOvLnAaS8Gw==
dependencies:
"@emotion/core" "^10.0.14"
"@emotion/styled" "^10.0.14"
"@storybook/client-logger" "5.2.5"
"@storybook/client-logger" "5.2.6"
common-tags "^1.8.0"
core-js "^3.0.1"
deep-object-diff "^1.1.0"
@ -2452,19 +2471,19 @@
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==
"@storybook/ui@5.2.6":
version "5.2.6"
resolved "https://registry.yarnpkg.com/@storybook/ui/-/ui-5.2.6.tgz#33df2f2e03d9cf81dc52928a0dc4db280ee8f56a"
integrity sha512-jT3PtpEsTqnESO0U8BotC+5P971Xqy0s2leSZcgU9PNe4Eb7NaxypSULOulPgPAx1JOmMipUBdK54PP/nyudkA==
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"
"@storybook/addons" "5.2.6"
"@storybook/api" "5.2.6"
"@storybook/channels" "5.2.6"
"@storybook/client-logger" "5.2.6"
"@storybook/components" "5.2.6"
"@storybook/core-events" "5.2.6"
"@storybook/router" "5.2.6"
"@storybook/theming" "5.2.6"
copy-to-clipboard "^3.0.8"
core-js "^3.0.1"
core-js-pure "^3.0.1"
@ -2491,13 +2510,13 @@
telejson "^3.0.2"
util-deprecate "^1.0.2"
"@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==
"@storybook/vue@~5.2.6":
version "5.2.6"
resolved "https://registry.yarnpkg.com/@storybook/vue/-/vue-5.2.6.tgz#1d79880c7e1a14e4deb66c5e438ed3326a3c7c47"
integrity sha512-jYoe+rHT1mKCJp8tcbE6ZPIhLidi5nD9z4XKzfHCZ4HsIWSl7dD+Q7QX1JeZYCCMf6VA27G40l4hUJHWEUyWxA==
dependencies:
"@storybook/addons" "5.2.5"
"@storybook/core" "5.2.5"
"@storybook/addons" "5.2.6"
"@storybook/core" "5.2.6"
"@types/webpack-env" "^1.13.9"
common-tags "^1.8.0"
core-js "^3.0.1"
@ -3246,7 +3265,7 @@ acorn@^5.5.3:
resolved "https://registry.yarnpkg.com/acorn/-/acorn-5.7.3.tgz#67aa231bf8812974b85235a96771eb6bd07ea279"
integrity sha512-T/zvzYRfbVojPWahDsE5evJdHb3oJoQfFbsrKM7w5Zcs++Tr257tia3BmMP8XYVjp1S9RZXQMh7gao96BlqZOw==
acorn@^6.0.1, acorn@^6.0.2, acorn@^6.0.7:
acorn@^6.0.1, acorn@^6.0.7:
version "6.1.1"
resolved "https://registry.yarnpkg.com/acorn/-/acorn-6.1.1.tgz#7d25ae05bb8ad1f9b699108e1094ecd7884adc1f"
integrity sha512-jPTiwtOxaHNaAPg/dmrJ/beuzLRnXtB0kQPQ8JpotKJgTB6rX6c8mlf315941pyjBSaPg8NHXS9fhP4u17DpGA==
@ -4123,10 +4142,10 @@ async-retry@^1.2.1:
dependencies:
retry "0.12.0"
async-validator@^3.2.1:
version "3.2.1"
resolved "https://registry.yarnpkg.com/async-validator/-/async-validator-3.2.1.tgz#19ac8655c1296a5331b00c75f2492f0d33cae1f8"
integrity sha512-yc96RhAthww0n52m9osoI1uDQbbyd/N2xwPWS1gVvngSWOsKerpBFCulvmhp8GfNwUay41TWskNTd3swQM1XMA==
async-validator@^3.2.2:
version "3.2.2"
resolved "https://registry.yarnpkg.com/async-validator/-/async-validator-3.2.2.tgz#91f6314d2dc7f03fd90940bcb577afc8ee5466ac"
integrity sha512-NT5efhGkksDqODAsARaTAlkPshMgmpWw80ijM2MEr1TrDczBETaNRS3GDd1jsVRK5YSfVW10Zscab98rDYkaBA==
async@^1.4.0:
version "1.5.2"
@ -6379,10 +6398,10 @@ data-urls@^1.0.0:
whatwg-mimetype "^2.2.0"
whatwg-url "^7.0.0"
date-fns@2.6.0:
version "2.6.0"
resolved "https://registry.yarnpkg.com/date-fns/-/date-fns-2.6.0.tgz#a5bc82e6a4c3995ae124b0ba1a71aec7b8cbd666"
integrity sha512-F55YxqRdEfP/eYQmQjLN798v0AwLjmZ8nMBjdQvNwEE3N/zWVrlkkqT+9seBlPlsbkybG4JmWg3Ee3dIV9BcGQ==
date-fns@2.7.0:
version "2.7.0"
resolved "https://registry.yarnpkg.com/date-fns/-/date-fns-2.7.0.tgz#8271d943cc4636a1f27698f1b8d6a9f1ceb74026"
integrity sha512-wxYp2PGoUDN5ZEACc61aOtYFvSsJUylIvCjpjDOqM1UDaKIIuMJ9fAnMYFHV3TQaDpfTVxhwNK/GiCaHKuemTA==
date-fns@^1.27.2:
version "1.30.1"
@ -7126,12 +7145,12 @@ eslint-plugin-standard@~4.0.1:
resolved "https://registry.yarnpkg.com/eslint-plugin-standard/-/eslint-plugin-standard-4.0.1.tgz#ff0519f7ffaff114f76d1bd7c3996eef0f6e20b4"
integrity sha512-v/KBnfyaOMPmZc/dmc6ozOdWqekGp7bBGq4jLAecEfPGmfKiWS4sA8sC0LqiV9w5qmXAtXVn4M3p1jSyhY85SQ==
eslint-plugin-vue@~5.2.3:
version "5.2.3"
resolved "https://registry.yarnpkg.com/eslint-plugin-vue/-/eslint-plugin-vue-5.2.3.tgz#3ee7597d823b5478804b2feba9863b1b74273961"
integrity sha512-mGwMqbbJf0+VvpGR5Lllq0PMxvTdrZ/ZPjmhkacrCHbubJeJOt+T6E3HUzAifa2Mxi7RSdJfC9HFpOeSYVMMIw==
eslint-plugin-vue@~6.0.0:
version "6.0.0"
resolved "https://registry.yarnpkg.com/eslint-plugin-vue/-/eslint-plugin-vue-6.0.0.tgz#fc7a4116dff614a27be8639fb47973703dd332fa"
integrity sha512-+LxTJCd6nDt+AKQ1X+ySD48xJHft8OkeQmAhiq6UoAMxRFTiEKIDusiGgEUJLwKyiwGUGWbbqEbbWvupH5TSjg==
dependencies:
vue-eslint-parser "^5.0.0"
vue-eslint-parser "^6.0.4"
eslint-scope@^4.0.0, eslint-scope@^4.0.3:
version "4.0.3"
@ -7208,16 +7227,7 @@ esm@^3.2.25:
resolved "https://registry.yarnpkg.com/esm/-/esm-3.2.25.tgz#342c18c29d56157688ba5ce31f8431fbb795cc10"
integrity sha512-U1suiZ2oDVWv4zPO56S0NcR5QriEahGtdN2OR6FiOG4WJvcjBVFB0qI4+eKoWFH483PKGuLuu6V8Z4T5g63UVA==
espree@^4.1.0:
version "4.1.0"
resolved "https://registry.yarnpkg.com/espree/-/espree-4.1.0.tgz#728d5451e0fd156c04384a7ad89ed51ff54eb25f"
integrity sha512-I5BycZW6FCVIub93TeVY1s7vjhP9CY6cXCznIRfiig7nRviKZYdRnj/sHEWC6A7WE9RDWOFq9+7OsWSYz8qv2w==
dependencies:
acorn "^6.0.2"
acorn-jsx "^5.0.0"
eslint-visitor-keys "^1.0.0"
espree@^5.0.1:
espree@^5.0.0, espree@^5.0.1:
version "5.0.1"
resolved "https://registry.yarnpkg.com/espree/-/espree-5.0.1.tgz#5d6526fa4fc7f0788a5cf75b15f30323e2f81f7a"
integrity sha512-qWAZcWh4XE/RwzLJejfcofscgMc9CamR6Tn1+XRXNzrvUSSbiAjGOI/fggztjIi7y9VLPqnICMIPiGyr8JaZ0A==
@ -8135,10 +8145,10 @@ glob@7.1.4:
once "^1.3.0"
path-is-absolute "^1.0.0"
glob@^7.0.0, glob@^7.0.3, glob@^7.0.5, glob@^7.1.1, glob@^7.1.2, glob@^7.1.3, glob@^7.1.4, glob@^7.1.5, glob@~7.1.1:
version "7.1.5"
resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.5.tgz#6714c69bee20f3c3e64c4dd905553e532b40cdc0"
integrity sha512-J9dlskqUXK1OeTOYBEn5s8aMukWMwWfs+rPTn/jn50Ux4MNXVhubL1wu/j2t+H4NVI+cXEcCaYellqaPVGXNqQ==
glob@^7.0.0, glob@^7.0.3, glob@^7.0.5, glob@^7.1.1, glob@^7.1.2, glob@^7.1.3, glob@^7.1.4, glob@^7.1.5, glob@^7.1.6, glob@~7.1.1:
version "7.1.6"
resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.6.tgz#141f33b81a7c2492e125594307480c46679278a6"
integrity sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==
dependencies:
fs.realpath "^1.0.0"
inflight "^1.0.4"
@ -10713,6 +10723,14 @@ map-visit@^1.0.0:
dependencies:
object-visit "^1.0.0"
markdown-to-jsx@^6.10.3:
version "6.10.3"
resolved "https://registry.yarnpkg.com/markdown-to-jsx/-/markdown-to-jsx-6.10.3.tgz#7f0946684acd321125ff2de7fd258a9b9c7c40b7"
integrity sha512-PSoUyLnW/xoW6RsxZrquSSz5eGEOTwa15H5eqp3enmrp8esmgDJmhzd6zmQ9tgAA9TxJzx1Hmf3incYU/IamoQ==
dependencies:
prop-types "^15.6.2"
unquote "^1.1.0"
markdown-to-jsx@^6.9.1, markdown-to-jsx@^6.9.3:
version "6.10.2"
resolved "https://registry.yarnpkg.com/markdown-to-jsx/-/markdown-to-jsx-6.10.2.tgz#644f602b81d088f10aef1c3674874876146cf38b"
@ -14138,15 +14156,7 @@ schema-utils@^1.0.0:
ajv-errors "^1.0.0"
ajv-keywords "^3.1.0"
schema-utils@^2.0.0, schema-utils@^2.1.0, schema-utils@^2.2.0:
version "2.2.0"
resolved "https://registry.yarnpkg.com/schema-utils/-/schema-utils-2.2.0.tgz#48a065ce219e0cacf4631473159037b2c1ae82da"
integrity sha512-5EwsCNhfFTZvUreQhx/4vVQpJ/lnCAkgoIHLhSpp4ZirE+4hzFvdJi0FMub6hxbFVBJYSpeVVmon+2e7uEGRrA==
dependencies:
ajv "^6.10.2"
ajv-keywords "^3.4.1"
schema-utils@^2.0.1:
schema-utils@^2.0.0, schema-utils@^2.0.1, schema-utils@^2.1.0, schema-utils@^2.2.0, schema-utils@^2.4.1, schema-utils@^2.5.0:
version "2.5.0"
resolved "https://registry.yarnpkg.com/schema-utils/-/schema-utils-2.5.0.tgz#8f254f618d402cc80257486213c8970edfd7c22f"
integrity sha512-32ISrwW2scPXHUSusP8qMg5dLUawKkyV+/qIEV9JdXKx+rsM6mi8vZY8khg2M69Qom16rtroWXD3Ybtiws38gQ==
@ -14154,14 +14164,6 @@ schema-utils@^2.0.1:
ajv "^6.10.2"
ajv-keywords "^3.4.1"
schema-utils@^2.4.1:
version "2.4.1"
resolved "https://registry.yarnpkg.com/schema-utils/-/schema-utils-2.4.1.tgz#e89ade5d056dc8bcaca377574bb4a9c4e1b8be56"
integrity sha512-RqYLpkPZX5Oc3fw/kHHHyP56fg5Y+XBpIpV8nCg0znIALfq3OH+Ea9Hfeac9BAMwG5IICltiZ0vxFvJQONfA5w==
dependencies:
ajv "^6.10.2"
ajv-keywords "^3.4.1"
scriptjs@^2.5.9:
version "2.5.9"
resolved "https://registry.yarnpkg.com/scriptjs/-/scriptjs-2.5.9.tgz#343915cd2ec2ed9bfdde2b9875cd28f59394b35f"
@ -14964,6 +14966,11 @@ storybook-design-token@^0.4.1:
raw-loader "3.1.0"
react-use-clipboard "0.1.4"
storybook-vue-router@^1.0.7:
version "1.0.7"
resolved "https://registry.yarnpkg.com/storybook-vue-router/-/storybook-vue-router-1.0.7.tgz#366451212149d9d0a32557545b244667bb01768e"
integrity sha512-R+DYARQ40YVbMbV5moLDmQvodJX5FQPVy5cULb782P1gD5rAkulWtgt8yrM7pmjYru+LTPdLS4blrFPnWlb0sQ==
stream-browserify@^2.0.1:
version "2.0.2"
resolved "https://registry.yarnpkg.com/stream-browserify/-/stream-browserify-2.0.2.tgz#87521d38a44aa7ee91ce1cd2a47df0cb49dd660b"
@ -15160,16 +15167,15 @@ style-loader@^0.23.1, style-loader@~0.23.1:
loader-utils "^1.1.0"
schema-utils "^1.0.0"
style-resources-loader@^1.2.1, style-resources-loader@~1.2.1:
version "1.2.1"
resolved "https://registry.yarnpkg.com/style-resources-loader/-/style-resources-loader-1.2.1.tgz#7679d5dc2f27046b2fc2b83c1d5b6c1b8a9b820c"
integrity sha512-ekId7AwZRW429UjQo02CJTt0Y8GwoT9zidvJLq4lRTJbu0cghv9XNRmt9mS4MR41+gZwMRT0EpFzP68HDWLbXQ==
style-resources-loader@^1.2.1, style-resources-loader@~1.3.2:
version "1.3.2"
resolved "https://registry.yarnpkg.com/style-resources-loader/-/style-resources-loader-1.3.2.tgz#dee034e33e84060ded0b1980f866453e98589873"
integrity sha512-UIwyrl/OZGO+ptyeNyeDnNE+2RqD0AKqjAuxBxhce0YlHMx2DbZ48g0Mx9buKuiNSgBUXYQtbwilKcYeJlVsog==
dependencies:
glob "^7.1.2"
is-callable "^1.1.4"
is-plain-object "^2.0.4"
glob "^7.1.6"
is-promise "^2.1.0"
loader-utils "^1.1.0"
loader-utils "^1.2.3"
schema-utils "^2.5.0"
stylehacks@^4.0.0:
version "4.0.3"
@ -15223,10 +15229,10 @@ svg-tags@^1.0.0:
resolved "https://registry.yarnpkg.com/svg-tags/-/svg-tags-1.0.0.tgz#58f71cee3bd519b59d4b2a843b6c7de64ac04764"
integrity sha1-WPcc7jvVGbWdSyqEO2x95krAR2Q=
svg-to-vue@^0.5.0:
version "0.5.0"
resolved "https://registry.yarnpkg.com/svg-to-vue/-/svg-to-vue-0.5.0.tgz#9b75baab677104a13649e38814dc4e9c6b20cd47"
integrity sha512-DhyoSbSM9h7HygtxS+QFDziGTx3JiMhu2Mry3XdmOgcgsgSmTS0iqpHzmo0V91UNre4AZrnsw1cAD4yWtmeuGw==
svg-to-vue@^0.6.0:
version "0.6.0"
resolved "https://registry.yarnpkg.com/svg-to-vue/-/svg-to-vue-0.6.0.tgz#d5de9ec7126ac3c11adf8cfad013a6264ef57184"
integrity sha512-SYGJMBq5EHt/nIJxZ4kA9A6bilaFXtOPFJRoMQ2ml/jFP4N9L7HVFTm+5WCFN3QFnEUXtH6BHzpoOlwP1/5+2A==
dependencies:
svgo "^1.3.2"
@ -16278,15 +16284,15 @@ vue-count-to@~1.0.13:
resolved "https://registry.yarnpkg.com/vue-count-to/-/vue-count-to-1.0.13.tgz#3e7573ea6e64c2b2972f64e0a2ab2e23c7590ff3"
integrity sha512-6R4OVBVNtQTlcbXu6SJ8ENR35M2/CdWt3Jmv57jOUM+1ojiFmjVGvZPH8DfHpMDSA+ITs+EW5V6qthADxeyYOQ==
vue-eslint-parser@^5.0.0:
version "5.0.0"
resolved "https://registry.yarnpkg.com/vue-eslint-parser/-/vue-eslint-parser-5.0.0.tgz#00f4e4da94ec974b821a26ff0ed0f7a78402b8a1"
integrity sha512-JlHVZwBBTNVvzmifwjpZYn0oPWH2SgWv5dojlZBsrhablDu95VFD+hriB1rQGwbD+bms6g+rAFhQHk6+NyiS6g==
vue-eslint-parser@^6.0.4:
version "6.0.4"
resolved "https://registry.yarnpkg.com/vue-eslint-parser/-/vue-eslint-parser-6.0.4.tgz#56ff47e2c2644bff39951d5a284982c7ecd6f7fa"
integrity sha512-GYsDsDWwKaGtnkW4nGUxr01wqIO2FB9/QHQTW1Gl5SUr5OyQvpnR90/D+Gq2cIxURX7aJ7+VyD+37Yx9eFwTgw==
dependencies:
debug "^4.1.0"
debug "^4.1.1"
eslint-scope "^4.0.0"
eslint-visitor-keys "^1.0.0"
espree "^4.1.0"
espree "^5.0.0"
esquery "^1.0.1"
lodash "^4.17.11"
@ -16385,13 +16391,13 @@ vue-style-loader@^4.1.0:
hash-sum "^1.0.2"
loader-utils "^1.0.2"
vue-svg-loader@~0.14.0:
version "0.14.0"
resolved "https://registry.yarnpkg.com/vue-svg-loader/-/vue-svg-loader-0.14.0.tgz#672358ffb3aea4f4f5c4f6659a44feba8e0cca4a"
integrity sha512-MRHbKsj+u0lGoElCJ+ZvCZpCl+xNiZW8sfeyfB3wIa0G5P4qKBXhpHvhFIXupxQAEdJu0vaC/CUsLeAmXeluuw==
vue-svg-loader@~0.15.0:
version "0.15.0"
resolved "https://registry.yarnpkg.com/vue-svg-loader/-/vue-svg-loader-0.15.0.tgz#09bb9929c3f8955a246ea80909e26139badc0509"
integrity sha512-698GfXu9k2wPxI382Qf7MfrtBXjIjThqmOsksVKHqeTvVO+Ary9q69SVzA6EEJmj5vmF5u1KRVb/I1BDh4fPTQ==
dependencies:
loader-utils "^1.2.3"
svg-to-vue "^0.5.0"
svg-to-vue "^0.6.0"
vue-sweetalert-icons@~4.2.0:
version "4.2.0"
@ -16592,36 +16598,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:
version "4.41.0"
resolved "https://registry.yarnpkg.com/webpack/-/webpack-4.41.0.tgz#db6a254bde671769f7c14e90a1a55e73602fc70b"
integrity sha512-yNV98U4r7wX1VJAj5kyMsu36T8RPPQntcb5fJLOsMz/pt/WrKC0Vp1bAlqPLkA1LegSwQwf6P+kAbyhRKVQ72g==
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"
webpack@^4.41.2:
webpack@^4.33.0, webpack@^4.38.0, 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==

View File

@ -1924,20 +1924,20 @@ cypress-cucumber-preprocessor@^1.16.2:
js-string-escape "^1.0.1"
through "^2.3.8"
cypress-file-upload@^3.4.0:
version "3.4.0"
resolved "https://registry.yarnpkg.com/cypress-file-upload/-/cypress-file-upload-3.4.0.tgz#f066853357994ed7b64e0ea35920d3d85273914e"
integrity sha512-BY7jrpOPFEGcGBzkTReEjwQ59+O3u2SH2OleXdnDCuWIPHjbDx7haXukyAFd906JsI4Z2zXPiKrUVFHZc96eFA==
cypress-file-upload@^3.5.0:
version "3.5.0"
resolved "https://registry.yarnpkg.com/cypress-file-upload/-/cypress-file-upload-3.5.0.tgz#7ff6294a3be68adcac72bc1fa25c75c57e0701fc"
integrity sha512-MgrsP4C2pUMvHqixH33OtXHNKkwQZV6ny0fu+APDTEP9O/uuKFh3sYcnPNU6XGfuC85/RmqVNw21ZQyyT+S5IQ==
cypress-plugin-retries@^1.4.0:
version "1.4.0"
resolved "https://registry.yarnpkg.com/cypress-plugin-retries/-/cypress-plugin-retries-1.4.0.tgz#30477294a22e368c874d50dc282e657906080955"
integrity sha512-Pudna9+dn0wp3flUVWt1ttn6hKTnD1MIBUSznYkw+uRv3JPNJhxHIv9cfxrZmig49/R1fIyGBVNORchtnFedEw==
cypress@^3.6.0:
version "3.6.0"
resolved "https://registry.yarnpkg.com/cypress/-/cypress-3.6.0.tgz#b7c88c169970aeb74a00182a1e8dc43a355d9eea"
integrity sha512-ODhbOrH1XZx0DUoYmJSvOSbEQjycNOpFYe7jOnHkT1+sdsn2+uqwAjZ1x982q3H4R/5iZjpSd50gd/iw2bofzg==
cypress@^3.6.1:
version "3.6.1"
resolved "https://registry.yarnpkg.com/cypress/-/cypress-3.6.1.tgz#4420957923879f60b7a5146ccbf81841a149b653"
integrity sha512-6n0oqENdz/oQ7EJ6IgESNb2M7Bo/70qX9jSJsAziJTC3kICfEMmJUlrAnP9bn+ut24MlXQST5nRXhUP5nRIx6A==
dependencies:
"@cypress/listr-verbose-renderer" "0.4.1"
"@cypress/xvfb" "1.2.4"
@ -1996,10 +1996,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.6.0:
version "2.6.0"
resolved "https://registry.yarnpkg.com/date-fns/-/date-fns-2.6.0.tgz#a5bc82e6a4c3995ae124b0ba1a71aec7b8cbd666"
integrity sha512-F55YxqRdEfP/eYQmQjLN798v0AwLjmZ8nMBjdQvNwEE3N/zWVrlkkqT+9seBlPlsbkybG4JmWg3Ee3dIV9BcGQ==
date-fns@^2.7.0:
version "2.7.0"
resolved "https://registry.yarnpkg.com/date-fns/-/date-fns-2.7.0.tgz#8271d943cc4636a1f27698f1b8d6a9f1ceb74026"
integrity sha512-wxYp2PGoUDN5ZEACc61aOtYFvSsJUylIvCjpjDOqM1UDaKIIuMJ9fAnMYFHV3TQaDpfTVxhwNK/GiCaHKuemTA==
date-now@^0.1.4:
version "0.1.4"