Skip to content
Commits on Source (33)
......@@ -26,7 +26,6 @@
"scripts": [
"../node_modules/material-design-lite/dist/material.min.js",
"../node_modules/medium-editor/dist/js/medium-editor.min.js",
"shims/fontawesome.js",
"shims/jitsi-api.min.js"
],
"environmentSource": "environments/environment.ts",
......
......@@ -4,7 +4,7 @@ services:
- docker:dind
stages:
- test:unit
- test
- build
- prepare
- review
......@@ -12,6 +12,7 @@ stages:
- test:e2e
- deploy:canary
- deploy:production
- cleanup
variables:
CYPRESS_INSTALL_BINARY: 0 # Speeds up the install process
......@@ -20,37 +21,18 @@ variables:
test:
image: circleci/node:8-browsers
stage: test:unit
stage: test
script:
- npm ci
- npm run test -- --no-watch --no-progress --browsers=ChromeHeadlessCI
e2e:base:
image: cypress/base:10
stage: test:e2e
variables:
CYPRESS_INSTALL_BINARY: 3.4.1
lint:
stage: test
script:
- npm ci
- >
if [ "$CI_BUILD_REF_NAME" == "master" ]; then
export E2E_DOMAIN=https://www.minds.com
else
export E2E_DOMAIN=https://$CI_BUILD_REF_SLUG.$KUBE_INGRESS_BASE_DOMAIN
fi
- export CYPRESS_baseUrl=$E2E_DOMAIN
- echo "E2E tests for $CI_BUILD_REF_NAME running against $E2E_DOMAIN with user $CYPRESS_username"
- $(npm bin)/cypress run --record --key $CYPRESS_RECORD_ID --config CYPRESS_baseUrl=$E2E_DOMAIN
artifacts:
when: always
paths:
- cypress/screenshots
- cypress/videos
cache:
paths:
- .npm
- cache/Cypress
allow_failure: true #manual inspection in case of timeouts
- npm i -g prettier
- prettier --check "src/**/*.ts"
- prettier --check "src/**/*.scss"
- prettier --check "src/**/*.html"
e2e:chrome:
image: cypress/browsers:chrome67
......@@ -79,8 +61,14 @@ e2e:chrome:
- cache/Cypress
allow_failure: true #manual inspection in case of timeouts
###############
# Build Stage #
###############
build:review:
stage: build
before_script:
- sed -ri "s|\"VERSION\"|\"$CI_PIPELINE_ID\"|" src/environments/environment.prod.ts
script:
- npm ci && npm install -g gulp-cli
- npm run postinstall
......@@ -97,6 +85,8 @@ build:review:
build:production:en:
stage: build
before_script:
- sed -ri "s|\"VERSION\"|\"$CI_PIPELINE_ID\"|" src/environments/environment.prod.ts
script:
- npm ci && npm install -g gulp-cli
- npm run postinstall
......@@ -113,6 +103,8 @@ build:production:en:
build:production:i18n:
stage: build
before_script:
- sed -ri "s|\"VERSION\"|\"$CI_PIPELINE_ID\"|" src/environments/environment.prod.ts
script:
- npm ci && npm install -g gulp-cli
- npm run postinstall
......@@ -127,13 +119,28 @@ build:production:i18n:
- master
- test/gitlab-ci
#################
# Prepare Stage #
#################
.sentry_prepare: &sentry_prepare
stage: prepare
image: getsentry/sentry-cli
script:
- echo "Create a new release $CI_PIPELINE_ID"
- sentry-cli releases new $CI_PIPELINE_ID
- sentry-cli releases set-commits --auto $CI_PIPELINE_ID
- sentry-cli releases files $CI_PIPELINE_ID upload-sourcemaps $CI_PROJECT_DIR/dist/en -x .js -x .map --validate --url-prefix $SOURCEMAP_PREFIX
- sentry-cli releases finalize $CI_PIPELINE_ID
- echo "Finalized release for $CI_PIPELINE_ID"
prepare:review:
stage: prepare
image: minds/ci:latest
script:
- docker login -u gitlab-ci-token -p ${CI_BUILD_TOKEN} ${CI_REGISTRY}
- docker build -t $CI_REGISTRY_IMAGE/front-init:$CI_BUILD_REF -f containers/front-init/Dockerfile dist/.
- docker push $CI_REGISTRY_IMAGE/front-init:$CI_BUILD_REF
- docker build -t $CI_REGISTRY_IMAGE/front-init:$CI_PIPELINE_ID -f containers/front-init/Dockerfile dist/.
- docker push $CI_REGISTRY_IMAGE/front-init:$CI_PIPELINE_ID
dependencies:
- build:review
except:
......@@ -141,13 +148,36 @@ prepare:review:
- master
- test/gitlab-ci
prepare:review:sentry:
<<: *sentry_prepare
variables:
SOURCEMAP_PREFIX: "~/en"
except:
refs:
- master
- test/gitlab-ci
dependencies:
- build:review
prepare:production:
stage: prepare
image: minds/ci:latest
script:
- docker login -u gitlab-ci-token -p ${CI_BUILD_TOKEN} ${CI_REGISTRY}
- docker build -t $CI_REGISTRY_IMAGE/front-init:$CI_BUILD_REF -f containers/front-init/Dockerfile dist/.
- docker push $CI_REGISTRY_IMAGE/front-init:$CI_BUILD_REF
- docker build -t $CI_REGISTRY_IMAGE/front-init:$CI_PIPELINE_ID -f containers/front-init/Dockerfile dist/.
- docker push $CI_REGISTRY_IMAGE/front-init:$CI_PIPELINE_ID
only:
refs:
- master
- test/gitlab-ci
dependencies:
- build:production:en
- build:production:i18n
prepare:production:sentry:
<<: *sentry_prepare
variables:
SOURCEMAP_PREFIX: "~/front/dist/en"
only:
refs:
- master
......@@ -155,6 +185,26 @@ prepare:production:
dependencies:
- build:production:en
- build:production:i18n
################
# Review Stage #
################
.cleanup_review: &cleanup_review
image: minds/helm-eks:latest
script:
- aws eks update-kubeconfig --name=sandbox
- helm del --purge $CI_BUILD_REF_SLUG
environment:
name: review/$CI_COMMIT_REF_NAME
url: https://$CI_BUILD_REF_SLUG.$KUBE_INGRESS_BASE_DOMAIN
action: stop
variables:
GIT_STRATEGY: none
except:
refs:
- master
- test/gitlab-ci
review:start:
stage: review
......@@ -166,12 +216,14 @@ review:start:
--install \
--reuse-values \
--set frontInit.image.repository=$CI_REGISTRY_IMAGE/front-init \
--set frontInit.image.tag=$CI_BUILD_REF \
--set-string frontInit.image.tag=$CI_PIPELINE_ID \
--set domain=$CI_BUILD_REF_SLUG.$KUBE_INGRESS_BASE_DOMAIN \
--set elasticsearch.clusterName=$CI_BUILD_REF_SLUG--elasticsearch \
--wait \
$CI_BUILD_REF_SLUG \
./helm-charts/minds"
# Update sentry
- sentry-cli releases deploys $CI_PIPELINE_ID new -e review-$CI_COMMIT_REF_SLUG
environment:
name: review/$CI_COMMIT_REF_NAME
url: https://$CI_BUILD_REF_SLUG.$KUBE_INGRESS_BASE_DOMAIN
......@@ -182,71 +234,53 @@ review:start:
- test/gitlab-ci
review:stop:
<<: *cleanup_review
stage: review
image: minds/helm-eks:latest
script:
- aws eks update-kubeconfig --name=sandbox
- helm del --purge $CI_BUILD_REF_SLUG
environment:
name: review/$CI_COMMIT_REF_NAME
url: https://$CI_BUILD_REF_SLUG.$KUBE_INGRESS_BASE_DOMAIN
action: stop
variables:
GIT_STRATEGY: none
when: manual
except:
refs:
- master
- test/gitlab-ci
staging:fpm:
stage: deploy:staging
################
# Deploy Stage #
################
.deploy: &deploy
image: minds/ci:latest
script:
- IMAGE_LABEL="staging"
## Sync assets with CDN
- aws s3 sync dist $S3_REPOSITORY_URL
- $(aws ecr get-login --no-include-email --region us-east-1)
## Update docker front-init container
- docker login -u gitlab-ci-token -p ${CI_BUILD_TOKEN} ${CI_REGISTRY}
- docker pull $CI_REGISTRY_IMAGE/front-init:$CI_BUILD_REF
- docker tag $CI_REGISTRY_IMAGE/front-init:$CI_BUILD_REF $ECR_REPOSITORY_URL:$IMAGE_LABEL
- docker pull $CI_REGISTRY_IMAGE/front-init:$CI_PIPELINE_ID
- docker tag $CI_REGISTRY_IMAGE/front-init:$CI_PIPELINE_ID $ECR_REPOSITORY_URL:$IMAGE_LABEL
- docker push $ECR_REPOSITORY_URL:$IMAGE_LABEL
## Deploy the new container in rolling restart
- aws ecs update-service --service=$ECS_APP_STAGING_SERVICE --force-new-deployment --region us-east-1 --cluster=$ECS_CLUSTER
- aws ecs update-service --service=$ECS_SERVICE --force-new-deployment --region us-east-1 --cluster=$ECS_CLUSTER
## Update sentry
- sentry-cli releases deploys $CI_PIPELINE_ID new -e $IMAGE_LABEL
dependencies:
- build:production:en
- build:production:i18n
only:
refs:
- master
- test/gitlab-ci
dependencies:
- build:production:en
- build:production:i18n
staging:fpm:
<<: *deploy
stage: deploy:staging
variables:
IMAGE_LABEL: "staging"
ECS_SERVICE: $ECS_APP_STAGING_SERVICE
environment:
name: staging
url: https://www.minds.com # requires staging cookie
deploy:canary:
<<: *deploy
stage: deploy:canary
image: minds/ci:latest
script:
- IMAGE_LABEL="canary"
## Sync assets with CDN
- aws s3 sync dist $S3_REPOSITORY_URL
- $(aws ecr get-login --no-include-email --region us-east-1)
## Update docker front-init container
- docker login -u gitlab-ci-token -p ${CI_BUILD_TOKEN} ${CI_REGISTRY}
- docker pull $CI_REGISTRY_IMAGE/front-init:$CI_BUILD_REF
- docker tag $CI_REGISTRY_IMAGE/front-init:$CI_BUILD_REF $ECR_REPOSITORY_URL:$IMAGE_LABEL
- docker push $ECR_REPOSITORY_URL:$IMAGE_LABEL
## Deploy the new container in rolling restart
- aws ecs update-service --service=$ECS_APP_CANARY_SERVICE --force-new-deployment --region us-east-1 --cluster=$ECS_CLUSTER
only:
refs:
- master
- test/gitlab-ci
dependencies:
- build:production:en
- build:production:i18n
variables:
IMAGE_LABEL: "canary"
ECS_SERVICE: $ECS_APP_CANARY_SERVICE
environment:
name: canary
url: https://www.minds.com/?canary=1 # requires canary cookie
......@@ -254,27 +288,25 @@ deploy:canary:
allow_failure: false # prevents auto deploy to full production
deploy:production:
<<: *deploy
stage: deploy:production
image: minds/ci:latest
script:
- IMAGE_LABEL="production"
- $(aws ecr get-login --no-include-email --region us-east-1)
## Update docker front-init container
- docker login -u gitlab-ci-token -p ${CI_BUILD_TOKEN} ${CI_REGISTRY}
- docker pull $CI_REGISTRY_IMAGE/front-init:$CI_BUILD_REF
- docker tag $CI_REGISTRY_IMAGE/front-init:$CI_BUILD_REF $ECR_REPOSITORY_URL:$IMAGE_LABEL
- docker push $ECR_REPOSITORY_URL:$IMAGE_LABEL
## Deploy the new container in rolling restart
- aws ecs update-service --service=$ECS_APP_PRODUCTION_SERVICE --force-new-deployment --region us-east-1 --cluster=$ECS_CLUSTER
only:
refs:
- master
- test/gitlab-ci
dependencies:
- build:production:en
- build:production:i18n
variables:
IMAGE_LABEL: "production"
ECS_SERVICE: $ECS_APP_PRODUCTION_SERVICE
environment:
name: production
url: https://www.minds.com
when: delayed
start_in: 2 hours # reduce? can always be deployed manually earlier too
start_in: 12 hours # reduce? can always be deployed manually earlier too
#################
# Cleanup stage #
#################
cleanup:review: # We stop the review site after the e2e tests have run
<<: *cleanup_review
stage: cleanup
except:
refs:
- master
- test/gitlab-ci
# .prettierrc
# Use this file to define your defaults for prettier
# For a list of all available options:
# https://prettier.io/docs/en/options.html
trailingComma: 'es5'
printWidth: 80
singleQuote: true
semi: true
......@@ -28,7 +28,6 @@
"scripts": [
"node_modules/material-design-lite/dist/material.min.js",
"node_modules/medium-editor/dist/js/medium-editor.min.js",
"src/shims/fontawesome.js",
"src/shims/jitsi-api.min.js"
]
},
......@@ -36,7 +35,11 @@
"production": {
"optimization": true,
"outputHashing": "all",
"sourceMap": false,
"sourceMap": {
"hidden": true,
"scripts": true,
"styles": true
},
"extractCss": true,
"namedChunks": false,
"aot": true,
......@@ -78,7 +81,6 @@
"scripts": [
"node_modules/material-design-lite/dist/material.min.js",
"node_modules/medium-editor/dist/js/medium-editor.min.js",
"src/shims/fontawesome.js",
"src/shims/jitsi-api.min.js"
],
"assets": [
......
#!/bin/sh
export NODE_OPTIONS="--max-old-space-size=3584"
ng build --prod --vendor-chunk --output-path="$1/en/" --deploy-url="$2/en/" --build-optimizer=false --source-map=false
ng build --prod --vendor-chunk --output-path="$1/en/" --deploy-url="$2/en/" --build-optimizer=false
......@@ -1866,6 +1866,63 @@
}
}
},
"@sentry/browser": {
"version": "5.6.2",
"resolved": "https://registry.npmjs.org/@sentry/browser/-/browser-5.6.2.tgz",
"integrity": "sha512-Nm/W/5ra6+OQCWQkdd86vHjcYUjHCVqCzQyPasd6HE7SNlWe5euGVfFfDuUFsiDrMAG5uKfGYw5u/AqoweiQkQ==",
"requires": {
"@sentry/core": "5.6.2",
"@sentry/types": "5.6.1",
"@sentry/utils": "5.6.1",
"tslib": "^1.9.3"
}
},
"@sentry/core": {
"version": "5.6.2",
"resolved": "https://registry.npmjs.org/@sentry/core/-/core-5.6.2.tgz",
"integrity": "sha512-grbjvNmyxP5WSPR6UobN2q+Nss7Hvz+BClBT8QTr7VTEG5q89TwNddn6Ej3bGkaUVbct/GpVlI3XflWYDsnU6Q==",
"requires": {
"@sentry/hub": "5.6.1",
"@sentry/minimal": "5.6.1",
"@sentry/types": "5.6.1",
"@sentry/utils": "5.6.1",
"tslib": "^1.9.3"
}
},
"@sentry/hub": {
"version": "5.6.1",
"resolved": "https://registry.npmjs.org/@sentry/hub/-/hub-5.6.1.tgz",
"integrity": "sha512-m+OhkIV5yTAL3R1+XfCwzUQka0UF/xG4py8sEfPXyYIcoOJ2ZTX+1kQJLy8QQJ4RzOBwZA+DzRKP0cgzPJ3+oQ==",
"requires": {
"@sentry/types": "5.6.1",
"@sentry/utils": "5.6.1",
"tslib": "^1.9.3"
}
},
"@sentry/minimal": {
"version": "5.6.1",
"resolved": "https://registry.npmjs.org/@sentry/minimal/-/minimal-5.6.1.tgz",
"integrity": "sha512-ercCKuBWHog6aS6SsJRuKhJwNdJ2oRQVWT2UAx1zqvsbHT9mSa8ZRjdPHYOtqY3DoXKk/pLUFW/fkmAnpdMqRw==",
"requires": {
"@sentry/hub": "5.6.1",
"@sentry/types": "5.6.1",
"tslib": "^1.9.3"
}
},
"@sentry/types": {
"version": "5.6.1",
"resolved": "https://registry.npmjs.org/@sentry/types/-/types-5.6.1.tgz",
"integrity": "sha512-Kub8TETefHpdhvtnDj3kKfhCj0u/xn3Zi2zIC7PB11NJHvvPXENx97tciz4roJGp7cLRCJsFqCg4tHXniqDSnQ=="
},
"@sentry/utils": {
"version": "5.6.1",
"resolved": "https://registry.npmjs.org/@sentry/utils/-/utils-5.6.1.tgz",
"integrity": "sha512-rfgha+UsHW816GqlSRPlniKqAZylOmQWML2JsujoUP03nPu80zdN43DK9Poy/d9OxBxv0gd5K2n+bFdM2kqLQQ==",
"requires": {
"@sentry/types": "5.6.1",
"tslib": "^1.9.3"
}
},
"@types/jasmine": {
"version": "2.8.14",
"resolved": "https://registry.npmjs.org/@types/jasmine/-/jasmine-2.8.14.tgz",
......@@ -2756,7 +2813,7 @@
"async-limiter": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/async-limiter/-/async-limiter-1.0.0.tgz",
"integrity": "sha1-ePrtjD0HSrgfIrTphdeehzj3IPg="
"integrity": "sha512-jp/uFnooOiO+L211eZOoSyzpOITMXx1rBITauYykG3BRYPu8h0UcxsPNB04RR5vo4Tyz3+ay17tR6JVf9qzYWg=="
},
"async-settle": {
"version": "1.0.0",
......@@ -3104,7 +3161,7 @@
"bencode": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/bencode/-/bencode-2.0.0.tgz",
"integrity": "sha1-5y5rNpHYJL0D6nqp11LNHUmlACc=",
"integrity": "sha512-wr2HwwrUpfB5c68zmAudOltC7rZ1G0+lQOcnuEcfIM3AWAVnB3rHI3nlgd/2CWTfQ3w3zagKt89zni/M+VLZ8g==",
"requires": {
"safe-buffer": "^5.1.1"
}
......@@ -11188,7 +11245,7 @@
"source-map": {
"version": "0.6.1",
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
"integrity": "sha1-dHIq8y6WFOnCh6jQu95IteLxomM=",
"integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
"dev": true
},
"useragent": {
......@@ -11872,7 +11929,7 @@
"lodash.mergewith": {
"version": "4.6.1",
"resolved": "https://registry.npmjs.org/lodash.mergewith/-/lodash.mergewith-4.6.1.tgz",
"integrity": "sha1-Y5BX5ybDr72z59QnQcqo1uQzWSc=",
"integrity": "sha512-eWw5r+PYICtEBgrBE5hhlT6aAa75f411bgDz/ZL2KZqYV03USvucsxcHUIlGTDTECs1eunpI7HOV7U+WLDvNdQ==",
"dev": true
},
"lodash.once": {
......@@ -12531,7 +12588,7 @@
"mimic-fn": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-1.2.0.tgz",
"integrity": "sha1-ggyGo5M0ZA6ZUWkovQP8qIBX0CI=",
"integrity": "sha512-jf84uxzwiuiIVKiOLpfYk7N46TSy8ubTonmneY9vrpHNAnp0QBt2BxWV9dO3/j+BoVAb+a5G6YDPW3M5HOdMWQ==",
"dev": true
},
"mimic-response": {
......@@ -12636,7 +12693,7 @@
"mixin-deep": {
"version": "1.3.1",
"resolved": "https://registry.npmjs.org/mixin-deep/-/mixin-deep-1.3.1.tgz",
"integrity": "sha1-pJ5yaNzhoNlpjkUybFYm3zVD0P4=",
"integrity": "sha512-8ZItLHeEgaqEvd5lYBXfm4EZSFCX29Jb9K+lAHhDKzReKBQKj3R+7NOF6tjqYi9t4oI8VUfaWITJQm86wnXGNQ==",
"dev": true,
"requires": {
"for-in": "^1.0.2",
......@@ -12646,7 +12703,7 @@
"is-extendable": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz",
"integrity": "sha1-p0cPnkJnM9gb2B4RVSZOOjUHyrQ=",
"integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==",
"dev": true,
"requires": {
"is-plain-object": "^2.0.4"
......@@ -12762,7 +12819,7 @@
"mp4-stream": {
"version": "2.0.3",
"resolved": "https://registry.npmjs.org/mp4-stream/-/mp4-stream-2.0.3.tgz",
"integrity": "sha1-MKzuB3CdMj+NzYegezzpw8S/s2Q=",
"integrity": "sha512-5NzgI0+bGakoZEwnIYINXqB3mnewkt3Y7jcvkXsTubnCNUSdM8cpP0Vemxf6FLg0qUN8fydTgNMVAc3QU8B92g==",
"requires": {
"buffer-alloc": "^1.1.0",
"inherits": "^2.0.1",
......@@ -13274,7 +13331,7 @@
"normalize-package-data": {
"version": "2.4.0",
"resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.4.0.tgz",
"integrity": "sha1-EvlaMH1YNSB1oEkHuErIvpisAS8=",
"integrity": "sha512-9jjUFbTPfEy3R/ad/2oNbKtW9Hgovl5O1FvFWKkKblNXoN/Oou6+9+KKohPK13Yc3/TyunyWhJp6gvRNR/PPAw==",
"dev": true,
"requires": {
"hosted-git-info": "^2.1.4",
......@@ -14601,6 +14658,12 @@
"resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz",
"integrity": "sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ="
},
"prettier": {
"version": "1.18.2",
"resolved": "https://registry.npmjs.org/prettier/-/prettier-1.18.2.tgz",
"integrity": "sha512-OeHeMc0JhFE9idD4ZdtNibzY0+TPHSpSSb9h8FqtP+YnoZZ1sl8Vc9b1sasjfymH3SonAF4QcA2+mzHPhMvIiw==",
"dev": true
},
"pretty-hrtime": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/pretty-hrtime/-/pretty-hrtime-1.0.3.tgz",
......@@ -15028,7 +15091,7 @@
"random-access-file": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/random-access-file/-/random-access-file-2.0.1.tgz",
"integrity": "sha1-3CLeeScOmoTLNqJBm3WXJZMNyus=",
"integrity": "sha512-nb4fClpzoUY+v1SHrro+9yykN90eMA1rc+xM39tnZ5R3BgFY+J/NxPZ0KuUpishEsvnwou9Fvm2wa3cjeuG7vg==",
"requires": {
"mkdirp": "^0.5.1",
"random-access-storage": "^1.1.1"
......@@ -16193,7 +16256,7 @@
"set-value": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/set-value/-/set-value-2.0.0.tgz",
"integrity": "sha1-ca5KiPD+77v1LR6mBPP7MV67YnQ=",
"integrity": "sha512-hw0yxk9GT/Hr5yJEYnHNKYXkIA8mVJgd9ditYZCe16ZczcaELYYcfvaXesNACk2O8O0nTiPQcQhGUQj8JLzeeg==",
"dev": true,
"requires": {
"extend-shallow": "^2.0.1",
......@@ -18452,7 +18515,7 @@
"type-is": {
"version": "1.6.16",
"resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.16.tgz",
"integrity": "sha1-+JzjQVQcZysl7nrjxz3uOyvlAZQ=",
"integrity": "sha512-HRkVv/5qY2G6I8iab9cI7v1bOIdhm94dVjQCPFElW9W+3GeDOSHmy2EBYe4VTApuzolPcmgFTN3ftVJRKR2J9Q==",
"dev": true,
"requires": {
"media-typer": "0.3.0",
......
import { trigger, style, animate, transition, keyframes } from '@angular/animations';
import {
trigger,
style,
animate,
transition,
keyframes,
} from '@angular/animations';
export const animations: any[] = [
trigger('foolishIn', [
transition('* => *', [
style({ opacity: 0 }),
animate(2000, keyframes([
style({ opacity: 0, transformOrigin: '50% 50%', transform: 'scale(0, 0) rotate(360deg)', offset: 0.000 }),
style({ opacity: 1, transformOrigin: '0% 100%', transform: 'scale(0.5, 0.5) rotate(0deg)', offset: 0.066 }),
style({ opacity: 1, transformOrigin: '100% 100%', transform: 'scale(0.5, 0.5) rotate(0deg)', offset: 0.132 }),
style({ opacity: 1, transformOrigin: '0%', transform: 'scale(0.5, 0.5) rotate(0deg)', offset: 0.198 }),
style({ opacity: 1, transformOrigin: '0% 0%', transform: 'scale(0.5, 0.5) rotate(0deg)', offset: 0.264 }),
style({ opacity: 1, transformOrigin: '50% 50%', transform: 'scale(1, 1) rotate(0deg)', offset: 0.330 }),
style({ opacity: 1, offset: 0.660 }),
style({ opacity: 0, offset: 1.000 }),
]))
])
])
animate(
2000,
keyframes([
style({
opacity: 0,
transformOrigin: '50% 50%',
transform: 'scale(0, 0) rotate(360deg)',
offset: 0.0,
}),
style({
opacity: 1,
transformOrigin: '0% 100%',
transform: 'scale(0.5, 0.5) rotate(0deg)',
offset: 0.066,
}),
style({
opacity: 1,
transformOrigin: '100% 100%',
transform: 'scale(0.5, 0.5) rotate(0deg)',
offset: 0.132,
}),
style({
opacity: 1,
transformOrigin: '0%',
transform: 'scale(0.5, 0.5) rotate(0deg)',
offset: 0.198,
}),
style({
opacity: 1,
transformOrigin: '0% 0%',
transform: 'scale(0.5, 0.5) rotate(0deg)',
offset: 0.264,
}),
style({
opacity: 1,
transformOrigin: '50% 50%',
transform: 'scale(1, 1) rotate(0deg)',
offset: 0.33,
}),
style({ opacity: 1, offset: 0.66 }),
style({ opacity: 0, offset: 1.0 }),
])
),
]),
]),
];
......@@ -4,7 +4,9 @@
</ng-container>
<ng-container icons>
<m-notifications--topbar-toggle *ngIf="session.isLoggedIn()"></m-notifications--topbar-toggle>
<m-notifications--topbar-toggle
*ngIf="session.isLoggedIn()"
></m-notifications--topbar-toggle>
</ng-container>
</m-v2-topbar>
<ng-template #legacyTopbar>
......@@ -20,15 +22,18 @@
</m-topbar>
</ng-template>
<m-sidebar--markers [class.has-v2-navbar]="featuresService.has('top-feeds')"></m-sidebar--markers>
<m-sidebar--markers
[class.has-v2-navbar]="featuresService.has('top-feeds')"
></m-sidebar--markers>
<m-body [class.has-v2-navbar]="featuresService.has('top-feeds')">
<m-announcement [id]="'blockchain:sale'" *ngIf="false">
<span class="m-blockchain--wallet-address-notice--action"
<span
class="m-blockchain--wallet-address-notice--action"
routerLink="/tokens"
i18n="@@BLOCKCHAIN__SALE__NOTICE"
>
The MINDS token is now live. Learn more here.
The MINDS token is now live. Learn more here.
</span>
</m-announcement>
<m-blockchain--wallet-address-notice></m-blockchain--wallet-address-notice>
......@@ -42,11 +47,12 @@
<m-overlay-modal></m-overlay-modal>
<m--blockchain--transaction-overlay></m--blockchain--transaction-overlay>
<m-modal--tos-updated *ngIf="session.isLoggedIn()"></m-modal--tos-updated>
<m-juryDutySession__summons *ngIf="session.isLoggedIn()"></m-juryDutySession__summons>
<m-juryDutySession__summons
*ngIf="session.isLoggedIn()"
></m-juryDutySession__summons>
<m-modal-signup-on-scroll></m-modal-signup-on-scroll>
<m-channel--onboarding *ngIf="showOnboarding"></m-channel--onboarding>
<m-cookies-notice *ngIf="!session.isLoggedIn()">
</m-cookies-notice>
<m-cookies-notice *ngIf="!session.isLoggedIn()"> </m-cookies-notice>
@import "defaults";
@import "themes";
@import 'defaults';
@import 'themes';
html, body {
html,
body {
font-family: 'Roboto', Helvetica, sans-serif !important;
}
m-app {
//width: 100%;
//min-width: $min-mobile;
//height: 100%;
......@@ -15,8 +15,8 @@ m-app {
//overflow: visible;
//position: relative;
.initial-loading{
width:100%;
.initial-loading {
width: 100%;
}
.m-initial-loading-centred {
......@@ -24,20 +24,20 @@ m-app {
}
m-body {
@include m-theme(){
@include m-theme() {
background-color: themed($m-body-bg);
}
// display: inline-block;
// overflow:visible;
// flex-grow: 1;
// z-index: 1;
// margin-top: $layout-header-height;
// margin-left: $layout-sidebar-width;
// width: 100%;
//
// @media screen and (max-width: $min-tablet){
// margin-left:0;
// }
// display: inline-block;
// overflow:visible;
// flex-grow: 1;
// z-index: 1;
// margin-top: $layout-header-height;
// margin-left: $layout-sidebar-width;
// width: 100%;
//
// @media screen and (max-width: $min-tablet){
// margin-left:0;
// }
}
p {
......@@ -51,12 +51,11 @@ m-app {
font-size: 20px;
line-height: 20px;
overflow: visible;
@include m-theme(){
@include m-theme() {
color: rgba(themed($m-black), 0.75);
}
}
.mdl-card__supporting-text{
.mdl-card__supporting-text {
font-family: 'Roboto', Helvetica, sans-serif;
}
}
......@@ -68,10 +67,12 @@ m-app {
flex-direction: column;
width: 100%;
height: 100%;
.m-page--main, .m-page__main {
.m-page--main,
.m-page__main {
overflow: visible !important;
}
.m-page--sidebar, .m-page__sidebar {
.m-page--sidebar,
.m-page__sidebar {
width: initial !important;
min-width: 300px;
padding: 16px !important;
......@@ -84,13 +85,15 @@ m-app {
margin: auto;
}
.m-page--main, .m-page__main {
.m-page--main,
.m-page__main {
padding: 16px;
flex: 1;
overflow: auto;
}
.m-page--sidebar, .m-page__sidebar {
.m-page--sidebar,
.m-page__sidebar {
padding: 16px 0 16px 16px;
width: 300px;
}
......@@ -106,18 +109,19 @@ m-app {
text-decoration: none;
font-size: 13px;
@include m-theme(){
@include m-theme() {
background-color: themed($m-white);
border: 1px solid themed($m-grey-50);
}
&.m-page--sidebar--navigation--item-active {
@include m-theme(){
@include m-theme() {
color: themed($m-blue);
}
}
i, span {
i,
span {
vertical-align: middle;
}
......@@ -127,7 +131,7 @@ m-app {
}
}
.m-loader {
width: 100% ;
width: 100%;
padding: 16px;
text-align: center;
}
......@@ -11,11 +11,11 @@ import { BlockchainService } from './modules/blockchain/blockchain.service';
import { Web3WalletService } from './modules/blockchain/web3-wallet.service';
import { Client } from './services/api/client';
import { WebtorrentService } from './modules/webtorrent/webtorrent.service';
import { ActivatedRoute, Router } from "@angular/router";
import { ChannelOnboardingService } from "./modules/onboarding/channel/onboarding.service";
import { BlockListService } from "./common/services/block-list.service";
import { FeaturesService } from "./services/features.service";
import { ThemeService } from "./common/services/theme.service";
import { ActivatedRoute, Router } from '@angular/router';
import { ChannelOnboardingService } from './modules/onboarding/channel/onboarding.service';
import { BlockListService } from './common/services/block-list.service';
import { FeaturesService } from './services/features.service';
import { ThemeService } from './common/services/theme.service';
import { BannedService } from './modules/report/banned/banned.service';
@Component({
......@@ -50,7 +50,7 @@ export class Minds {
public blockListService: BlockListService,
public featuresService: FeaturesService,
public themeService: ThemeService,
private bannedService: BannedService,
private bannedService: BannedService
) {
this.name = 'Minds';
}
......@@ -58,11 +58,15 @@ export class Minds {
async ngOnInit() {
this.notificationService.getNotifications();
this.session.isLoggedIn(async (is) => {
this.session.isLoggedIn(async is => {
if (is) {
this.showOnboarding = await this.onboardingService.showModal();
if (this.minds.user.language !== this.minds.language) {
console.log('[app]:: language change', this.minds.user.language, this.minds.language);
console.log(
'[app]:: language change',
this.minds.user.language,
this.minds.language
);
window.location.reload(true);
}
}
......@@ -93,7 +97,7 @@ export class Minds {
this.web3Wallet.setUp();
this.webtorrent.setUp();
this.themeService.setUp();
}
......
import { CUSTOM_ELEMENTS_SCHEMA, NgModule } from '@angular/core';
import {
CUSTOM_ELEMENTS_SCHEMA,
NgModule,
Injectable,
ErrorHandler,
} from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
import { RouterModule } from '@angular/router';
import { CaptchaModule } from './modules/captcha/captcha.module';
import { environment } from '../environments/environment';
import { Minds } from './app.component';
import { MINDS_APP_ROUTING_DECLARATIONS, MindsAppRoutes, MindsAppRoutingProviders } from './router/app';
import {
MINDS_APP_ROUTING_DECLARATIONS,
MindsAppRoutes,
MindsAppRoutingProviders,
} from './router/app';
import { MINDS_DECLARATIONS } from './declarations';
import { MINDS_PLUGIN_DECLARATIONS } from './plugin-declarations';
......@@ -56,13 +66,28 @@ import { HelpdeskModule } from './modules/helpdesk/helpdesk.module';
import { MobileModule } from './modules/mobile/mobile.module';
import { IssuesModule } from './modules/issues/issues.module';
import { CanaryModule } from './modules/canary/canary.module';
import { HttpClientModule } from "@angular/common/http";
import { AnalyticsModule } from "./modules/analytics/analytics.module";
import { HttpClientModule } from '@angular/common/http';
import { AnalyticsModule } from './modules/analytics/analytics.module';
import * as Sentry from '@sentry/browser';
Sentry.init({
dsn: 'https://3f786f8407e042db9053434a3ab527a2@sentry.io/1538008', // TODO: do not hardcard
release: environment.version,
environment: (<any>window.Minds).environment || 'development',
});
@Injectable()
export class SentryErrorHandler implements ErrorHandler {
constructor() {}
handleError(error) {
// const eventId = Sentry.captureException(error.originalError || error);
// Sentry.showReportDialog({ eventId });
}
}
@NgModule({
bootstrap: [
Minds
],
bootstrap: [Minds],
declarations: [
Minds,
MINDS_APP_ROUTING_DECLARATIONS,
......@@ -75,7 +100,7 @@ import { AnalyticsModule } from "./modules/analytics/analytics.module";
ReactiveFormsModule,
FormsModule,
HttpClientModule,
RouterModule.forRoot(MindsAppRoutes, { onSameUrlNavigation: "reload" }),
RouterModule.forRoot(MindsAppRoutes, { onSameUrlNavigation: 'reload' }),
CaptchaModule,
CommonModule,
AnalyticsModule,
......@@ -122,13 +147,11 @@ import { AnalyticsModule } from "./modules/analytics/analytics.module";
ChannelsModule,
],
providers: [
{ provide: ErrorHandler, useClass: SentryErrorHandler },
MindsAppRoutingProviders,
MINDS_PROVIDERS,
MINDS_PLUGIN_PROVIDERS,
],
schemas: [
CUSTOM_ELEMENTS_SCHEMA
]
schemas: [CUSTOM_ELEMENTS_SCHEMA],
})
export class MindsModule {
}
export class MindsModule {}
import { Cookie } from '../../services/cookie';
import { HttpClient, HttpHeaders } from "@angular/common/http";
import { HttpClient, HttpHeaders } from '@angular/common/http';
/**
* API Class
*/
export class MindsHttpClient {
base: string = '/';
cookie: Cookie = new Cookie();
......@@ -13,18 +12,14 @@ export class MindsHttpClient {
return new MindsHttpClient(http);
}
constructor(public http: HttpClient) {
}
constructor(public http: HttpClient) {}
/**
* Return a GET request
*/
get(endpoint: string, data: Object = {}, options: Object = {}) {
endpoint += '?' + this.buildParams(data);
return this.http.get(
this.base + endpoint,
this.buildOptions(options)
);
return this.http.get(this.base + endpoint, this.buildOptions(options));
// .map(response => response.json());
}
......@@ -54,23 +49,22 @@ export class MindsHttpClient {
* Return a DELETE request
*/
delete(endpoint: string, data: Object = {}, options: Object = {}) {
return this.http.delete(
this.base + endpoint,
this.buildOptions(options)
);
return this.http.delete(this.base + endpoint, this.buildOptions(options));
}
private buildParams(object: Object) {
return Object.keys(object).map((k) => {
return encodeURIComponent(k) + '=' + encodeURIComponent(object[k]);
}).join('&');
return Object.keys(object)
.map(k => {
return encodeURIComponent(k) + '=' + encodeURIComponent(object[k]);
})
.join('&');
}
/**
* Build the options
*/
private buildOptions(options: Object) {
const XSRF_TOKEN = this.cookie.get('XSRF-TOKEN');
const XSRF_TOKEN = this.cookie.get('XSRF-TOKEN') || '';
const headers = new HttpHeaders({
'X-XSRF-TOKEN': XSRF_TOKEN,
......@@ -78,11 +72,9 @@ export class MindsHttpClient {
return Object.assign(options, {
headers: headers,
cache: true
cache: true,
});
}
}
export { Client } from '../../services/api/client';
......@@ -56,7 +56,7 @@ import { ChartComponent } from './components/chart/chart.component';
import { DateSelectorComponent } from './components/date-selector/date-selector.component';
import { AdminActionsButtonComponent } from './components/button/admin-actions/admin-actions.component';
import { InlineEditorComponent } from './components/editors/inline-editor.component';
import { AttachmentService } from "../services/attachment";
import { AttachmentService } from '../services/attachment';
import { MaterialBoundSwitchComponent } from './components/material/bound-switch.component';
import { IfFeatureDirective } from './directives/if-feature.directive';
import { MindsEmoji } from './components/emoji/emoji';
......@@ -81,35 +81,30 @@ import { PieGraph } from './components/graphs/pie-graph';
import { GraphSVG } from './components/graphs/svg';
import { GraphPoints } from './components/graphs/points';
import { DynamicFormComponent } from './components/forms/dynamic-form/dynamic-form.component';
import { SortSelectorComponent } from "./components/sort-selector/sort-selector.component";
import { SortSelectorComponent } from './components/sort-selector/sort-selector.component';
import { UpdateMarkersService } from './services/update-markers.service';
import { SocketsService } from '../services/sockets';
import { Storage } from '../services/storage';
import { HttpClient } from "@angular/common/http";
import { AndroidAppDownloadComponent } from "./components/android-app-download-button/button.component";
import { SwitchComponent } from "./components/switch/switch.component";
import { V2TopbarComponent } from "./layout/v2-topbar/v2-topbar.component";
import { UserMenuComponent } from "./layout/v2-topbar/user-menu.component";
import { FeaturedContentComponent } from "./components/featured-content/featured-content.component";
import { FeaturedContentService } from "./components/featured-content/featured-content.service";
import { BoostedContentService } from "./services/boosted-content.service";
import { HttpClient } from '@angular/common/http';
import { AndroidAppDownloadComponent } from './components/android-app-download-button/button.component';
import { SwitchComponent } from './components/switch/switch.component';
import { V2TopbarComponent } from './layout/v2-topbar/v2-topbar.component';
import { UserMenuComponent } from './layout/v2-topbar/user-menu.component';
import { FeaturedContentComponent } from './components/featured-content/featured-content.component';
import { FeaturedContentService } from './components/featured-content/featured-content.service';
import { BoostedContentService } from './services/boosted-content.service';
import { FeedsService } from './services/feeds.service';
import { EntitiesService } from "./services/entities.service";
import { BlockListService } from "./services/block-list.service";
import { SettingsService } from "../modules/settings/settings.service";
import { ThemeService } from "./services/theme.service";
import { HorizontalInfiniteScroll } from "./components/infinite-scroll/horizontal-infinite-scroll.component";
import { EntitiesService } from './services/entities.service';
import { BlockListService } from './services/block-list.service';
import { SettingsService } from '../modules/settings/settings.service';
import { ThemeService } from './services/theme.service';
import { HorizontalInfiniteScroll } from './components/infinite-scroll/horizontal-infinite-scroll.component';
import { ReferralsLinksComponent } from '../modules/wallet/tokens/referrals/links/links.component';
import { ShareModalComponent } from '../modules/modals/share/share';
@NgModule({
imports: [
NgCommonModule,
RouterModule,
FormsModule,
ReactiveFormsModule,
],
imports: [NgCommonModule, RouterModule, FormsModule, ReactiveFormsModule],
declarations: [
MINDS_PIPES,
......@@ -283,44 +278,65 @@ import { ShareModalComponent } from '../modules/modals/share/share';
{
provide: AttachmentService,
useFactory: AttachmentService._,
deps: [Session, Client, Upload, HttpClient ]
deps: [Session, Client, Upload, HttpClient],
},
{
provide: UpdateMarkersService,
useFactory: (_http, _session, _sockets) => { return new UpdateMarkersService(_http, _session, _sockets); },
deps: [ MindsHttpClient, Session, SocketsService ],
useFactory: (_http, _session, _sockets) => {
return new UpdateMarkersService(_http, _session, _sockets);
},
deps: [MindsHttpClient, Session, SocketsService],
},
{
provide: MindsHttpClient,
useFactory: MindsHttpClient._,
deps: [HttpClient]
deps: [HttpClient],
},
{
provide: NSFWSelectorCreatorService,
useFactory: (_storage) => new NSFWSelectorCreatorService(_storage),
deps: [ Storage ],
useFactory: _storage => new NSFWSelectorCreatorService(_storage),
deps: [Storage],
},
{
provide: NSFWSelectorConsumerService,
useFactory: (_storage) => new NSFWSelectorConsumerService(_storage),
deps: [ Storage ],
useFactory: _storage => new NSFWSelectorConsumerService(_storage),
deps: [Storage],
},
{
provide: BoostedContentService,
useFactory: (client, session, entitiesService, blockListService, settingsService) => new BoostedContentService(client, session, entitiesService, blockListService, settingsService),
deps: [ Client, Session, EntitiesService, BlockListService, SettingsService ]
useFactory: (
client,
session,
entitiesService,
blockListService,
settingsService
) =>
new BoostedContentService(
client,
session,
entitiesService,
blockListService,
settingsService
),
deps: [
Client,
Session,
EntitiesService,
BlockListService,
SettingsService,
],
},
{
provide: FeaturedContentService,
useFactory: boostedContentService => new FeaturedContentService(boostedContentService),
deps: [ FeedsService ],
}
useFactory: boostedContentService =>
new FeaturedContentService(boostedContentService),
deps: [FeedsService],
},
],
entryComponents: [
NotificationsToasterComponent,
ReferralsLinksComponent,
ShareModalComponent,
]
],
})
export class CommonModule {}
......@@ -9,24 +9,24 @@ import { Client } from '../../../services/api';
<minds-graph-line [data]="data"></minds-graph-line>
<div class="graph-labels">
<div class="graph-label mdl-color-text--blue-grey-300" *ngFor="let point of data">
{{point.total}}
<b>{{point.timestamp * 1000 | date: 'MMMd'}}</b>
<div
class="graph-label mdl-color-text--blue-grey-300"
*ngFor="let point of data"
>
{{ point.total }}
<b>{{ point.timestamp * 1000 | date: 'MMMd' }}</b>
</div>
</div>
`,
})
export class AnalyticsImpressions {
key;
span: number = 5;
unit: string = 'day';
data: Array<any> = [];
constructor(public client: Client) {
}
constructor(public client: Client) {}
set _key(value: any) {
this.key = value;
......@@ -35,13 +35,13 @@ export class AnalyticsImpressions {
get() {
var self = this;
this.client.get('api/v1/analytics/' + this.key, {
span: this.span,
unit: this.unit
})
this.client
.get('api/v1/analytics/' + this.key, {
span: this.span,
unit: this.unit,
})
.then((response: any) => {
self.data = response.data;
});
}
}
.m-androidApp__download {
box-sizing: border-box;
border-radius: 8px;
@include m-theme(){
@include m-theme() {
border: 1px solid rgba(themed($m-white-always), 0.7);
background: themed($m-black-always);
}
......@@ -33,13 +33,13 @@
text-rendering: optimizeLegibility;
-webkit-font-smoothing: antialiased;
@include m-theme(){
@include m-theme() {
color: themed($m-white-always);
}
}
i.material-icons {
@include m-theme(){
@include m-theme() {
color: themed($m-white-always);
}
}
......
import { Component } from '@angular/core';
import { Router } from "@angular/router";
import { Router } from '@angular/router';
@Component({
selector: 'm-androidApp__download',
......@@ -10,14 +10,10 @@ import { Router } from "@angular/router";
Android App
</h2>
</a>
`
`,
})
export class AndroidAppDownloadComponent {
minds = window.Minds;
constructor(private router: Router) {
}
constructor(private router: Router) {}
}
@import "defaults";
@import 'defaults';
$m-announcment-height: 50px;
m-announcement{
m-announcement {
display: block;
position: relative;
width: 100%;
min-height: $m-announcment-height;
height: $m-announcment-height;
.m-announcement{
position:fixed;
.m-announcement {
position: fixed;
width: 100%;
height: $m-announcment-height;
z-index: 9999;
display:flex;
display: flex;
flex-direction: row;
align-items:center;
align-items: center;
@include m-theme(){
@include m-theme() {
background-color: themed($m-blue);
}
@media screen and (max-width: 770px){
width: 100%;
@media screen and (max-width: 770px) {
width: 100%;
}
}
.m-announcement--content{
.m-announcement--content {
text-align: center;
letter-spacing: 1.2px;
font-weight: 300;
......@@ -38,33 +36,33 @@ m-announcement{
text-rendering: optimizeLegibility;
font-size: 16px;
flex: 1;
@include m-theme(){
@include m-theme() {
color: themed($m-white);
}
@media screen and (max-width:770px){
font-size:10px;
padding-right: 50px;
@media screen and (max-width: 770px) {
font-size: 10px;
padding-right: 50px;
}
a {
text-decoration:none;
@include m-theme(){
text-decoration: none;
@include m-theme() {
color: themed($m-white);
}
display:block;
display: block;
font-weight: 300;
}
}
.m-announcement--close{
cursor:pointer;
padding:12px;
position:absolute;
.m-announcement--close {
cursor: pointer;
padding: 12px;
position: absolute;
right: 0;
i {
@include m-theme(){
@include m-theme() {
color: themed($m-white);
}
}
......
......@@ -6,12 +6,10 @@ import { Client } from '../../../services/api';
@Component({
selector: 'm-announcement',
host: {
'[hidden]': 'hidden'
'[hidden]': 'hidden',
},
template: `
<div class="m-announcement">
<div class="m-announcement--content">
<ng-content></ng-content>
</div>
......@@ -19,28 +17,22 @@ import { Client } from '../../../services/api';
<div class="m-announcement--close" (click)="close()">
<i class="material-icons">close</i>
</div>
</div>
`
`,
})
export class AnnouncementComponent {
minds: Minds = window.Minds;
hidden: boolean = false;
@Input() id: string = 'default';
constructor(private storage: Storage) {
}
constructor(private storage: Storage) {}
ngOnInit() {
if (this.storage.get('hide-announcement:' + this.id))
this.hidden = true;
if (this.storage.get('hide-announcement:' + this.id)) this.hidden = true;
}
close() {
this.storage.set('hide-announcement:' + this.id, true);
this.hidden = true;
}
}
export * from './text-input-autocomplete.module';
export {
TextInputAutocompleteMenuComponent
TextInputAutocompleteMenuComponent,
} from './text-input-autocomplete-menu.component';