commit
2749058783
|
@ -0,0 +1,2 @@
|
||||||
|
dist
|
||||||
|
node_modules
|
|
@ -0,0 +1,13 @@
|
||||||
|
# Editor configuration, see http://editorconfig.org
|
||||||
|
root = true
|
||||||
|
|
||||||
|
[*]
|
||||||
|
charset = utf-8
|
||||||
|
indent_style = space
|
||||||
|
indent_size = 4
|
||||||
|
insert_final_newline = true
|
||||||
|
trim_trailing_whitespace = true
|
||||||
|
|
||||||
|
[*.md]
|
||||||
|
max_line_length = off
|
||||||
|
trim_trailing_whitespace = false
|
|
@ -0,0 +1,39 @@
|
||||||
|
# See http://help.github.com/ignore-files/ for more about ignoring files.
|
||||||
|
|
||||||
|
# compiled output
|
||||||
|
/dist
|
||||||
|
/tmp
|
||||||
|
/out-tsc
|
||||||
|
|
||||||
|
# dependencies
|
||||||
|
/node_modules
|
||||||
|
|
||||||
|
# IDEs and editors
|
||||||
|
/.idea
|
||||||
|
.project
|
||||||
|
.classpath
|
||||||
|
.c9/
|
||||||
|
*.launch
|
||||||
|
.settings/
|
||||||
|
*.sublime-workspace
|
||||||
|
|
||||||
|
# IDE - VSCode
|
||||||
|
.vscode/*
|
||||||
|
!.vscode/settings.json
|
||||||
|
!.vscode/tasks.json
|
||||||
|
!.vscode/launch.json
|
||||||
|
!.vscode/extensions.json
|
||||||
|
|
||||||
|
# misc
|
||||||
|
/.sass-cache
|
||||||
|
/connect.lock
|
||||||
|
/coverage
|
||||||
|
/libpeerconnection.log
|
||||||
|
npm-debug.log
|
||||||
|
yarn-error.log
|
||||||
|
testem.log
|
||||||
|
/typings
|
||||||
|
|
||||||
|
# System Files
|
||||||
|
.DS_Store
|
||||||
|
Thumbs.db
|
|
@ -0,0 +1,16 @@
|
||||||
|
# Multistage Dockerfile to build the marketplace UI and a web server to run it
|
||||||
|
|
||||||
|
# STAGE ONE: build the marketplace angular application
|
||||||
|
FROM node:latest as build
|
||||||
|
WORKDIR /usr/src/app
|
||||||
|
COPY package*.json ./
|
||||||
|
RUN npm install
|
||||||
|
COPY . .
|
||||||
|
ARG selene_env
|
||||||
|
ARG application_name
|
||||||
|
RUN npm run build -- --project=globalnav
|
||||||
|
RUN npm run build-${selene_env} -- --project=${application_name}
|
||||||
|
|
||||||
|
# STAGE TWO: build the web server and copy the compiled angular app to it.
|
||||||
|
FROM nginx:latest
|
||||||
|
COPY --from=build /usr/src/app/dist/${application_name} /usr/share/nginx/html
|
|
@ -0,0 +1,99 @@
|
||||||
|
pipeline {
|
||||||
|
agent any
|
||||||
|
|
||||||
|
stages {
|
||||||
|
|
||||||
|
// Run the build in the against the dev branch to check for compile errors
|
||||||
|
stage('Build dev branch') {
|
||||||
|
when {
|
||||||
|
branch 'dev'
|
||||||
|
}
|
||||||
|
steps {
|
||||||
|
echo 'Building code in the "dev" branch...'
|
||||||
|
sh 'npm install'
|
||||||
|
sh 'ng build --project shared'
|
||||||
|
sh 'ng build --project globalnav'
|
||||||
|
sh 'ng build --project page-not-found'
|
||||||
|
sh 'ng build --project account --configuration development'
|
||||||
|
sh 'ng build --project sso --configuration development'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Deploy to the Test environment
|
||||||
|
stage('Build for Test Environment') {
|
||||||
|
when {
|
||||||
|
branch 'test'
|
||||||
|
}
|
||||||
|
steps {
|
||||||
|
echo 'Building code in the "test" branch...'
|
||||||
|
sh 'npm install'
|
||||||
|
sh 'ng build --project shared'
|
||||||
|
sh 'ng build --project globalnav'
|
||||||
|
sh 'ng build --project page-not-found'
|
||||||
|
sh 'ng build --project account --configuration test'
|
||||||
|
sh 'ng build --project sso --configuration test'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
stage('Deploy to Test Environment') {
|
||||||
|
when {
|
||||||
|
branch 'test'
|
||||||
|
}
|
||||||
|
steps {
|
||||||
|
echo 'Deploying to test environment web servers...'
|
||||||
|
withCredentials([sshUserPrivateKey(credentialsId: '6413826d-79f6-4d03-9902-ee1b73a96efd', keyFileVariable: 'JENKINS_SSH_KEY', passphraseVariable: '', usernameVariable: 'SERVER_USER')]) {
|
||||||
|
// Deploy account application and its associated libraries
|
||||||
|
sh 'scp -r dist/shared root@192.81.211.55:/var/www/'
|
||||||
|
sh 'scp -r dist/globalnav root@192.81.211.55:/var/www/'
|
||||||
|
sh 'scp -r dist/page-not-found root@192.81.211.55:/var/www/'
|
||||||
|
sh 'scp -r dist/account root@192.81.211.55:/var/www/'
|
||||||
|
|
||||||
|
// Deploy single sign on application and its associated libraries
|
||||||
|
sh 'scp -r dist/shared root@198.199.90.118:/var/www/'
|
||||||
|
sh 'scp -r dist/globalnav root@198.199.90.118:/var/www/'
|
||||||
|
sh 'scp -r dist/page-not-found root@198.199.90.118:/var/www/'
|
||||||
|
sh 'scp -r dist/sso root@198.199.90.118:/var/www/'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Deploy to the Production environment
|
||||||
|
stage('Build for Production Environment') {
|
||||||
|
when {
|
||||||
|
branch 'master'
|
||||||
|
}
|
||||||
|
steps {
|
||||||
|
echo 'Building code in the "master" branch...'
|
||||||
|
sh 'npm install'
|
||||||
|
sh 'ng build --project shared --prod'
|
||||||
|
sh 'ng build --project globalnav --prod'
|
||||||
|
sh 'ng build --project page-not-found'
|
||||||
|
sh 'ng build --project account --prod'
|
||||||
|
sh 'ng build --project sso --prod'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
stage('Deploy to Production Environment') {
|
||||||
|
when {
|
||||||
|
branch 'master'
|
||||||
|
}
|
||||||
|
steps {
|
||||||
|
echo 'Deploying to production environment web servers...'
|
||||||
|
withCredentials([sshUserPrivateKey(credentialsId: '6413826d-79f6-4d03-9902-ee1b73a96efd', keyFileVariable: 'JENKINS_SSH_KEY', passphraseVariable: '', usernameVariable: 'SERVER_USER')]) {
|
||||||
|
// Deploy account application and its associated libraries
|
||||||
|
sh 'scp -r dist/shared root@???:/var/www/'
|
||||||
|
sh 'scp -r dist/globalnav root@???:/var/www/'
|
||||||
|
sh 'scp -r dist/page-not-found root@???:/var/www/'
|
||||||
|
sh 'scp -r dist/account root@???:/var/www/'
|
||||||
|
|
||||||
|
// Deploy single sign on application and its associated libraries
|
||||||
|
sh 'scp -r dist/shared root@???:/var/www/'
|
||||||
|
sh 'scp -r dist/globalnav root@???:/var/www/'
|
||||||
|
sh 'scp -r dist/page-not-found root@???:/var/www/'
|
||||||
|
sh 'scp -r dist/sso root@???:/var/www/'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,794 @@
|
||||||
|
{
|
||||||
|
"$schema": "./node_modules/@angular/cli/lib/config/schema.json",
|
||||||
|
"version": 1,
|
||||||
|
"newProjectRoot": "projects",
|
||||||
|
"projects": {
|
||||||
|
"internet": {
|
||||||
|
"root": "",
|
||||||
|
"sourceRoot": "src",
|
||||||
|
"projectType": "application",
|
||||||
|
"prefix": "app",
|
||||||
|
"schematics": {
|
||||||
|
"@schematics/angular:component": {
|
||||||
|
"styleext": "scss"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"architect": {
|
||||||
|
"build": {
|
||||||
|
"builder": "@angular-devkit/build-angular:browser",
|
||||||
|
"options": {
|
||||||
|
"outputPath": "dist/internet",
|
||||||
|
"index": "src/index.html",
|
||||||
|
"main": "src/main.ts",
|
||||||
|
"polyfills": "src/polyfills.ts",
|
||||||
|
"tsConfig": "src/tsconfig.app.json",
|
||||||
|
"assets": [
|
||||||
|
"src/favicon.ico",
|
||||||
|
"src/assets"
|
||||||
|
],
|
||||||
|
"styles": [
|
||||||
|
"src/styles.scss",
|
||||||
|
"src/theme.scss"
|
||||||
|
],
|
||||||
|
"stylePreprocessorOptions": {
|
||||||
|
"includePaths": [
|
||||||
|
"./src/stylesheets"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"scripts": []
|
||||||
|
},
|
||||||
|
"configurations": {
|
||||||
|
"production": {
|
||||||
|
"fileReplacements": [
|
||||||
|
{
|
||||||
|
"replace": "src/environments/environment.ts",
|
||||||
|
"with": "src/environments/environment.prod.ts"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"optimization": true,
|
||||||
|
"outputHashing": "all",
|
||||||
|
"sourceMap": false,
|
||||||
|
"extractCss": true,
|
||||||
|
"namedChunks": false,
|
||||||
|
"aot": true,
|
||||||
|
"extractLicenses": true,
|
||||||
|
"vendorChunk": false,
|
||||||
|
"buildOptimizer": true,
|
||||||
|
"budgets": [
|
||||||
|
{
|
||||||
|
"type": "initial",
|
||||||
|
"maximumWarning": "2mb",
|
||||||
|
"maximumError": "5mb"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"serve": {
|
||||||
|
"builder": "@angular-devkit/build-angular:dev-server",
|
||||||
|
"options": {
|
||||||
|
"browserTarget": "internet:build"
|
||||||
|
},
|
||||||
|
"configurations": {
|
||||||
|
"production": {
|
||||||
|
"browserTarget": "internet:build:production"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"extract-i18n": {
|
||||||
|
"builder": "@angular-devkit/build-angular:extract-i18n",
|
||||||
|
"options": {
|
||||||
|
"browserTarget": "internet:build"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"test": {
|
||||||
|
"builder": "@angular-devkit/build-angular:karma",
|
||||||
|
"options": {
|
||||||
|
"main": "src/test.ts",
|
||||||
|
"polyfills": "src/polyfills.ts",
|
||||||
|
"tsConfig": "src/tsconfig.spec.json",
|
||||||
|
"karmaConfig": "src/karma.conf.js",
|
||||||
|
"styles": [
|
||||||
|
"src/styles.scss",
|
||||||
|
"src/theme.scss"
|
||||||
|
],
|
||||||
|
"stylePreprocessorOptions": {
|
||||||
|
"includePaths": [
|
||||||
|
"./src/stylesheets"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"scripts": [],
|
||||||
|
"assets": [
|
||||||
|
"src/favicon.ico",
|
||||||
|
"src/assets"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"lint": {
|
||||||
|
"builder": "@angular-devkit/build-angular:tslint",
|
||||||
|
"options": {
|
||||||
|
"tsConfig": [
|
||||||
|
"src/tsconfig.app.json",
|
||||||
|
"src/tsconfig.spec.json"
|
||||||
|
],
|
||||||
|
"exclude": [
|
||||||
|
"**/node_modules/**"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"internet-e2e": {
|
||||||
|
"root": "e2e/",
|
||||||
|
"projectType": "application",
|
||||||
|
"prefix": "",
|
||||||
|
"architect": {
|
||||||
|
"e2e": {
|
||||||
|
"builder": "@angular-devkit/build-angular:protractor",
|
||||||
|
"options": {
|
||||||
|
"protractorConfig": "e2e/protractor.conf.js",
|
||||||
|
"devServerTarget": "internet:serve"
|
||||||
|
},
|
||||||
|
"configurations": {
|
||||||
|
"production": {
|
||||||
|
"devServerTarget": "internet:serve:production"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"lint": {
|
||||||
|
"builder": "@angular-devkit/build-angular:tslint",
|
||||||
|
"options": {
|
||||||
|
"tsConfig": "e2e/tsconfig.e2e.json",
|
||||||
|
"exclude": [
|
||||||
|
"**/node_modules/**"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"market": {
|
||||||
|
"root": "projects/market/",
|
||||||
|
"sourceRoot": "projects/market/src",
|
||||||
|
"projectType": "application",
|
||||||
|
"prefix": "market",
|
||||||
|
"schematics": {
|
||||||
|
"@schematics/angular:component": {
|
||||||
|
"styleext": "scss",
|
||||||
|
"spec": false
|
||||||
|
},
|
||||||
|
"@schematics/angular:class": {
|
||||||
|
"spec": false
|
||||||
|
},
|
||||||
|
"@schematics/angular:directive": {
|
||||||
|
"spec": false
|
||||||
|
},
|
||||||
|
"@schematics/angular:guard": {
|
||||||
|
"spec": false
|
||||||
|
},
|
||||||
|
"@schematics/angular:module": {
|
||||||
|
"spec": false
|
||||||
|
},
|
||||||
|
"@schematics/angular:pipe": {
|
||||||
|
"spec": false
|
||||||
|
},
|
||||||
|
"@schematics/angular:service": {
|
||||||
|
"spec": false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"architect": {
|
||||||
|
"build": {
|
||||||
|
"builder": "@angular-devkit/build-angular:browser",
|
||||||
|
"options": {
|
||||||
|
"outputPath": "dist/market",
|
||||||
|
"index": "projects/market/src/index.html",
|
||||||
|
"main": "projects/market/src/main.ts",
|
||||||
|
"polyfills": "projects/market/src/polyfills.ts",
|
||||||
|
"tsConfig": "projects/market/tsconfig.app.json",
|
||||||
|
"assets": [
|
||||||
|
"projects/market/src/favicon.ico",
|
||||||
|
"projects/market/src/assets"
|
||||||
|
],
|
||||||
|
"styles": [
|
||||||
|
"src/styles.scss",
|
||||||
|
"src/theme.scss"
|
||||||
|
],
|
||||||
|
"stylePreprocessorOptions": {
|
||||||
|
"includePaths": [
|
||||||
|
"./src/stylesheets"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"scripts": []
|
||||||
|
},
|
||||||
|
"configurations": {
|
||||||
|
"production": {
|
||||||
|
"fileReplacements": [
|
||||||
|
{
|
||||||
|
"replace": "projects/market/src/environments/environment.ts",
|
||||||
|
"with": "projects/market/src/environments/environment.prod.ts"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"optimization": true,
|
||||||
|
"outputHashing": "all",
|
||||||
|
"sourceMap": false,
|
||||||
|
"extractCss": true,
|
||||||
|
"namedChunks": false,
|
||||||
|
"aot": true,
|
||||||
|
"extractLicenses": true,
|
||||||
|
"vendorChunk": false,
|
||||||
|
"buildOptimizer": true,
|
||||||
|
"budgets": [
|
||||||
|
{
|
||||||
|
"type": "initial",
|
||||||
|
"maximumWarning": "2mb",
|
||||||
|
"maximumError": "5mb"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"test": {
|
||||||
|
"fileReplacements": [
|
||||||
|
{
|
||||||
|
"replace": "projects/market/src/environments/environment.ts",
|
||||||
|
"with": "projects/market/src/environments/environment.test.ts"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"outputHashing": "all"
|
||||||
|
},
|
||||||
|
"development": {
|
||||||
|
"fileReplacements": [
|
||||||
|
{
|
||||||
|
"replace": "projects/market/src/environments/environment.ts",
|
||||||
|
"with": "projects/market/src/environments/environment.dev.ts"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"serve": {
|
||||||
|
"builder": "@angular-devkit/build-angular:dev-server",
|
||||||
|
"options": {
|
||||||
|
"browserTarget": "market:build"
|
||||||
|
},
|
||||||
|
"configurations": {
|
||||||
|
"production": {
|
||||||
|
"browserTarget": "market:build:production"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"extract-i18n": {
|
||||||
|
"builder": "@angular-devkit/build-angular:extract-i18n",
|
||||||
|
"options": {
|
||||||
|
"browserTarget": "market:build"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"test": {
|
||||||
|
"builder": "@angular-devkit/build-angular:karma",
|
||||||
|
"options": {
|
||||||
|
"main": "projects/market/src/test.ts",
|
||||||
|
"polyfills": "projects/market/src/polyfills.ts",
|
||||||
|
"tsConfig": "projects/market/tsconfig.spec.json",
|
||||||
|
"karmaConfig": "projects/market/karma.conf.js",
|
||||||
|
"styles": [
|
||||||
|
"src/styles.scss",
|
||||||
|
"src/theme.scss"
|
||||||
|
],
|
||||||
|
"stylePreprocessorOptions": {
|
||||||
|
"includePaths": [
|
||||||
|
"./src/stylesheets"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"scripts": [],
|
||||||
|
"assets": [
|
||||||
|
"projects/market/src/favicon.ico",
|
||||||
|
"projects/market/src/assets"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"lint": {
|
||||||
|
"builder": "@angular-devkit/build-angular:tslint",
|
||||||
|
"options": {
|
||||||
|
"tsConfig": [
|
||||||
|
"projects/market/tsconfig.app.json",
|
||||||
|
"projects/market/tsconfig.spec.json"
|
||||||
|
],
|
||||||
|
"exclude": [
|
||||||
|
"**/node_modules/**"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"market-e2e": {
|
||||||
|
"root": "projects/market-e2e/",
|
||||||
|
"projectType": "application",
|
||||||
|
"prefix": "",
|
||||||
|
"architect": {
|
||||||
|
"e2e": {
|
||||||
|
"builder": "@angular-devkit/build-angular:protractor",
|
||||||
|
"options": {
|
||||||
|
"protractorConfig": "projects/market-e2e/protractor.conf.js",
|
||||||
|
"devServerTarget": "market:serve"
|
||||||
|
},
|
||||||
|
"configurations": {
|
||||||
|
"production": {
|
||||||
|
"devServerTarget": "market:serve:production"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"lint": {
|
||||||
|
"builder": "@angular-devkit/build-angular:tslint",
|
||||||
|
"options": {
|
||||||
|
"tsConfig": "projects/market-e2e/tsconfig.e2e.json",
|
||||||
|
"exclude": [
|
||||||
|
"**/node_modules/**"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"sso": {
|
||||||
|
"root": "projects/sso/",
|
||||||
|
"sourceRoot": "projects/sso/src",
|
||||||
|
"projectType": "application",
|
||||||
|
"prefix": "sso",
|
||||||
|
"schematics": {
|
||||||
|
"@schematics/angular:component": {
|
||||||
|
"styleext": "scss",
|
||||||
|
"spec": false
|
||||||
|
},
|
||||||
|
"@schematics/angular:class": {
|
||||||
|
"spec": false
|
||||||
|
},
|
||||||
|
"@schematics/angular:directive": {
|
||||||
|
"spec": false
|
||||||
|
},
|
||||||
|
"@schematics/angular:guard": {
|
||||||
|
"spec": false
|
||||||
|
},
|
||||||
|
"@schematics/angular:module": {
|
||||||
|
"spec": false
|
||||||
|
},
|
||||||
|
"@schematics/angular:pipe": {
|
||||||
|
"spec": false
|
||||||
|
},
|
||||||
|
"@schematics/angular:service": {
|
||||||
|
"spec": false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"architect": {
|
||||||
|
"build": {
|
||||||
|
"builder": "@angular-devkit/build-angular:browser",
|
||||||
|
"options": {
|
||||||
|
"outputPath": "dist/sso",
|
||||||
|
"index": "projects/sso/src/index.html",
|
||||||
|
"main": "projects/sso/src/main.ts",
|
||||||
|
"polyfills": "projects/sso/src/polyfills.ts",
|
||||||
|
"tsConfig": "projects/sso/tsconfig.app.json",
|
||||||
|
"assets": [
|
||||||
|
"projects/sso/src/favicon.ico",
|
||||||
|
"projects/sso/src/assets"
|
||||||
|
],
|
||||||
|
"styles": [
|
||||||
|
"src/styles.scss",
|
||||||
|
"src/theme.scss"
|
||||||
|
],
|
||||||
|
"stylePreprocessorOptions": {
|
||||||
|
"includePaths": [
|
||||||
|
"./src/stylesheets"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"scripts": []
|
||||||
|
},
|
||||||
|
"configurations": {
|
||||||
|
"production": {
|
||||||
|
"fileReplacements": [
|
||||||
|
{
|
||||||
|
"replace": "projects/sso/src/environments/environment.ts",
|
||||||
|
"with": "projects/sso/src/environments/environment.prod.ts"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"optimization": true,
|
||||||
|
"outputHashing": "all",
|
||||||
|
"sourceMap": false,
|
||||||
|
"extractCss": true,
|
||||||
|
"namedChunks": false,
|
||||||
|
"aot": true,
|
||||||
|
"extractLicenses": true,
|
||||||
|
"vendorChunk": false,
|
||||||
|
"buildOptimizer": true,
|
||||||
|
"budgets": [
|
||||||
|
{
|
||||||
|
"type": "initial",
|
||||||
|
"maximumWarning": "2mb",
|
||||||
|
"maximumError": "5mb"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"test": {
|
||||||
|
"fileReplacements": [
|
||||||
|
{
|
||||||
|
"replace": "projects/sso/src/environments/environment.ts",
|
||||||
|
"with": "projects/sso/src/environments/environment.test.ts"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"outputHashing": "all"
|
||||||
|
},
|
||||||
|
"development": {
|
||||||
|
"fileReplacements": [
|
||||||
|
{
|
||||||
|
"replace": "projects/sso/src/environments/environment.ts",
|
||||||
|
"with": "projects/sso/src/environments/environment.dev.ts"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"serve": {
|
||||||
|
"builder": "@angular-devkit/build-angular:dev-server",
|
||||||
|
"options": {
|
||||||
|
"browserTarget": "sso:build"
|
||||||
|
},
|
||||||
|
"configurations": {
|
||||||
|
"production": {
|
||||||
|
"browserTarget": "sso:build:production"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"extract-i18n": {
|
||||||
|
"builder": "@angular-devkit/build-angular:extract-i18n",
|
||||||
|
"options": {
|
||||||
|
"browserTarget": "sso:build"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"test": {
|
||||||
|
"builder": "@angular-devkit/build-angular:karma",
|
||||||
|
"options": {
|
||||||
|
"main": "projects/sso/src/test.ts",
|
||||||
|
"polyfills": "projects/sso/src/polyfills.ts",
|
||||||
|
"tsConfig": "projects/sso/tsconfig.spec.json",
|
||||||
|
"karmaConfig": "projects/sso/karma.conf.js",
|
||||||
|
"styles": [
|
||||||
|
"src/styles.scss",
|
||||||
|
"src/theme.scss"
|
||||||
|
],
|
||||||
|
"stylePreprocessorOptions": {
|
||||||
|
"includePaths": [
|
||||||
|
"./src/stylesheets"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"scripts": [],
|
||||||
|
"assets": [
|
||||||
|
"projects/sso/src/favicon.ico",
|
||||||
|
"projects/sso/src/assets"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"lint": {
|
||||||
|
"builder": "@angular-devkit/build-angular:tslint",
|
||||||
|
"options": {
|
||||||
|
"tsConfig": [
|
||||||
|
"projects/sso/tsconfig.app.json",
|
||||||
|
"projects/sso/tsconfig.spec.json"
|
||||||
|
],
|
||||||
|
"exclude": [
|
||||||
|
"**/node_modules/**"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"sso-e2e": {
|
||||||
|
"root": "projects/sso-e2e/",
|
||||||
|
"projectType": "application",
|
||||||
|
"prefix": "",
|
||||||
|
"architect": {
|
||||||
|
"e2e": {
|
||||||
|
"builder": "@angular-devkit/build-angular:protractor",
|
||||||
|
"options": {
|
||||||
|
"protractorConfig": "projects/sso-e2e/protractor.conf.js",
|
||||||
|
"devServerTarget": "sso:serve"
|
||||||
|
},
|
||||||
|
"configurations": {
|
||||||
|
"production": {
|
||||||
|
"devServerTarget": "sso:serve:production"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"lint": {
|
||||||
|
"builder": "@angular-devkit/build-angular:tslint",
|
||||||
|
"options": {
|
||||||
|
"tsConfig": "projects/sso-e2e/tsconfig.e2e.json",
|
||||||
|
"exclude": [
|
||||||
|
"**/node_modules/**"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"globalnav": {
|
||||||
|
"root": "projects/globalnav",
|
||||||
|
"sourceRoot": "projects/globalnav/src",
|
||||||
|
"projectType": "library",
|
||||||
|
"prefix": "globalnav",
|
||||||
|
"architect": {
|
||||||
|
"build": {
|
||||||
|
"builder": "@angular-devkit/build-ng-packagr:build",
|
||||||
|
"options": {
|
||||||
|
"tsConfig": "projects/globalnav/tsconfig.lib.json",
|
||||||
|
"project": "projects/globalnav/ng-package.json"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"test": {
|
||||||
|
"builder": "@angular-devkit/build-angular:karma",
|
||||||
|
"options": {
|
||||||
|
"main": "projects/globalnav/src/test.ts",
|
||||||
|
"tsConfig": "projects/globalnav/tsconfig.spec.json",
|
||||||
|
"karmaConfig": "projects/globalnav/karma.conf.js"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"lint": {
|
||||||
|
"builder": "@angular-devkit/build-angular:tslint",
|
||||||
|
"options": {
|
||||||
|
"tsConfig": [
|
||||||
|
"projects/globalnav/tsconfig.lib.json",
|
||||||
|
"projects/globalnav/tsconfig.spec.json"
|
||||||
|
],
|
||||||
|
"exclude": [
|
||||||
|
"**/node_modules/**"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"account": {
|
||||||
|
"root": "projects/account/",
|
||||||
|
"sourceRoot": "projects/account/src",
|
||||||
|
"projectType": "application",
|
||||||
|
"prefix": "account",
|
||||||
|
"schematics": {
|
||||||
|
"@schematics/angular:component": {
|
||||||
|
"styleext": "scss",
|
||||||
|
"spec": false
|
||||||
|
},
|
||||||
|
"@schematics/angular:class": {
|
||||||
|
"spec": false
|
||||||
|
},
|
||||||
|
"@schematics/angular:directive": {
|
||||||
|
"spec": false
|
||||||
|
},
|
||||||
|
"@schematics/angular:guard": {
|
||||||
|
"spec": false
|
||||||
|
},
|
||||||
|
"@schematics/angular:module": {
|
||||||
|
"spec": false
|
||||||
|
},
|
||||||
|
"@schematics/angular:pipe": {
|
||||||
|
"spec": false
|
||||||
|
},
|
||||||
|
"@schematics/angular:service": {
|
||||||
|
"spec": false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"architect": {
|
||||||
|
"build": {
|
||||||
|
"builder": "@angular-devkit/build-angular:browser",
|
||||||
|
"options": {
|
||||||
|
"outputPath": "dist/account",
|
||||||
|
"index": "projects/account/src/index.html",
|
||||||
|
"main": "projects/account/src/main.ts",
|
||||||
|
"polyfills": "projects/account/src/polyfills.ts",
|
||||||
|
"tsConfig": "projects/account/tsconfig.app.json",
|
||||||
|
"assets": [
|
||||||
|
"projects/account/src/favicon.ico",
|
||||||
|
"projects/account/src/assets"
|
||||||
|
],
|
||||||
|
"styles": [
|
||||||
|
"src/styles.scss",
|
||||||
|
"src/theme.scss"
|
||||||
|
],
|
||||||
|
"stylePreprocessorOptions": {
|
||||||
|
"includePaths": [
|
||||||
|
"./src/stylesheets"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"scripts": []
|
||||||
|
},
|
||||||
|
"configurations": {
|
||||||
|
"production": {
|
||||||
|
"fileReplacements": [
|
||||||
|
{
|
||||||
|
"replace": "projects/account/src/environments/environment.ts",
|
||||||
|
"with": "projects/account/src/environments/environment.prod.ts"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"optimization": true,
|
||||||
|
"outputHashing": "all",
|
||||||
|
"sourceMap": false,
|
||||||
|
"extractCss": true,
|
||||||
|
"namedChunks": false,
|
||||||
|
"aot": true,
|
||||||
|
"extractLicenses": true,
|
||||||
|
"vendorChunk": false,
|
||||||
|
"buildOptimizer": true,
|
||||||
|
"budgets": [
|
||||||
|
{
|
||||||
|
"type": "initial",
|
||||||
|
"maximumWarning": "2mb",
|
||||||
|
"maximumError": "5mb"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"development": {
|
||||||
|
"fileReplacements": [
|
||||||
|
{
|
||||||
|
"replace": "projects/account/src/environments/environment.ts",
|
||||||
|
"with": "projects/account/src/environments/environment.dev.ts"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"outputHashing": "all"
|
||||||
|
},
|
||||||
|
"test": {
|
||||||
|
"fileReplacements": [
|
||||||
|
{
|
||||||
|
"replace": "projects/account/src/environments/environment.ts",
|
||||||
|
"with": "projects/account/src/environments/environment.test.ts"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"outputHashing": "all"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"serve": {
|
||||||
|
"builder": "@angular-devkit/build-angular:dev-server",
|
||||||
|
"options": {
|
||||||
|
"browserTarget": "account:build"
|
||||||
|
},
|
||||||
|
"configurations": {
|
||||||
|
"production": {
|
||||||
|
"browserTarget": "account:build:production"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"extract-i18n": {
|
||||||
|
"builder": "@angular-devkit/build-angular:extract-i18n",
|
||||||
|
"options": {
|
||||||
|
"browserTarget": "account:build"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"test": {
|
||||||
|
"builder": "@angular-devkit/build-angular:karma",
|
||||||
|
"options": {
|
||||||
|
"main": "projects/account/src/test.ts",
|
||||||
|
"polyfills": "projects/account/src/polyfills.ts",
|
||||||
|
"tsConfig": "projects/account/tsconfig.spec.json",
|
||||||
|
"karmaConfig": "projects/account/karma.conf.js",
|
||||||
|
"styles": [
|
||||||
|
"src/styles.scss",
|
||||||
|
"src/theme.scss"
|
||||||
|
],
|
||||||
|
"stylePreprocessorOptions": {
|
||||||
|
"includePaths": [
|
||||||
|
"./src/stylesheets"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"scripts": [],
|
||||||
|
"assets": [
|
||||||
|
"projects/account/src/favicon.ico",
|
||||||
|
"projects/account/src/assets"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"lint": {
|
||||||
|
"builder": "@angular-devkit/build-angular:tslint",
|
||||||
|
"options": {
|
||||||
|
"tsConfig": [
|
||||||
|
"projects/account/tsconfig.app.json",
|
||||||
|
"projects/account/tsconfig.spec.json"
|
||||||
|
],
|
||||||
|
"exclude": [
|
||||||
|
"**/node_modules/**"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"account-e2e": {
|
||||||
|
"root": "projects/account-e2e/",
|
||||||
|
"projectType": "application",
|
||||||
|
"prefix": "",
|
||||||
|
"architect": {
|
||||||
|
"e2e": {
|
||||||
|
"builder": "@angular-devkit/build-angular:protractor",
|
||||||
|
"options": {
|
||||||
|
"protractorConfig": "projects/account-e2e/protractor.conf.js",
|
||||||
|
"devServerTarget": "account:serve"
|
||||||
|
},
|
||||||
|
"configurations": {
|
||||||
|
"production": {
|
||||||
|
"devServerTarget": "account:serve:production"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"lint": {
|
||||||
|
"builder": "@angular-devkit/build-angular:tslint",
|
||||||
|
"options": {
|
||||||
|
"tsConfig": "projects/account-e2e/tsconfig.e2e.json",
|
||||||
|
"exclude": [
|
||||||
|
"**/node_modules/**"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"page-not-found": {
|
||||||
|
"root": "projects/page-not-found",
|
||||||
|
"sourceRoot": "projects/page-not-found/src",
|
||||||
|
"projectType": "library",
|
||||||
|
"prefix": "lib",
|
||||||
|
"architect": {
|
||||||
|
"build": {
|
||||||
|
"builder": "@angular-devkit/build-ng-packagr:build",
|
||||||
|
"options": {
|
||||||
|
"tsConfig": "projects/page-not-found/tsconfig.lib.json",
|
||||||
|
"project": "projects/page-not-found/ng-package.json"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"test": {
|
||||||
|
"builder": "@angular-devkit/build-angular:karma",
|
||||||
|
"options": {
|
||||||
|
"main": "projects/page-not-found/src/test.ts",
|
||||||
|
"tsConfig": "projects/page-not-found/tsconfig.spec.json",
|
||||||
|
"karmaConfig": "projects/page-not-found/karma.conf.js"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"lint": {
|
||||||
|
"builder": "@angular-devkit/build-angular:tslint",
|
||||||
|
"options": {
|
||||||
|
"tsConfig": [
|
||||||
|
"projects/page-not-found/tsconfig.lib.json",
|
||||||
|
"projects/page-not-found/tsconfig.spec.json"
|
||||||
|
],
|
||||||
|
"exclude": [
|
||||||
|
"**/node_modules/**"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"shared": {
|
||||||
|
"root": "projects/shared",
|
||||||
|
"sourceRoot": "projects/shared/src",
|
||||||
|
"projectType": "library",
|
||||||
|
"prefix": "shared",
|
||||||
|
"architect": {
|
||||||
|
"build": {
|
||||||
|
"builder": "@angular-devkit/build-ng-packagr:build",
|
||||||
|
"options": {
|
||||||
|
"tsConfig": "projects/shared/tsconfig.lib.json",
|
||||||
|
"project": "projects/shared/ng-package.json"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"test": {
|
||||||
|
"builder": "@angular-devkit/build-angular:karma",
|
||||||
|
"options": {
|
||||||
|
"main": "projects/shared/src/test.ts",
|
||||||
|
"tsConfig": "projects/shared/tsconfig.spec.json",
|
||||||
|
"karmaConfig": "projects/shared/karma.conf.js"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"lint": {
|
||||||
|
"builder": "@angular-devkit/build-angular:tslint",
|
||||||
|
"options": {
|
||||||
|
"tsConfig": [
|
||||||
|
"projects/shared/tsconfig.lib.json",
|
||||||
|
"projects/shared/tsconfig.spec.json"
|
||||||
|
],
|
||||||
|
"exclude": [
|
||||||
|
"**/node_modules/**"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"defaultProject": "internet"
|
||||||
|
}
|
|
@ -0,0 +1,28 @@
|
||||||
|
// Protractor configuration file, see link for more information
|
||||||
|
// https://github.com/angular/protractor/blob/master/lib/config.ts
|
||||||
|
|
||||||
|
const { SpecReporter } = require('jasmine-spec-reporter');
|
||||||
|
|
||||||
|
exports.config = {
|
||||||
|
allScriptsTimeout: 11000,
|
||||||
|
specs: [
|
||||||
|
'./src/**/*.e2e-spec.ts'
|
||||||
|
],
|
||||||
|
capabilities: {
|
||||||
|
'browserName': 'chrome'
|
||||||
|
},
|
||||||
|
directConnect: true,
|
||||||
|
baseUrl: 'http://localhost:4200/',
|
||||||
|
framework: 'jasmine',
|
||||||
|
jasmineNodeOpts: {
|
||||||
|
showColors: true,
|
||||||
|
defaultTimeoutInterval: 30000,
|
||||||
|
print: function() {}
|
||||||
|
},
|
||||||
|
onPrepare() {
|
||||||
|
require('ts-node').register({
|
||||||
|
project: require('path').join(__dirname, './tsconfig.e2e.json')
|
||||||
|
});
|
||||||
|
jasmine.getEnv().addReporter(new SpecReporter({ spec: { displayStacktrace: true } }));
|
||||||
|
}
|
||||||
|
};
|
|
@ -0,0 +1,14 @@
|
||||||
|
import { AppPage } from './app.po';
|
||||||
|
|
||||||
|
describe('workspace-project App', () => {
|
||||||
|
let page: AppPage;
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
page = new AppPage();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should display welcome message', () => {
|
||||||
|
page.navigateTo();
|
||||||
|
expect(page.getParagraphText()).toEqual('Welcome to internet!');
|
||||||
|
});
|
||||||
|
});
|
|
@ -0,0 +1,11 @@
|
||||||
|
import { browser, by, element } from 'protractor';
|
||||||
|
|
||||||
|
export class AppPage {
|
||||||
|
navigateTo() {
|
||||||
|
return browser.get('/');
|
||||||
|
}
|
||||||
|
|
||||||
|
getParagraphText() {
|
||||||
|
return element(by.css('app-root h1')).getText();
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,13 @@
|
||||||
|
{
|
||||||
|
"extends": "../tsconfig.json",
|
||||||
|
"compilerOptions": {
|
||||||
|
"outDir": "../out-tsc/app",
|
||||||
|
"module": "commonjs",
|
||||||
|
"target": "es5",
|
||||||
|
"types": [
|
||||||
|
"jasmine",
|
||||||
|
"jasminewd2",
|
||||||
|
"node"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,66 @@
|
||||||
|
{
|
||||||
|
"name": "internet",
|
||||||
|
"version": "0.0.0",
|
||||||
|
"scripts": {
|
||||||
|
"ng": "ng",
|
||||||
|
"start": "ng serve",
|
||||||
|
"build": "ng build",
|
||||||
|
"build-dev": "ng build --configuration=development",
|
||||||
|
"build-test": "ng build --configuration=test",
|
||||||
|
"build-prod": "ng build --prod",
|
||||||
|
"test": "ng test",
|
||||||
|
"lint": "ng lint",
|
||||||
|
"e2e": "ng e2e"
|
||||||
|
},
|
||||||
|
"private": true,
|
||||||
|
"dependencies": {
|
||||||
|
"@angular/animations": "~7.0.0",
|
||||||
|
"@angular/cdk": "^7.0.1",
|
||||||
|
"@angular/common": "~7.0.0",
|
||||||
|
"@angular/compiler": "~7.0.0",
|
||||||
|
"@angular/core": "~7.0.1",
|
||||||
|
"@angular/flex-layout": "^7.0.0-beta.19",
|
||||||
|
"@angular/forms": "~7.0.0",
|
||||||
|
"@angular/http": "~7.0.0",
|
||||||
|
"@angular/material": "^7.0.1",
|
||||||
|
"@angular/platform-browser": "~7.0.0",
|
||||||
|
"@angular/platform-browser-dynamic": "~7.0.0",
|
||||||
|
"@angular/router": "~7.0.0",
|
||||||
|
"@fortawesome/angular-fontawesome": "^0.3.0",
|
||||||
|
"@fortawesome/fontawesome-svg-core": "^1.2.7",
|
||||||
|
"@fortawesome/free-brands-svg-icons": "^5.4.2",
|
||||||
|
"@fortawesome/free-solid-svg-icons": "^5.4.2",
|
||||||
|
"angular-6-social-login": "^1.1.1",
|
||||||
|
"angular-font-awesome": "^3.1.2",
|
||||||
|
"core-js": "^2.5.4",
|
||||||
|
"font-awesome": "^4.7.0",
|
||||||
|
"ngx-cookie-service": "^2.1.0",
|
||||||
|
"rxjs": "~6.3.3",
|
||||||
|
"zone.js": "~0.8.26"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@angular-devkit/build-angular": "~0.10.0",
|
||||||
|
"@angular-devkit/build-ng-packagr": "~0.10.0",
|
||||||
|
"@angular/cli": "~7.0.3",
|
||||||
|
"@angular/compiler-cli": "~7.0.0",
|
||||||
|
"@angular/language-service": "~7.0.0",
|
||||||
|
"@types/node": "~8.9.4",
|
||||||
|
"@types/jasmine": "~2.8.8",
|
||||||
|
"@types/jasminewd2": "~2.0.3",
|
||||||
|
"codelyzer": "~4.5.0",
|
||||||
|
"jasmine-core": "~2.99.1",
|
||||||
|
"jasmine-spec-reporter": "~4.2.1",
|
||||||
|
"karma": "~3.0.0",
|
||||||
|
"karma-chrome-launcher": "~2.2.0",
|
||||||
|
"karma-coverage-istanbul-reporter": "~2.0.1",
|
||||||
|
"karma-jasmine": "~1.1.2",
|
||||||
|
"karma-jasmine-html-reporter": "^0.2.2",
|
||||||
|
"ng-packagr": "^4.6.0",
|
||||||
|
"protractor": "~5.4.0",
|
||||||
|
"ts-node": "~7.0.0",
|
||||||
|
"tsickle": ">=0.29.0",
|
||||||
|
"tslib": "^1.9.0",
|
||||||
|
"tslint": "~5.11.0",
|
||||||
|
"typescript": "~3.1.1"
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,11 @@
|
||||||
|
# This file is currently used by autoprefixer to adjust CSS to support the below specified browsers
|
||||||
|
# For additional information regarding the format and rule options, please see:
|
||||||
|
# https://github.com/browserslist/browserslist#queries
|
||||||
|
#
|
||||||
|
# For IE 9-11 support, please remove 'not' from the last line of the file and adjust as needed
|
||||||
|
|
||||||
|
> 0.5%
|
||||||
|
last 2 versions
|
||||||
|
Firefox ESR
|
||||||
|
not dead
|
||||||
|
not IE 9-11
|
|
@ -0,0 +1,31 @@
|
||||||
|
// Karma configuration file, see link for more information
|
||||||
|
// https://karma-runner.github.io/1.0/config/configuration-file.html
|
||||||
|
|
||||||
|
module.exports = function (config) {
|
||||||
|
config.set({
|
||||||
|
basePath: '',
|
||||||
|
frameworks: ['jasmine', '@angular-devkit/build-angular'],
|
||||||
|
plugins: [
|
||||||
|
require('karma-jasmine'),
|
||||||
|
require('karma-chrome-launcher'),
|
||||||
|
require('karma-jasmine-html-reporter'),
|
||||||
|
require('karma-coverage-istanbul-reporter'),
|
||||||
|
require('@angular-devkit/build-angular/plugins/karma')
|
||||||
|
],
|
||||||
|
client: {
|
||||||
|
clearContext: false // leave Jasmine Spec Runner output visible in browser
|
||||||
|
},
|
||||||
|
coverageIstanbulReporter: {
|
||||||
|
dir: require('path').join(__dirname, '../../coverage'),
|
||||||
|
reports: ['html', 'lcovonly'],
|
||||||
|
fixWebpackSourcePaths: true
|
||||||
|
},
|
||||||
|
reporters: ['progress', 'kjhtml'],
|
||||||
|
port: 9876,
|
||||||
|
colors: true,
|
||||||
|
logLevel: config.LOG_INFO,
|
||||||
|
autoWatch: true,
|
||||||
|
browsers: ['Chrome'],
|
||||||
|
singleRun: false
|
||||||
|
});
|
||||||
|
};
|
|
@ -0,0 +1,8 @@
|
||||||
|
{
|
||||||
|
"/api/*": {
|
||||||
|
"target": "http://localhost:5003",
|
||||||
|
"secure": false,
|
||||||
|
"logLevel": "debug",
|
||||||
|
"changeOrigin": true
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,24 @@
|
||||||
|
import { NgModule } from '@angular/core';
|
||||||
|
import { Routes, RouterModule } from '@angular/router';
|
||||||
|
|
||||||
|
import { CreateAccountComponent } from './create-account/create-account.component';
|
||||||
|
import { DeviceComponent } from './device/device.component';
|
||||||
|
import { PageNotFoundComponent } from 'page-not-found';
|
||||||
|
import { ProfileComponent } from './profile/profile.component';
|
||||||
|
import { SkillComponent } from './skill/skill.component';
|
||||||
|
|
||||||
|
const routes: Routes = [
|
||||||
|
{ path: 'create-account', component: CreateAccountComponent },
|
||||||
|
{ path: 'device', component: DeviceComponent },
|
||||||
|
{ path: 'profile', component: ProfileComponent },
|
||||||
|
{ path: 'skill', component: SkillComponent },
|
||||||
|
{ path: '', redirectTo: '/profile', pathMatch: 'full' },
|
||||||
|
{ path: '**', component: PageNotFoundComponent }
|
||||||
|
];
|
||||||
|
|
||||||
|
@NgModule({
|
||||||
|
imports: [ RouterModule.forRoot(routes) ],
|
||||||
|
exports: [ RouterModule ]
|
||||||
|
})
|
||||||
|
export class AppRoutingModule {
|
||||||
|
}
|
|
@ -0,0 +1,5 @@
|
||||||
|
<globalnav-sidenav [mycroftUrls]="environment.mycroftUrls">
|
||||||
|
<div appBody id="account-body">
|
||||||
|
<router-outlet></router-outlet>
|
||||||
|
</div>
|
||||||
|
</globalnav-sidenav>
|
|
@ -0,0 +1,19 @@
|
||||||
|
import { Component, OnInit } from '@angular/core';
|
||||||
|
|
||||||
|
import { environment } from '../environments/environment';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'account-root',
|
||||||
|
templateUrl: './app.component.html',
|
||||||
|
styleUrls: ['./app.component.scss']
|
||||||
|
})
|
||||||
|
export class AppComponent implements OnInit {
|
||||||
|
public environment = environment;
|
||||||
|
title = 'Account';
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
}
|
||||||
|
|
||||||
|
ngOnInit() {
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,35 @@
|
||||||
|
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
|
||||||
|
import { BrowserModule } from '@angular/platform-browser';
|
||||||
|
import { HttpClientModule } from '@angular/common/http';
|
||||||
|
import { NgModule } from '@angular/core';
|
||||||
|
|
||||||
|
import { AppRoutingModule } from './app-routing.module';
|
||||||
|
import { AppComponent } from './app.component';
|
||||||
|
import { CreateAccountModule } from './create-account/create-account.module';
|
||||||
|
import { GlobalnavModule } from 'globalnav';
|
||||||
|
import { PageNotFoundModule } from 'page-not-found';
|
||||||
|
import { DeviceModule } from './device/device.module';
|
||||||
|
import { ProfileModule } from './profile/profile.module';
|
||||||
|
import { SharedModule } from 'shared';
|
||||||
|
import { SkillModule } from './skill/skill.module';
|
||||||
|
|
||||||
|
@NgModule(
|
||||||
|
{
|
||||||
|
declarations: [ AppComponent ],
|
||||||
|
imports: [
|
||||||
|
BrowserModule,
|
||||||
|
BrowserAnimationsModule,
|
||||||
|
CreateAccountModule,
|
||||||
|
GlobalnavModule,
|
||||||
|
HttpClientModule,
|
||||||
|
DeviceModule,
|
||||||
|
PageNotFoundModule,
|
||||||
|
ProfileModule,
|
||||||
|
SharedModule,
|
||||||
|
SkillModule,
|
||||||
|
AppRoutingModule
|
||||||
|
],
|
||||||
|
bootstrap: [ AppComponent ]
|
||||||
|
}
|
||||||
|
)
|
||||||
|
export class AppModule { }
|
|
@ -0,0 +1,14 @@
|
||||||
|
<h2 *ngIf="step === 'Terms of Use'" class="mat-h2">First, the legal stuff...</h2>
|
||||||
|
<h2 *ngIf="step === 'Privacy Policy'" class="mat-h2">We value your privacy!</h2>
|
||||||
|
<mat-card class="mat-elevation-z0" fxLayout="column" fxLayoutAlign="space-around">
|
||||||
|
<mat-card-content [innerHTML]="agreementContent"></mat-card-content>
|
||||||
|
<mat-card-actions align="right">
|
||||||
|
<button *ngIf="!agreementAccepted" mat-button (click)="acceptAgreement()">
|
||||||
|
Accept
|
||||||
|
</button>
|
||||||
|
<button *ngIf="agreementAccepted" class="accepted-button" mat-button (click)="declineAgreement()">
|
||||||
|
<fa-icon [icon]="acceptedIcon"></fa-icon>
|
||||||
|
Accepted
|
||||||
|
</button>
|
||||||
|
</mat-card-actions>
|
||||||
|
</mat-card>
|
|
@ -0,0 +1,36 @@
|
||||||
|
@import "~@angular/material/theming";
|
||||||
|
@import "mycroft-colors";
|
||||||
|
@import "~src/stylesheets/components/buttons";
|
||||||
|
|
||||||
|
h2 {
|
||||||
|
margin-left: 16px;
|
||||||
|
margin-bottom: 0;
|
||||||
|
color: mat-color($mycroft-primary);
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
mat-card {
|
||||||
|
height: 60vh;
|
||||||
|
margin-bottom: 16px;
|
||||||
|
margin-left: auto;
|
||||||
|
margin-right: auto;
|
||||||
|
max-width: 1000px;
|
||||||
|
mat-card-content {
|
||||||
|
max-height: 85%;
|
||||||
|
overflow-y: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
mat-card-actions {
|
||||||
|
padding-right: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
button {
|
||||||
|
@include action-button-primary;
|
||||||
|
width: 120px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.accepted-button {
|
||||||
|
background-color: mat-color($mycroft-accent, A100);
|
||||||
|
}
|
|
@ -0,0 +1,48 @@
|
||||||
|
import { Component, Input, OnInit } from '@angular/core';
|
||||||
|
import { FormGroup } from '@angular/forms';
|
||||||
|
import { DomSanitizer, SafeHtml } from '@angular/platform-browser';
|
||||||
|
|
||||||
|
import { faCheck } from '@fortawesome/free-solid-svg-icons';
|
||||||
|
|
||||||
|
import { Agreement, CreateAccountService } from '../create-account.service';
|
||||||
|
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'account-agreement-step',
|
||||||
|
templateUrl: './agreement-step.component.html',
|
||||||
|
styleUrls: ['./agreement-step.component.scss']
|
||||||
|
})
|
||||||
|
export class AgreementStepComponent implements OnInit {
|
||||||
|
public acceptedIcon = faCheck;
|
||||||
|
public agreementAccepted = false;
|
||||||
|
public agreementContent: SafeHtml;
|
||||||
|
@Input() newAcctForm: FormGroup;
|
||||||
|
@Input() step: string;
|
||||||
|
|
||||||
|
constructor(private newAcctService: CreateAccountService, private sanitizer: DomSanitizer) {
|
||||||
|
}
|
||||||
|
|
||||||
|
ngOnInit() {
|
||||||
|
this.newAcctService.getAgreement(this.step).subscribe(
|
||||||
|
(response) => { this.agreementContent = this.sanitizer.bypassSecurityTrustHtml(response.content); }
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
acceptAgreement() {
|
||||||
|
if (this.step === 'Terms of Use') {
|
||||||
|
this.newAcctForm.controls.termsOfUse.setValue(true);
|
||||||
|
} else {
|
||||||
|
this.newAcctForm.controls.privacyPolicy.setValue(true);
|
||||||
|
}
|
||||||
|
this.agreementAccepted = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
declineAgreement () {
|
||||||
|
if (this.step === 'Terms of Use') {
|
||||||
|
this.newAcctForm.controls.termsOfUse.setValue(false);
|
||||||
|
} else {
|
||||||
|
this.newAcctForm.controls.privacyPolicy.setValue(false);
|
||||||
|
}
|
||||||
|
this.agreementAccepted = false;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,33 @@
|
||||||
|
<mat-card fxLayout.gt-sm="row" fxLayoutAlign="center center" class="mat-elevation-z0" [formGroup]="newAcctForm.get('login')">
|
||||||
|
<!-- Federated Log In Controls -->
|
||||||
|
<mat-card class="mat-elevation-z0">
|
||||||
|
<h2 class="mat-h2">Log In Using...</h2>
|
||||||
|
<p>{{federatedLoginText}}</p>
|
||||||
|
<div id="federated-buttons" fxLayout="column" fxLayoutAlign="center center">
|
||||||
|
<shared-google-button></shared-google-button>
|
||||||
|
<shared-facebook-button (facebookEmail)="onFacebookLogin($event)"></shared-facebook-button>
|
||||||
|
<shared-github-button></shared-github-button>
|
||||||
|
</div>
|
||||||
|
</mat-card>
|
||||||
|
|
||||||
|
<h1 class="mat-h1">OR</h1>
|
||||||
|
|
||||||
|
<!-- Mycroft Log In Controls-->
|
||||||
|
<mat-card class="mat-elevation-z0">
|
||||||
|
<h2 class="mat-h2">Email and Password</h2>
|
||||||
|
<p>{{internalLoginText}}</p>
|
||||||
|
<div fxLayout="column">
|
||||||
|
<mat-form-field [appearance]="'outline'">
|
||||||
|
<mat-label>Email Address</mat-label>
|
||||||
|
<input matInput type="email" formControlName="userEnteredEmail" [readonly]="disableInternal">
|
||||||
|
<mat-error>
|
||||||
|
Must be a valid email address
|
||||||
|
</mat-error>
|
||||||
|
</mat-form-field>
|
||||||
|
<mat-form-field [appearance]="'outline'">
|
||||||
|
<mat-label>Password</mat-label>
|
||||||
|
<input matInput type="password" formControlName="password" [readonly]="disableInternal">
|
||||||
|
</mat-form-field>
|
||||||
|
</div>
|
||||||
|
</mat-card>
|
||||||
|
</mat-card>
|
|
@ -0,0 +1,31 @@
|
||||||
|
@import "~@angular/material/theming";
|
||||||
|
@import "mycroft-colors";
|
||||||
|
|
||||||
|
.mat-h1 {
|
||||||
|
padding: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mat-h2 {
|
||||||
|
color: mat-color($mycroft-primary);
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
mat-card {
|
||||||
|
margin-left: auto;
|
||||||
|
margin-right: auto;
|
||||||
|
max-width: 1000px;
|
||||||
|
|
||||||
|
mat-card {
|
||||||
|
height: 300px;
|
||||||
|
max-width: 400px;
|
||||||
|
|
||||||
|
#federated-buttons {
|
||||||
|
height: 180px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
mat-form-field {
|
||||||
|
max-width: 400px;
|
||||||
|
min-width: 300px;
|
||||||
|
}
|
|
@ -0,0 +1,28 @@
|
||||||
|
import { Component, Input, OnInit } from '@angular/core';
|
||||||
|
import { FormGroup } from '@angular/forms';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'account-authentication-step',
|
||||||
|
templateUrl: './authentication-step.component.html',
|
||||||
|
styleUrls: ['./authentication-step.component.scss']
|
||||||
|
})
|
||||||
|
export class AuthenticationStepComponent implements OnInit {
|
||||||
|
public disableInternal = false;
|
||||||
|
public federatedLoginText: string;
|
||||||
|
public internalLoginText: string;
|
||||||
|
@Input() newAcctForm: FormGroup;
|
||||||
|
|
||||||
|
constructor() { }
|
||||||
|
|
||||||
|
ngOnInit() {
|
||||||
|
this.federatedLoginText = 'To use this option, you must allow the ' +
|
||||||
|
'provider to share your email address with Mycroft';
|
||||||
|
this.internalLoginText = 'Login credentials stored on Mycroft ' +
|
||||||
|
'servers are encrypted for your privacy and protection.';
|
||||||
|
}
|
||||||
|
|
||||||
|
onFacebookLogin(email: string) {
|
||||||
|
this.newAcctForm.patchValue({login: {federatedEmail: email}});
|
||||||
|
this.disableInternal = true;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,126 @@
|
||||||
|
<form [formGroup]="newAcctForm" (ngSubmit)="onFormSubmit()">
|
||||||
|
|
||||||
|
<!-- Show a horizontal stepper on larger devices -->
|
||||||
|
<mat-horizontal-stepper *ngIf="!alignVertical" labelPosition="bottom" [linear]="true">
|
||||||
|
<!-- Use font awesome icons in the stepper to indicate progress -->
|
||||||
|
<ng-template matStepperIcon="done">
|
||||||
|
<fa-icon [icon]="stepDoneIcon"></fa-icon>
|
||||||
|
</ng-template>
|
||||||
|
<ng-template matStepperIcon="edit">
|
||||||
|
<fa-icon [icon]="stepDoneIcon"></fa-icon>
|
||||||
|
</ng-template>
|
||||||
|
|
||||||
|
<mat-step label="Terms Of Use" [stepControl]="termsOfUseControl">
|
||||||
|
<account-agreement-step [newAcctForm]="newAcctForm" [step]="'Terms of Use'">
|
||||||
|
</account-agreement-step>
|
||||||
|
<div fxLayout="row" fxLayoutAlign="end">
|
||||||
|
<button mat-button matStepperNext type="button" [disabled]="!termsOfUseControl.valid">
|
||||||
|
Next
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</mat-step>
|
||||||
|
|
||||||
|
<mat-step label="Privacy Policy" [stepControl]="privacyPolicyControl">
|
||||||
|
<account-agreement-step [newAcctForm]="newAcctForm" [step]="'Privacy Policy'">
|
||||||
|
</account-agreement-step>
|
||||||
|
<div fxLayout="row" fxLayoutAlign="end">
|
||||||
|
<button mat-button matStepperNext type="button" [disabled]="!privacyPolicyControl.valid">
|
||||||
|
Next
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</mat-step>
|
||||||
|
|
||||||
|
<mat-step label="Login" [stepControl]="loginControl">
|
||||||
|
<account-authentication-step [newAcctForm]="newAcctForm"></account-authentication-step>
|
||||||
|
<div fxLayout="row" fxLayoutAlign="end">
|
||||||
|
<button mat-button matStepperNext type="button" [disabled]="!loginControl.valid">
|
||||||
|
Next
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</mat-step>
|
||||||
|
|
||||||
|
<mat-step label="Username" [stepControl]="usernameControl">
|
||||||
|
<account-username-step [newAcctForm]="newAcctForm"></account-username-step>
|
||||||
|
<div fxLayout="row" fxLayoutAlign="end">
|
||||||
|
<button mat-button matStepperNext type="button" [disabled]="!usernameControl.valid">
|
||||||
|
Next
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</mat-step>
|
||||||
|
|
||||||
|
<mat-step label="Support Mycroft" [stepControl]="supportControl">
|
||||||
|
<account-support-step [newAcctForm]="newAcctForm"></account-support-step>
|
||||||
|
<div fxLayout="row" fxLayoutAlign="end">
|
||||||
|
<button mat-button matStepperNext type="button" [disabled]="!supportControl.valid">
|
||||||
|
Next
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</mat-step>
|
||||||
|
|
||||||
|
<mat-step label="Done!">
|
||||||
|
<account-done-step [newAcctForm]="newAcctForm"></account-done-step>
|
||||||
|
</mat-step>
|
||||||
|
</mat-horizontal-stepper>
|
||||||
|
|
||||||
|
<!-- Show a vertical stepper on smaller devices -->
|
||||||
|
<mat-vertical-stepper *ngIf="alignVertical" [linear]="true">
|
||||||
|
<!-- Use font awesome icons in the stepper to indicate progress -->
|
||||||
|
<ng-template matStepperIcon="done">
|
||||||
|
<fa-icon [icon]="stepDoneIcon"></fa-icon>
|
||||||
|
</ng-template>
|
||||||
|
<ng-template matStepperIcon="edit">
|
||||||
|
<fa-icon [icon]="stepDoneIcon"></fa-icon>
|
||||||
|
</ng-template>
|
||||||
|
|
||||||
|
<mat-step label="Terms Of Use" [stepControl]="termsOfUseControl">
|
||||||
|
<account-agreement-step [newAcctForm]="newAcctForm" [step]="'Terms of Use'">
|
||||||
|
</account-agreement-step>
|
||||||
|
<div fxLayout="row" fxLayoutAlign="end">
|
||||||
|
<button mat-button matStepperNext type="button" [disabled]="!termsOfUseControl.valid">
|
||||||
|
Next
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</mat-step>
|
||||||
|
|
||||||
|
<mat-step label="Privacy Policy" [stepControl]="privacyPolicyControl">
|
||||||
|
<account-agreement-step [newAcctForm]="newAcctForm" [step]="'Privacy Policy'">
|
||||||
|
</account-agreement-step>
|
||||||
|
<div fxLayout="row" fxLayoutAlign="end">
|
||||||
|
<button mat-button matStepperNext type="button" [disabled]="!privacyPolicyControl.valid">
|
||||||
|
Next
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</mat-step>
|
||||||
|
|
||||||
|
<mat-step label="Log In Method" [stepControl]="loginControl">
|
||||||
|
<account-authentication-step [newAcctForm]="newAcctForm"></account-authentication-step>
|
||||||
|
<div fxLayout="row" fxLayoutAlign="end">
|
||||||
|
<button mat-button matStepperNext type="button" [disabled]="!loginControl.valid">
|
||||||
|
Next
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</mat-step>
|
||||||
|
|
||||||
|
<mat-step label="Display Name" [stepControl]="usernameControl">
|
||||||
|
<account-username-step [newAcctForm]="newAcctForm"></account-username-step>
|
||||||
|
<div fxLayout="row" fxLayoutAlign="end">
|
||||||
|
<button mat-button matStepperNext type="button" [disabled]="!usernameControl.valid">
|
||||||
|
Next
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</mat-step>
|
||||||
|
|
||||||
|
<mat-step label="Support Mycroft" [stepControl]="supportControl">
|
||||||
|
<account-support-step [newAcctForm]="newAcctForm"></account-support-step>
|
||||||
|
<div fxLayout="row" fxLayoutAlign="end">
|
||||||
|
<button mat-button matStepperNext type="button" [disabled]="!supportControl.valid">
|
||||||
|
Next
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</mat-step>
|
||||||
|
|
||||||
|
<mat-step label="Done!">
|
||||||
|
<account-done-step [newAcctForm]="newAcctForm"></account-done-step>
|
||||||
|
</mat-step>
|
||||||
|
</mat-vertical-stepper>
|
||||||
|
</form>
|
|
@ -0,0 +1,17 @@
|
||||||
|
@import "~@angular/material/theming";
|
||||||
|
@import "mycroft-colors";
|
||||||
|
@import "~src/stylesheets/components/buttons";
|
||||||
|
|
||||||
|
button {
|
||||||
|
@include action-button-primary;
|
||||||
|
}
|
||||||
|
|
||||||
|
button:disabled {
|
||||||
|
background-color: mat-color($mycroft-accent, 200);
|
||||||
|
}
|
||||||
|
|
||||||
|
mat-horizontal-stepper {
|
||||||
|
margin-left: auto;
|
||||||
|
margin-right: auto;
|
||||||
|
max-width: 1200px;
|
||||||
|
}
|
|
@ -0,0 +1,140 @@
|
||||||
|
import { Component, OnInit } from '@angular/core';
|
||||||
|
import { MediaChange, MediaObserver } from '@angular/flex-layout';
|
||||||
|
import {
|
||||||
|
AbstractControl,
|
||||||
|
FormBuilder,
|
||||||
|
FormGroup,
|
||||||
|
ValidatorFn,
|
||||||
|
Validators
|
||||||
|
} from '@angular/forms';
|
||||||
|
|
||||||
|
import { faCheck } from '@fortawesome/free-solid-svg-icons';
|
||||||
|
import { MatSnackBar } from '@angular/material';
|
||||||
|
import { Subscription } from 'rxjs';
|
||||||
|
|
||||||
|
import {
|
||||||
|
CreateAccountService,
|
||||||
|
navigateToLogin,
|
||||||
|
storeRedirect
|
||||||
|
} from './create-account.service';
|
||||||
|
|
||||||
|
const noDelay = 0;
|
||||||
|
|
||||||
|
export function loginValidator(): ValidatorFn {
|
||||||
|
return (loginGroup: FormGroup) => {
|
||||||
|
let valid = true;
|
||||||
|
const federatedEmail = loginGroup.controls['federatedEmail'];
|
||||||
|
const userEnteredEmail = loginGroup.controls['userEnteredEmail'];
|
||||||
|
const password = loginGroup.controls['password'];
|
||||||
|
|
||||||
|
if (federatedEmail.value) {
|
||||||
|
if (userEnteredEmail.value || password.value) {
|
||||||
|
valid = false;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (!userEnteredEmail.valid || !password.value) {
|
||||||
|
valid = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return valid ? null : {loginInvalid: true};
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export function membershipValidator(): ValidatorFn {
|
||||||
|
return (supportGroup: FormGroup) => {
|
||||||
|
let valid = true;
|
||||||
|
const membershipType = supportGroup.controls['membership'];
|
||||||
|
const paymentAccountId = supportGroup.controls['paymentAccountId'];
|
||||||
|
|
||||||
|
if (membershipType.value !== 'MAYBE LATER') {
|
||||||
|
if (!paymentAccountId.value) {
|
||||||
|
valid = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return valid ? null : {membershipInvalid: true};
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'account-create-account',
|
||||||
|
templateUrl: './create-account.component.html',
|
||||||
|
styleUrls: ['./create-account.component.scss']
|
||||||
|
})
|
||||||
|
export class CreateAccountComponent implements OnInit {
|
||||||
|
public alignVertical: boolean;
|
||||||
|
public usernameControl: AbstractControl;
|
||||||
|
public loginControl: AbstractControl;
|
||||||
|
private mediaWatcher: Subscription;
|
||||||
|
public newAcctForm: FormGroup;
|
||||||
|
public privacyPolicyControl: AbstractControl;
|
||||||
|
public stepDoneIcon = faCheck;
|
||||||
|
public supportControl: AbstractControl;
|
||||||
|
public termsOfUseControl: AbstractControl;
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
private formBuilder: FormBuilder,
|
||||||
|
public mediaObserver: MediaObserver,
|
||||||
|
private newAcctService: CreateAccountService,
|
||||||
|
private errorSnackbar: MatSnackBar
|
||||||
|
) {
|
||||||
|
this.mediaWatcher = mediaObserver.media$.subscribe(
|
||||||
|
(change: MediaChange) => {
|
||||||
|
this.alignVertical = ['xs', 'sm'].includes(change.mqAlias);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
ngOnInit() {
|
||||||
|
storeRedirect();
|
||||||
|
this.buildForm();
|
||||||
|
this.setControlFormAliases();
|
||||||
|
}
|
||||||
|
|
||||||
|
private buildForm() {
|
||||||
|
const loginGroup = this.formBuilder.group(
|
||||||
|
{
|
||||||
|
federatedEmail: [null],
|
||||||
|
userEnteredEmail: [null, Validators.email],
|
||||||
|
password: [null]
|
||||||
|
},
|
||||||
|
{validator: loginValidator()}
|
||||||
|
);
|
||||||
|
const supportGroup = this.formBuilder.group(
|
||||||
|
{
|
||||||
|
openDataset: [null, Validators.required],
|
||||||
|
membership: [null, Validators.required],
|
||||||
|
paymentMethod: [null],
|
||||||
|
paymentAccountId: [null]
|
||||||
|
|
||||||
|
},
|
||||||
|
{validator: membershipValidator()}
|
||||||
|
);
|
||||||
|
|
||||||
|
this.newAcctForm = this.formBuilder.group({
|
||||||
|
username: ['', Validators.required],
|
||||||
|
privacyPolicy: [false, Validators.requiredTrue],
|
||||||
|
termsOfUse: [false, Validators.requiredTrue],
|
||||||
|
login: loginGroup,
|
||||||
|
support: supportGroup
|
||||||
|
});
|
||||||
|
this.newAcctForm.patchValue(
|
||||||
|
{support: {paymentMethod: 'Stripe', paymentAccountId: 'foostripe'}}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
private setControlFormAliases() {
|
||||||
|
this.usernameControl = this.newAcctForm.controls['username'];
|
||||||
|
this.loginControl = this.newAcctForm.controls['login'];
|
||||||
|
this.privacyPolicyControl = this.newAcctForm.controls['privacyPolicy'];
|
||||||
|
this.supportControl = this.newAcctForm.controls['support'];
|
||||||
|
this.termsOfUseControl = this.newAcctForm.controls['termsOfUse'];
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
onFormSubmit() {
|
||||||
|
this.newAcctService.addAccount(this.newAcctForm).subscribe(
|
||||||
|
(response) => { navigateToLogin(noDelay); }
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,54 @@
|
||||||
|
import { NgModule } from '@angular/core';
|
||||||
|
import { CommonModule } from '@angular/common';
|
||||||
|
import { FlexLayoutModule } from '@angular/flex-layout';
|
||||||
|
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
|
||||||
|
import {
|
||||||
|
MatButtonModule,
|
||||||
|
MatButtonToggleModule,
|
||||||
|
MatCardModule,
|
||||||
|
MatFormFieldModule,
|
||||||
|
MatInputModule,
|
||||||
|
MatSnackBarModule,
|
||||||
|
MatStepperModule
|
||||||
|
} from '@angular/material';
|
||||||
|
|
||||||
|
import { FontAwesomeModule } from '@fortawesome/angular-fontawesome';
|
||||||
|
|
||||||
|
import { AuthenticationStepComponent } from './authentication-step/authentication-step.component';
|
||||||
|
import { AgreementStepComponent } from './agreement-step/agreement-step.component';
|
||||||
|
import { CreateAccountComponent } from './create-account.component';
|
||||||
|
import { CreateAccountService } from './create-account.service';
|
||||||
|
import { UsernameStepComponent } from './username-step/username-step.component';
|
||||||
|
import { SharedModule } from 'shared';
|
||||||
|
import { SupportStepComponent } from './support-step/support-step.component';
|
||||||
|
import { DoneStepComponent } from './done-step/done-step.component';
|
||||||
|
|
||||||
|
@NgModule({
|
||||||
|
declarations: [
|
||||||
|
CreateAccountComponent,
|
||||||
|
AgreementStepComponent,
|
||||||
|
UsernameStepComponent,
|
||||||
|
AuthenticationStepComponent,
|
||||||
|
SupportStepComponent,
|
||||||
|
DoneStepComponent
|
||||||
|
],
|
||||||
|
imports: [
|
||||||
|
CommonModule,
|
||||||
|
FontAwesomeModule,
|
||||||
|
FlexLayoutModule,
|
||||||
|
FormsModule,
|
||||||
|
MatButtonModule,
|
||||||
|
MatButtonToggleModule,
|
||||||
|
MatCardModule,
|
||||||
|
MatFormFieldModule,
|
||||||
|
MatInputModule,
|
||||||
|
MatSnackBarModule,
|
||||||
|
MatStepperModule,
|
||||||
|
ReactiveFormsModule,
|
||||||
|
SharedModule,
|
||||||
|
],
|
||||||
|
providers: [
|
||||||
|
CreateAccountService
|
||||||
|
]
|
||||||
|
})
|
||||||
|
export class CreateAccountModule { }
|
|
@ -0,0 +1,83 @@
|
||||||
|
import { HttpClient, HttpErrorResponse } from '@angular/common/http';
|
||||||
|
import { Injectable } from '@angular/core';
|
||||||
|
import { FormGroup } from '@angular/forms';
|
||||||
|
import { MatSnackBar } from '@angular/material';
|
||||||
|
|
||||||
|
import { throwError } from 'rxjs';
|
||||||
|
import { catchError } from 'rxjs/operators';
|
||||||
|
|
||||||
|
import { environment } from '../../environments/environment';
|
||||||
|
|
||||||
|
const accountUrl = '/api/account';
|
||||||
|
const agreementUrl = '/api/agreement/';
|
||||||
|
const fiveSeconds = 5000;
|
||||||
|
|
||||||
|
export interface Agreement {
|
||||||
|
type: string;
|
||||||
|
version: string;
|
||||||
|
content: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function storeRedirect() {
|
||||||
|
localStorage.setItem(
|
||||||
|
'redirect',
|
||||||
|
decodeURIComponent(window.location.search).slice(10)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function navigateToLogin(delay: number): void {
|
||||||
|
const redirectURI = localStorage.getItem('redirect');
|
||||||
|
const singleSignOnURI = environment.mycroftUrls.singleSignOn +
|
||||||
|
'/login?redirect=' +
|
||||||
|
redirectURI;
|
||||||
|
localStorage.removeItem('redirect');
|
||||||
|
setTimeout(() => { window.location.assign(singleSignOnURI); }, delay);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Injectable({
|
||||||
|
providedIn: 'root'
|
||||||
|
})
|
||||||
|
export class CreateAccountService {
|
||||||
|
|
||||||
|
constructor(private http: HttpClient, private errorSnackbar: MatSnackBar) {
|
||||||
|
}
|
||||||
|
|
||||||
|
handleError(error: HttpErrorResponse) {
|
||||||
|
if (error.status === 400) {
|
||||||
|
this.errorSnackbar.open(
|
||||||
|
'Account creation failed.',
|
||||||
|
null,
|
||||||
|
{panelClass: 'mycroft-snackbar', duration: fiveSeconds}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
if (error.error instanceof ErrorEvent) {
|
||||||
|
// A client-side or network error occurred. Handle it accordingly.
|
||||||
|
console.error('An error occurred:', error.error.message);
|
||||||
|
} else {
|
||||||
|
// The backend returned an unsuccessful response code.
|
||||||
|
// The response body may contain clues as to what went wrong,
|
||||||
|
console.error(
|
||||||
|
`Backend returned code ${error.status}, ` +
|
||||||
|
`body was: ${error.error}`);
|
||||||
|
}
|
||||||
|
// return an observable with a user-facing error message
|
||||||
|
return throwError(
|
||||||
|
'Something bad happened; please try again later.');
|
||||||
|
}
|
||||||
|
|
||||||
|
getAgreement(agreementType: string) {
|
||||||
|
let url_suffix: string;
|
||||||
|
if (agreementType === 'Terms of Use') {
|
||||||
|
url_suffix = 'terms-of-use';
|
||||||
|
} else {
|
||||||
|
url_suffix = 'privacy-policy';
|
||||||
|
}
|
||||||
|
return this.http.get<Agreement>(agreementUrl + url_suffix);
|
||||||
|
}
|
||||||
|
|
||||||
|
addAccount(newAcctForm: FormGroup) {
|
||||||
|
return this.http.post<any>(accountUrl, newAcctForm.value).pipe(
|
||||||
|
catchError(this.handleError)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,5 @@
|
||||||
|
<mat-card fxLayout="column" fxLayoutAlign="center center" class="mat-elevation-z0">
|
||||||
|
<h1 class="mat-h1">You're Done!</h1>
|
||||||
|
<p class="mat-body">Your account is ready to be created. We are excited to have you as part of our community.</p>
|
||||||
|
<button mat-button>Create Account and Login</button>
|
||||||
|
</mat-card>
|
|
@ -0,0 +1,17 @@
|
||||||
|
@import "~@angular/material/theming";
|
||||||
|
@import "~src/stylesheets/components/buttons";
|
||||||
|
|
||||||
|
mat-card {
|
||||||
|
margin-left: auto;
|
||||||
|
margin-right: auto;
|
||||||
|
max-width: 700px;
|
||||||
|
|
||||||
|
h1 {
|
||||||
|
color: mat-color($mycroft-primary);
|
||||||
|
}
|
||||||
|
|
||||||
|
button {
|
||||||
|
@include action-button-primary;
|
||||||
|
margin-top: 16px;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,17 @@
|
||||||
|
import { Component, Input, OnInit } from '@angular/core';
|
||||||
|
import { FormGroup } from '@angular/forms';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'account-done-step',
|
||||||
|
templateUrl: './done-step.component.html',
|
||||||
|
styleUrls: ['./done-step.component.scss']
|
||||||
|
})
|
||||||
|
export class DoneStepComponent implements OnInit {
|
||||||
|
@Input() newAcctForm: FormGroup;
|
||||||
|
|
||||||
|
constructor() { }
|
||||||
|
|
||||||
|
ngOnInit() {
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,18 @@
|
||||||
|
<mat-card class="mat-elevation-z0">
|
||||||
|
<h2 class="mat-h2">Join Mycroft's Open Dataset</h2>
|
||||||
|
<p *ngFor="let paragraph of openDatasetDescription" class="mat-body">
|
||||||
|
{{paragraph}}
|
||||||
|
</p>
|
||||||
|
<mat-button-toggle-group>
|
||||||
|
<mat-button-toggle (click)="onOptIn()">Opt Into the Mycroft Open Dataset</mat-button-toggle>
|
||||||
|
<mat-button-toggle (click)="onOptOut()">Maybe Later</mat-button-toggle>
|
||||||
|
</mat-button-toggle-group>
|
||||||
|
</mat-card>
|
||||||
|
|
||||||
|
<mat-card class="mat-elevation-z0">
|
||||||
|
<h2 class="mat-h2">Become a Member</h2>
|
||||||
|
<p *ngFor="let paragraph of membershipDescription" class="mat-body">
|
||||||
|
{{paragraph}}
|
||||||
|
</p>
|
||||||
|
<shared-membership-options (selectedMembership)="onMembershipSelection($event)"></shared-membership-options>
|
||||||
|
</mat-card>
|
|
@ -0,0 +1,18 @@
|
||||||
|
@import "~@angular/material/theming";
|
||||||
|
@import "mycroft-colors";
|
||||||
|
@import "~src/stylesheets/components/buttons";
|
||||||
|
|
||||||
|
.mat-h2 {
|
||||||
|
color: mat-color($mycroft-primary);
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
mat-card {
|
||||||
|
margin-left: auto;
|
||||||
|
margin-right: auto;
|
||||||
|
max-width: 1000px;
|
||||||
|
}
|
||||||
|
|
||||||
|
mat-button-toggle-group {
|
||||||
|
@include options-button-group
|
||||||
|
}
|
|
@ -0,0 +1,56 @@
|
||||||
|
import { Component, Input, OnInit } from '@angular/core';
|
||||||
|
import { FormGroup } from '@angular/forms';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'account-support-step',
|
||||||
|
templateUrl: './support-step.component.html',
|
||||||
|
styleUrls: ['./support-step.component.scss']
|
||||||
|
})
|
||||||
|
export class SupportStepComponent implements OnInit {
|
||||||
|
@Input() newAcctForm: FormGroup;
|
||||||
|
public openDatasetDescription: string[];
|
||||||
|
public membershipDescription: string[];
|
||||||
|
|
||||||
|
constructor() { }
|
||||||
|
|
||||||
|
ngOnInit() {
|
||||||
|
this.openDatasetDescription = [
|
||||||
|
'Mycroft\'s voices and services can only improve with your help. ' +
|
||||||
|
'By joining our open dataset, you agree to allow Mycroft AI to collect data related ' +
|
||||||
|
'to your interactions with devices running Mycroft\'s voice assistant software. ' +
|
||||||
|
'We pledge to use this contribution in a responsible way.',
|
||||||
|
'Your data will also be made available to other researchers in the ' +
|
||||||
|
'voice AI space with values that align with our own, like Mozilla Common Voice. ' +
|
||||||
|
'As part of their agreement with Mycroft AI to access this data, they will be ' +
|
||||||
|
'required to honor your request to remove any trace of your contributions if you ' +
|
||||||
|
'decide to opt out.',
|
||||||
|
'You can opt in or out of the open dataset at any time on your account profile page.',
|
||||||
|
'We thank you in advance for helping to improve Mycroft\'s services!'
|
||||||
|
];
|
||||||
|
|
||||||
|
this.membershipDescription = [
|
||||||
|
'Mycroft\'s voice assistant software is open source, which means it is free to use and ' +
|
||||||
|
'the underlying source code is available to the public. Our entire platform is free ' +
|
||||||
|
'of advertisements. The data we collect from those that opt in to our open dataset ' +
|
||||||
|
'is not sold to anyone.',
|
||||||
|
'While many contributions to the Mycroft platform come in the form ' +
|
||||||
|
'of volunteer work by community members, there is also a small team employed by Mycroft AI. ' +
|
||||||
|
'The team curates the software, supports the community and ensures the privacy of your data. ' +
|
||||||
|
'Your donation will help ensure our team can continue providing these services to our ' +
|
||||||
|
'users and community.',
|
||||||
|
'Members will receive benefits like access to premium voices.'
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
onOptIn() {
|
||||||
|
this.newAcctForm.patchValue({support: {openDataset: true}});
|
||||||
|
}
|
||||||
|
|
||||||
|
onOptOut() {
|
||||||
|
this.newAcctForm.patchValue({support: {openDataset: false}});
|
||||||
|
}
|
||||||
|
|
||||||
|
onMembershipSelection(selectedMembership: string) {
|
||||||
|
this.newAcctForm.patchValue({support: {membership: selectedMembership}});
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,11 @@
|
||||||
|
<mat-card class="mat-elevation-z0">
|
||||||
|
<h2 class="mat-h2">What should we call you?</h2>
|
||||||
|
<p class="mat-body">{{whyUsernameParagraph}}</p>
|
||||||
|
<mat-form-field [appearance]="'outline'">
|
||||||
|
<mat-label>Display Name</mat-label>
|
||||||
|
<input matInput required type="text" [formControl]="usernameControl">
|
||||||
|
<mat-error *ngIf="usernameControl.hasError('required')">
|
||||||
|
Display Name is required
|
||||||
|
</mat-error>
|
||||||
|
</mat-form-field>
|
||||||
|
</mat-card>
|
|
@ -0,0 +1,24 @@
|
||||||
|
@import "~@angular/material/theming";
|
||||||
|
@import "mycroft-colors";
|
||||||
|
@import "~src/stylesheets/components/buttons";
|
||||||
|
|
||||||
|
.mat-h2 {
|
||||||
|
color: mat-color($mycroft-primary);
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
mat-card {
|
||||||
|
margin-left: auto;
|
||||||
|
margin-right: auto;
|
||||||
|
|
||||||
|
max-width: 700px;
|
||||||
|
}
|
||||||
|
|
||||||
|
mat-form-field {
|
||||||
|
max-width: 400px;
|
||||||
|
min-width: 280px;
|
||||||
|
}
|
||||||
|
|
||||||
|
mat-button-toggle-group {
|
||||||
|
@include options-button-group
|
||||||
|
}
|
|
@ -0,0 +1,24 @@
|
||||||
|
import { Component, Input, OnInit } from '@angular/core';
|
||||||
|
import { AbstractControl, FormGroup } from '@angular/forms';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'account-username-step',
|
||||||
|
templateUrl: './username-step.component.html',
|
||||||
|
styleUrls: ['./username-step.component.scss']
|
||||||
|
})
|
||||||
|
export class UsernameStepComponent implements OnInit {
|
||||||
|
@Input() newAcctForm: FormGroup;
|
||||||
|
public whyUsernameParagraph: string;
|
||||||
|
public usernameControl: AbstractControl;
|
||||||
|
|
||||||
|
constructor() { }
|
||||||
|
|
||||||
|
ngOnInit() {
|
||||||
|
this.usernameControl = this.newAcctForm.controls.username;
|
||||||
|
this.whyUsernameParagraph = 'In some Mycroft web applications, like our community ' +
|
||||||
|
'forum, you will interact with other community members. In these cases, displaying ' +
|
||||||
|
'your email address to other users is not ideal. Your display name will be used instead ' +
|
||||||
|
'of your email address to identify you on these sites.';
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,39 @@
|
||||||
|
<div mat-dialog-title class="mat-h2-primary">{{dialogTitle}}</div>
|
||||||
|
|
||||||
|
<div mat-dialog-content>
|
||||||
|
<div class="mat-body">{{dialogInstructions}}</div>
|
||||||
|
<mat-radio-group fxLayout="column" [(ngModel)]="dialogData">
|
||||||
|
<ng-container *ngFor="let possibleValue of possibleValues">
|
||||||
|
|
||||||
|
<!-- Radio buttons for pre-defined placements -->
|
||||||
|
<mat-radio-button *ngIf="possibleValue.preDefined" class="predefined-group" [value]="possibleValue.name">
|
||||||
|
{{possibleValue.name}}
|
||||||
|
</mat-radio-button>
|
||||||
|
|
||||||
|
<!-- Radio buttons for user-defined placements -->
|
||||||
|
<div *ngIf="!possibleValue.preDefined" fxLayout="row" fxLayoutAlign="space-between center">
|
||||||
|
<mat-radio-button [value]="possibleValue.name">
|
||||||
|
<mat-form-field [floatLabel]="'never'">
|
||||||
|
<input matInput class="user-defined-group" value="{{possibleValue.name}}">
|
||||||
|
</mat-form-field>
|
||||||
|
</mat-radio-button>
|
||||||
|
<button mat-icon-button [disableRipple]="true">
|
||||||
|
<fa-icon [icon]="deleteIcon"></fa-icon>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</ng-container>
|
||||||
|
|
||||||
|
<!-- Radio button to add a new user-defined group -->
|
||||||
|
<mat-radio-button>
|
||||||
|
<mat-form-field [floatLabel]="'never'">
|
||||||
|
<input matInput placeholder="Add {{dialogTitle}}">
|
||||||
|
</mat-form-field>
|
||||||
|
</mat-radio-button>
|
||||||
|
</mat-radio-group>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div mat-dialog-actions align="end">
|
||||||
|
<button mat-button (click)="onCancelClick()">CANCEL</button>
|
||||||
|
<button mat-button class="attribute-save-button" [mat-dialog-close]="dialogData">SAVE</button>
|
||||||
|
</div>
|
|
@ -0,0 +1,22 @@
|
||||||
|
@import '~@angular/material/theming';
|
||||||
|
@import '~src/stylesheets/mycroft-colors';
|
||||||
|
@import '~src/stylesheets/components/buttons';
|
||||||
|
|
||||||
|
.predefined-group {
|
||||||
|
margin-bottom: 12px;
|
||||||
|
margin-top: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mat-body{
|
||||||
|
margin-bottom: 16px;
|
||||||
|
width: 250px;
|
||||||
|
}
|
||||||
|
|
||||||
|
fa-icon {
|
||||||
|
color: mat-color($mycroft-warn);
|
||||||
|
margin-left: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.attribute-save-button {
|
||||||
|
@include action-button-primary;
|
||||||
|
}
|
|
@ -0,0 +1,34 @@
|
||||||
|
import {Component, Input, OnInit} from '@angular/core';
|
||||||
|
import { MatDialogRef } from '@angular/material';
|
||||||
|
|
||||||
|
import { faTrashAlt } from '@fortawesome/free-solid-svg-icons';
|
||||||
|
|
||||||
|
import { DeviceAttribute } from '../device.service';
|
||||||
|
import { GeographyEditComponent } from './geography/geography-edit.component';
|
||||||
|
import { GroupEditComponent } from './group/group-edit.component';
|
||||||
|
import { PlacementEditComponent } from './placement/placement-edit.component';
|
||||||
|
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'account-device-attribute-edit',
|
||||||
|
templateUrl: './attr-edit.component.html',
|
||||||
|
styleUrls: ['./attr-edit.component.scss']
|
||||||
|
})
|
||||||
|
export class AttrEditComponent implements OnInit {
|
||||||
|
@Input() dialogData: string;
|
||||||
|
@Input() dialogInstructions: string;
|
||||||
|
@Input() dialogRef: MatDialogRef<GeographyEditComponent | GroupEditComponent | PlacementEditComponent>;
|
||||||
|
@Input() dialogTitle: string;
|
||||||
|
@Input() possibleValues: DeviceAttribute[];
|
||||||
|
public deleteIcon = faTrashAlt;
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
}
|
||||||
|
|
||||||
|
ngOnInit() {
|
||||||
|
}
|
||||||
|
|
||||||
|
onCancelClick(): void {
|
||||||
|
this.dialogRef.close();
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,13 @@
|
||||||
|
<mat-form-field [appearance]="'outline'" (click)="onClick()">
|
||||||
|
<mat-label>{{label}}</mat-label>
|
||||||
|
<div fxLayout="row" fxLayoutAlign="none center">
|
||||||
|
<input
|
||||||
|
matInput
|
||||||
|
[readonly]="true"
|
||||||
|
type="text"
|
||||||
|
value="{{value.name}}"
|
||||||
|
>
|
||||||
|
<fa-icon matSuffix [icon]="editIcon" style="font-size: 16px;"></fa-icon>
|
||||||
|
</div>
|
||||||
|
<mat-hint>{{hint}}</mat-hint>
|
||||||
|
</mat-form-field>
|
|
@ -0,0 +1,9 @@
|
||||||
|
mat-form-field {
|
||||||
|
margin-bottom: 20px;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
fa-icon {
|
||||||
|
padding-right: 10px
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,43 @@
|
||||||
|
import { Component, Input, OnInit } from '@angular/core';
|
||||||
|
import { MatDialog } from '@angular/material';
|
||||||
|
|
||||||
|
import { faCaretRight } from '@fortawesome/free-solid-svg-icons';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'account-device-attribute-view',
|
||||||
|
templateUrl: './attr-view.component.html',
|
||||||
|
styleUrls: ['./attr-view.component.scss']
|
||||||
|
})
|
||||||
|
export class AttrViewComponent implements OnInit {
|
||||||
|
@Input() editDialog: any;
|
||||||
|
@Input() hint: string;
|
||||||
|
@Input() label: string;
|
||||||
|
@Input() possibleValues: any[];
|
||||||
|
@Input() value: any;
|
||||||
|
public editIcon = faCaretRight;
|
||||||
|
|
||||||
|
constructor(private dialog: MatDialog) {
|
||||||
|
}
|
||||||
|
|
||||||
|
ngOnInit() {
|
||||||
|
}
|
||||||
|
|
||||||
|
onClick() {
|
||||||
|
const dialogRef = this.dialog.open(this.editDialog, { data: this.value.name });
|
||||||
|
dialogRef.afterClosed().subscribe(
|
||||||
|
(result) => { this.updateDevice(result); }
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
updateDevice(newValue: string) {
|
||||||
|
if (newValue) {
|
||||||
|
this.possibleValues.forEach(
|
||||||
|
(value) => {
|
||||||
|
if (value.name === newValue) {
|
||||||
|
this.value = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,43 @@
|
||||||
|
<account-device-attribute-edit
|
||||||
|
[dialogData]="data"
|
||||||
|
[dialogInstructions]="dialogInstructions"
|
||||||
|
[dialogRef]="dialogRef"
|
||||||
|
[dialogTitle]="'Geography'"
|
||||||
|
[possibleValues]="deviceGeographies"
|
||||||
|
>
|
||||||
|
</account-device-attribute-edit>
|
||||||
|
<!--<div mat-dialog-title class="mat-h2-primary">Geography</div>-->
|
||||||
|
|
||||||
|
<!--<div mat-dialog-content>-->
|
||||||
|
<!--<div class="mat-body">-->
|
||||||
|
<!--Groups are useful to organize multiple devices. You can reuse device names if they are in different groups.-->
|
||||||
|
<!--</div>-->
|
||||||
|
<!--<mat-radio-group fxLayout="column" [(ngModel)]="data">-->
|
||||||
|
<!--<ng-container *ngFor="let geo of deviceGeographies">-->
|
||||||
|
<!--<!– Radio buttons for user-defined groups –>-->
|
||||||
|
<!--<div fxLayout="row" fxLayoutAlign="space-between center">-->
|
||||||
|
<!--<mat-radio-button [value]="geo.name">-->
|
||||||
|
<!--<mat-form-field [floatLabel]="'never'">-->
|
||||||
|
<!--<input matInput value="{{geo.name}}">-->
|
||||||
|
<!--</mat-form-field>-->
|
||||||
|
<!--</mat-radio-button>-->
|
||||||
|
<!--<button mat-icon-button [disableRipple]="true">-->
|
||||||
|
<!--<fa-icon class="danger-icon" [icon]="deleteIcon"></fa-icon>-->
|
||||||
|
<!--</button>-->
|
||||||
|
<!--</div>-->
|
||||||
|
|
||||||
|
<!--</ng-container>-->
|
||||||
|
|
||||||
|
<!--<!– Radio button to add a new user-defined group –>-->
|
||||||
|
<!--<mat-radio-button>-->
|
||||||
|
<!--<mat-form-field [floatLabel]="'never'">-->
|
||||||
|
<!--<input matInput placeholder="Add Geographic Location">-->
|
||||||
|
<!--</mat-form-field>-->
|
||||||
|
<!--</mat-radio-button>-->
|
||||||
|
<!--</mat-radio-group>-->
|
||||||
|
<!--</div>-->
|
||||||
|
|
||||||
|
<!--<div mat-dialog-actions align="end">-->
|
||||||
|
<!--<button mat-button (click)="onCancelClick()">CANCEL</button>-->
|
||||||
|
<!--<button mat-button [mat-dialog-close]="data" class="action-button">SAVE</button>-->
|
||||||
|
<!--</div>-->
|
|
@ -0,0 +1,25 @@
|
||||||
|
import { Component, Inject, OnInit } from '@angular/core';
|
||||||
|
import { MatDialogRef, MAT_DIALOG_DATA } from '@angular/material';
|
||||||
|
|
||||||
|
import { DeviceAttribute, DeviceService} from '../../device.service';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'account-device-geography-edit',
|
||||||
|
templateUrl: './geography-edit.component.html',
|
||||||
|
styleUrls: ['./geography-edit.component.scss']
|
||||||
|
})
|
||||||
|
export class GeographyEditComponent implements OnInit {
|
||||||
|
public deviceGeographies: DeviceAttribute[];
|
||||||
|
public dialogInstructions = '';
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
private deviceService: DeviceService,
|
||||||
|
public dialogRef: MatDialogRef<GeographyEditComponent>,
|
||||||
|
@Inject(MAT_DIALOG_DATA) public data: string) {
|
||||||
|
}
|
||||||
|
|
||||||
|
ngOnInit() {
|
||||||
|
this.deviceGeographies = this.deviceService.deviceGeographies;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,9 @@
|
||||||
|
<account-device-attribute-view
|
||||||
|
[editDialog]="dialog"
|
||||||
|
[hint]="'Country, postal code, time zone'"
|
||||||
|
[label]="'Geography'"
|
||||||
|
[possibleValues]="deviceGeographies"
|
||||||
|
[value]="device.location"
|
||||||
|
>
|
||||||
|
</account-device-attribute-view>
|
||||||
|
|
|
@ -0,0 +1,22 @@
|
||||||
|
import { Component, Input, OnInit } from '@angular/core';
|
||||||
|
|
||||||
|
import { Device, DeviceAttribute, DeviceService } from '../../device.service';
|
||||||
|
import { GeographyEditComponent } from './geography-edit.component';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'account-device-geography-view',
|
||||||
|
templateUrl: './geography-view.component.html',
|
||||||
|
styleUrls: ['./geography-view.component.scss']
|
||||||
|
})
|
||||||
|
export class GeographyViewComponent implements OnInit {
|
||||||
|
@Input() device: Device;
|
||||||
|
public deviceGeographies: DeviceAttribute[];
|
||||||
|
public dialog = GeographyEditComponent;
|
||||||
|
|
||||||
|
constructor( private service: DeviceService) {
|
||||||
|
}
|
||||||
|
|
||||||
|
ngOnInit() {
|
||||||
|
this.deviceGeographies = this.service.deviceGeographies;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,8 @@
|
||||||
|
<account-device-attribute-edit
|
||||||
|
[dialogData]="data"
|
||||||
|
[dialogInstructions]="dialogInstructions"
|
||||||
|
[dialogRef]="dialogRef"
|
||||||
|
[dialogTitle]="'Group'"
|
||||||
|
[possibleValues]="deviceGroups"
|
||||||
|
>
|
||||||
|
</account-device-attribute-edit>
|
|
@ -0,0 +1,25 @@
|
||||||
|
import { Component, Inject, OnInit } from '@angular/core';
|
||||||
|
import { MatDialogRef, MAT_DIALOG_DATA } from '@angular/material';
|
||||||
|
|
||||||
|
import { DeviceAttribute, DeviceService} from '../../device.service';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'account-device-group-edit',
|
||||||
|
templateUrl: './group-edit.component.html',
|
||||||
|
styleUrls: ['./group-edit.component.scss']
|
||||||
|
})
|
||||||
|
export class GroupEditComponent implements OnInit {
|
||||||
|
public deviceGroups: DeviceAttribute[];
|
||||||
|
public dialogInstructions = 'Groups are useful to organize multiple ' +
|
||||||
|
'devices. You can reuse device names if they are in different groups.';
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
private deviceService: DeviceService,
|
||||||
|
public dialogRef: MatDialogRef<GroupEditComponent>,
|
||||||
|
@Inject(MAT_DIALOG_DATA) public data: DeviceAttribute) {
|
||||||
|
}
|
||||||
|
|
||||||
|
ngOnInit() {
|
||||||
|
this.deviceGroups = this.deviceService.deviceGroups;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,9 @@
|
||||||
|
<account-device-attribute-view
|
||||||
|
[editDialog]="dialog"
|
||||||
|
[hint]="'Mechanism to categorize devices'"
|
||||||
|
[label]="'Group'"
|
||||||
|
[possibleValues]="deviceGroups"
|
||||||
|
[value]="device.group"
|
||||||
|
>
|
||||||
|
</account-device-attribute-view>
|
||||||
|
|
|
@ -0,0 +1,22 @@
|
||||||
|
import { Component, Input, OnInit } from '@angular/core';
|
||||||
|
|
||||||
|
import { Device, DeviceAttribute, DeviceService } from '../../device.service';
|
||||||
|
import { GroupEditComponent } from './group-edit.component';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'account-device-group-view',
|
||||||
|
templateUrl: './group-view.component.html',
|
||||||
|
styleUrls: ['./group-view.component.scss']
|
||||||
|
})
|
||||||
|
export class GroupViewComponent implements OnInit {
|
||||||
|
@Input() device: Device;
|
||||||
|
public deviceGroups: DeviceAttribute[];
|
||||||
|
public dialog = GroupEditComponent;
|
||||||
|
|
||||||
|
constructor( private service: DeviceService) {
|
||||||
|
}
|
||||||
|
|
||||||
|
ngOnInit() {
|
||||||
|
this.deviceGroups = this.service.deviceGroups;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,8 @@
|
||||||
|
<account-device-attribute-edit
|
||||||
|
[dialogData]="data"
|
||||||
|
[dialogInstructions]="dialogInstructions"
|
||||||
|
[dialogRef]="dialogRef"
|
||||||
|
[dialogTitle]="'Placement'"
|
||||||
|
[possibleValues]="devicePlacements"
|
||||||
|
>
|
||||||
|
</account-device-attribute-edit>
|
|
@ -0,0 +1,26 @@
|
||||||
|
import { Component, Inject, OnInit } from '@angular/core';
|
||||||
|
import { MatDialogRef, MAT_DIALOG_DATA } from '@angular/material';
|
||||||
|
|
||||||
|
import { DeviceAttribute, DeviceService} from '../../device.service';
|
||||||
|
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'account-device-placement-edit',
|
||||||
|
templateUrl: './placement-edit.component.html',
|
||||||
|
styleUrls: ['./placement-edit.component.scss']
|
||||||
|
})
|
||||||
|
export class PlacementEditComponent implements OnInit {
|
||||||
|
public devicePlacements: DeviceAttribute[];
|
||||||
|
public dialogInstructions = 'You can optionally indicate where a device is ' +
|
||||||
|
'placed within a location. Field is informational only.';
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
private deviceService: DeviceService,
|
||||||
|
public dialogRef: MatDialogRef<PlacementEditComponent>,
|
||||||
|
@Inject(MAT_DIALOG_DATA) public data: string) {
|
||||||
|
}
|
||||||
|
|
||||||
|
ngOnInit() {
|
||||||
|
this.devicePlacements = this.deviceService.devicePlacements;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,9 @@
|
||||||
|
<account-device-attribute-view
|
||||||
|
[editDialog]="dialog"
|
||||||
|
[hint]="'Where a device is placed within a location'"
|
||||||
|
[label]="'Placement'"
|
||||||
|
[possibleValues]="devicePlacements"
|
||||||
|
[value]="device.placement"
|
||||||
|
>
|
||||||
|
</account-device-attribute-view>
|
||||||
|
|
|
@ -0,0 +1,22 @@
|
||||||
|
import { Component, Input, OnInit } from '@angular/core';
|
||||||
|
|
||||||
|
import {Device, DeviceAttribute, DeviceService} from '../../device.service';
|
||||||
|
import { PlacementEditComponent } from './placement-edit.component';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'account-device-placement-view',
|
||||||
|
templateUrl: './placement-view.component.html',
|
||||||
|
styleUrls: ['./placement-view.component.scss']
|
||||||
|
})
|
||||||
|
export class PlacementViewComponent implements OnInit {
|
||||||
|
@Input() device: Device;
|
||||||
|
public devicePlacements: DeviceAttribute[];
|
||||||
|
public dialog = PlacementEditComponent;
|
||||||
|
|
||||||
|
constructor( private service: DeviceService) {
|
||||||
|
}
|
||||||
|
|
||||||
|
ngOnInit() {
|
||||||
|
this.devicePlacements = this.service.devicePlacements;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,8 @@
|
||||||
|
<account-device-attribute-edit
|
||||||
|
[dialogData]="data"
|
||||||
|
[dialogInstructions]="dialogInstructions"
|
||||||
|
[dialogRef]="dialogRef"
|
||||||
|
[dialogTitle]="'Voice'"
|
||||||
|
[possibleValues]="deviceVoices"
|
||||||
|
>
|
||||||
|
</account-device-attribute-edit>
|
|
@ -0,0 +1,27 @@
|
||||||
|
import { Component, Inject, OnInit } from '@angular/core';
|
||||||
|
import { MatDialogRef, MAT_DIALOG_DATA } from '@angular/material';
|
||||||
|
|
||||||
|
import { DeviceAttribute, DeviceService} from '../../device.service';
|
||||||
|
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'account-device-voice-edit',
|
||||||
|
templateUrl: './voice-edit.component.html',
|
||||||
|
styleUrls: ['./voice-edit.component.scss']
|
||||||
|
})
|
||||||
|
export class VoiceEditComponent implements OnInit {
|
||||||
|
public deviceVoices: DeviceAttribute[];
|
||||||
|
public dialogInstructions = 'Mycroft\'s voice technology is rapidly ' +
|
||||||
|
'evolving. Local voices guarantee the most privacy. Premium voices ' +
|
||||||
|
'are more natural but require an internet connection.';
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
private deviceService: DeviceService,
|
||||||
|
public dialogRef: MatDialogRef<VoiceEditComponent>,
|
||||||
|
@Inject(MAT_DIALOG_DATA) public data: string) {
|
||||||
|
}
|
||||||
|
|
||||||
|
ngOnInit() {
|
||||||
|
this.deviceVoices = this.deviceService.deviceVoices;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,9 @@
|
||||||
|
<account-device-attribute-view
|
||||||
|
[editDialog]="dialog"
|
||||||
|
[hint]="'Select the voice used by your device'"
|
||||||
|
[label]="'Voice'"
|
||||||
|
[possibleValues]="deviceVoices"
|
||||||
|
[value]="device.voice"
|
||||||
|
>
|
||||||
|
</account-device-attribute-view>
|
||||||
|
|
|
@ -0,0 +1,22 @@
|
||||||
|
import { Component, Input, OnInit } from '@angular/core';
|
||||||
|
|
||||||
|
import {Device, DeviceAttribute, DeviceService} from '../../device.service';
|
||||||
|
import { VoiceEditComponent } from './voice-edit.component';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'account-device-voice-view',
|
||||||
|
templateUrl: './voice-view.component.html',
|
||||||
|
styleUrls: ['./voice-view.component.scss']
|
||||||
|
})
|
||||||
|
export class VoiceViewComponent implements OnInit {
|
||||||
|
@Input() device: Device;
|
||||||
|
public deviceVoices: DeviceAttribute[];
|
||||||
|
public dialog = VoiceEditComponent;
|
||||||
|
|
||||||
|
constructor( private service: DeviceService) {
|
||||||
|
}
|
||||||
|
|
||||||
|
ngOnInit() {
|
||||||
|
this.deviceVoices = this.service.deviceVoices;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,8 @@
|
||||||
|
<account-device-attribute-edit
|
||||||
|
[dialogData]="data"
|
||||||
|
[dialogInstructions]="dialogInstructions"
|
||||||
|
[dialogRef]="dialogRef"
|
||||||
|
[dialogTitle]="'Wake Word'"
|
||||||
|
[possibleValues]="deviceWakeWords"
|
||||||
|
>
|
||||||
|
</account-device-attribute-edit>
|
|
@ -0,0 +1,27 @@
|
||||||
|
import { Component, Inject, OnInit } from '@angular/core';
|
||||||
|
import { MatDialogRef, MAT_DIALOG_DATA } from '@angular/material';
|
||||||
|
|
||||||
|
import { DeviceAttribute, DeviceService} from '../../device.service';
|
||||||
|
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'account-device-wake-word-edit',
|
||||||
|
templateUrl: './wake-word-edit.component.html',
|
||||||
|
styleUrls: ['./wake-word-edit.component.scss']
|
||||||
|
})
|
||||||
|
export class WakeWordEditComponent implements OnInit {
|
||||||
|
public deviceWakeWords: DeviceAttribute[];
|
||||||
|
public dialogInstructions = 'Mycroft\'s voice technology is rapidly ' +
|
||||||
|
'evolving. Local voices guarantee the most privacy. Premium voices ' +
|
||||||
|
'are more natural but require an internet connection.';
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
private deviceService: DeviceService,
|
||||||
|
public dialogRef: MatDialogRef<WakeWordEditComponent>,
|
||||||
|
@Inject(MAT_DIALOG_DATA) public data: string) {
|
||||||
|
}
|
||||||
|
|
||||||
|
ngOnInit() {
|
||||||
|
this.deviceWakeWords = this.deviceService.deviceWakeWords;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,9 @@
|
||||||
|
<account-device-attribute-view
|
||||||
|
[editDialog]="dialog"
|
||||||
|
[hint]="'Select the wake word used by your device'"
|
||||||
|
[label]="'Wake Word'"
|
||||||
|
[possibleValues]="deviceWakeWords"
|
||||||
|
[value]="device.wakeWord"
|
||||||
|
>
|
||||||
|
</account-device-attribute-view>
|
||||||
|
|
|
@ -0,0 +1,22 @@
|
||||||
|
import { Component, Input, OnInit } from '@angular/core';
|
||||||
|
|
||||||
|
import {Device, DeviceAttribute, DeviceService} from '../../device.service';
|
||||||
|
import { WakeWordEditComponent} from './wake-word-edit.component';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'account-device-wake-word-view',
|
||||||
|
templateUrl: './wake-word-view.component.html',
|
||||||
|
styleUrls: ['./wake-word-view.component.scss']
|
||||||
|
})
|
||||||
|
export class WakeWordViewComponent implements OnInit {
|
||||||
|
@Input() device: Device;
|
||||||
|
public deviceWakeWords: DeviceAttribute[];
|
||||||
|
public dialog = WakeWordEditComponent;
|
||||||
|
|
||||||
|
constructor( private service: DeviceService) {
|
||||||
|
}
|
||||||
|
|
||||||
|
ngOnInit() {
|
||||||
|
this.deviceWakeWords = this.service.deviceVoices;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,67 @@
|
||||||
|
<div id="add-device-button" fxLayout="row" fxLayoutAlign="start center">
|
||||||
|
<img src="../assets/generic-device-icon-blue.svg">
|
||||||
|
<span fxFlex class="mat-h2">ADD DEVICE</span>
|
||||||
|
<fa-icon class="mat-h2" [icon]="addIcon"></fa-icon>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Device listing - show summary in expansion panel header and editable fields in expansion panel detail -->
|
||||||
|
<mat-expansion-panel *ngFor="let device of devices">
|
||||||
|
|
||||||
|
<!-- Put the platform icon, device name and device placement in the panel header -->
|
||||||
|
<mat-expansion-panel-header [expandedHeight]="'100px'" [collapsedHeight]="'100px'">
|
||||||
|
<div fxLayout="row" fxLayoutAlign="start" fxLayoutGap="16px">
|
||||||
|
<img [src]="getDeviceIcon(device)"/>
|
||||||
|
<div>
|
||||||
|
<div class="mat-h2">{{device.name}}</div>
|
||||||
|
<div class="mat-subheader">{{device.placement.name}}</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</mat-expansion-panel-header>
|
||||||
|
|
||||||
|
<div id="device-settings" fxLayout.xs="row wrap">
|
||||||
|
<div fxLayout="row wrap" fxLayoutGap.gt-xs="16px">
|
||||||
|
<!-- Navigation to skill settings for this device. -->
|
||||||
|
<mat-form-field fxFlex.xl=40 fxFlex.lt-xl [appearance]="'outline'">
|
||||||
|
<mat-label>Name</mat-label>
|
||||||
|
<input
|
||||||
|
id="deviceName"
|
||||||
|
matInput
|
||||||
|
name="deviceName"
|
||||||
|
required
|
||||||
|
type="text"
|
||||||
|
value="{{device.name}}"
|
||||||
|
>
|
||||||
|
<mat-hint>Must be unique within a device group (if defined)</mat-hint>
|
||||||
|
</mat-form-field>
|
||||||
|
|
||||||
|
<account-device-group-view fxFlex.xl=40 fxFlex.lt-xl [device]="device"></account-device-group-view>
|
||||||
|
<account-device-geography-view fxFlex.xl=40 fxFlex.lt-xl [device]="device"></account-device-geography-view>
|
||||||
|
<account-device-placement-view fxFlex.xl=40 fxFlex.lt-xl [device]="device"></account-device-placement-view>
|
||||||
|
<account-device-voice-view fxFlex.xl=40 fxFlex.lt-xl [device]="device"></account-device-voice-view>
|
||||||
|
<account-device-wake-word-view fxFlex.xl=40 fxFlex.lt-xl [device]="device"></account-device-wake-word-view>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div fxFlex.xl="25" fxFlex.lt-xl>
|
||||||
|
<div fxLayout="column">
|
||||||
|
<!-- Static fields that display platform, software version and hardware version -->
|
||||||
|
<div>
|
||||||
|
<div *ngFor="let staticData of defineStaticDeviceFields(device)">
|
||||||
|
<span class="mat-body">{{staticData.name}}: </span>
|
||||||
|
<span class="mat-body-primary">{{staticData.value}}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Last but not least, the delete device button -->
|
||||||
|
<button mat-flat-button color="primary" class="settings-button">
|
||||||
|
<fa-icon [icon]="settingsIcon"></fa-icon>
|
||||||
|
SKILL SETTINGS
|
||||||
|
</button>
|
||||||
|
|
||||||
|
<button mat-flat-button color="warn" class="delete-button" (click)="onRemovalClick(device)">
|
||||||
|
<fa-icon [icon]="deleteIcon"></fa-icon>
|
||||||
|
REMOVE DEVICE
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</mat-expansion-panel>
|
|
@ -0,0 +1,77 @@
|
||||||
|
@import '~@angular/material/theming';
|
||||||
|
@import '~src/stylesheets/mycroft-colors';
|
||||||
|
@import '~src/stylesheets/components/buttons';
|
||||||
|
|
||||||
|
@mixin panel-defaults {
|
||||||
|
border-radius: 12px;
|
||||||
|
max-width: 1000px;
|
||||||
|
min-width: 250px;
|
||||||
|
margin-left: auto;
|
||||||
|
margin-right: auto;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#add-device-button {
|
||||||
|
@include action-button-primary;
|
||||||
|
@include panel-defaults;
|
||||||
|
border-radius: 12px;
|
||||||
|
cursor: pointer;
|
||||||
|
height: 50px;
|
||||||
|
margin-top: 32px;
|
||||||
|
|
||||||
|
img {
|
||||||
|
height: 32px;
|
||||||
|
margin-left: 16px;
|
||||||
|
}
|
||||||
|
.mat-h2 {
|
||||||
|
margin-bottom: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
fa-icon {
|
||||||
|
color: mat-color($mycroft-accent, 'A200');
|
||||||
|
margin-right: 16px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
mat-expansion-panel {
|
||||||
|
@include panel-defaults;
|
||||||
|
margin-top: 16px;
|
||||||
|
|
||||||
|
button {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
fa-icon {
|
||||||
|
padding-right: 10px
|
||||||
|
}
|
||||||
|
|
||||||
|
img {
|
||||||
|
height: 60px;
|
||||||
|
}
|
||||||
|
|
||||||
|
mat-form-field {
|
||||||
|
margin-bottom: 20px;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
//.delete-button {
|
||||||
|
// margin-top: 20px;
|
||||||
|
//}
|
||||||
|
|
||||||
|
.mat-body-primary {
|
||||||
|
margin-bottom: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mat-h2 {
|
||||||
|
color: mat-color($mycroft-primary);
|
||||||
|
margin-bottom: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mat-subheader {
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.settings-button {
|
||||||
|
margin-bottom: 20px;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,57 @@
|
||||||
|
import { Component, OnInit } from '@angular/core';
|
||||||
|
import { MatDialog } from '@angular/material';
|
||||||
|
|
||||||
|
import { faCog, faPlus, faTrash } from '@fortawesome/free-solid-svg-icons';
|
||||||
|
|
||||||
|
import { DeviceService, Device } from '../device.service';
|
||||||
|
import { RemoveComponent } from '../remove/remove.component';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'account-device-list',
|
||||||
|
templateUrl: './device-list.component.html',
|
||||||
|
styleUrls: ['./device-list.component.scss']
|
||||||
|
})
|
||||||
|
export class DeviceListComponent implements OnInit {
|
||||||
|
public addIcon = faPlus;
|
||||||
|
public deleteIcon = faTrash;
|
||||||
|
public devices: Device[];
|
||||||
|
public platforms = {
|
||||||
|
'mark-one': {icon: '../assets/mark-1-icon.svg', displayName: 'Mark I'},
|
||||||
|
'mark-two': {icon: '../assets/mark-2-icon.svg', displayName: 'Mark II'},
|
||||||
|
'picroft': {icon: '../assets/picroft-icon.svg', displayName: 'Picroft'},
|
||||||
|
'kde': {icon: '../assets/kde-icon.svg', displayName: 'KDE'}
|
||||||
|
};
|
||||||
|
private selectedDevice: Device;
|
||||||
|
public settingsIcon = faCog;
|
||||||
|
|
||||||
|
constructor(public dialog: MatDialog, private deviceService: DeviceService) { }
|
||||||
|
|
||||||
|
ngOnInit() {
|
||||||
|
this.devices = this.deviceService.devices;
|
||||||
|
}
|
||||||
|
|
||||||
|
onRemovalClick (device: Device) {
|
||||||
|
const removalDialogRef = this.dialog.open(RemoveComponent, {data: false});
|
||||||
|
this.selectedDevice = device;
|
||||||
|
removalDialogRef.afterClosed().subscribe(
|
||||||
|
(result) => {
|
||||||
|
if (result) { this.deviceService.deleteDevice(device); }
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
defineStaticDeviceFields(device: Device) {
|
||||||
|
const knownPlatform = this.platforms[device.platform];
|
||||||
|
return [
|
||||||
|
{name: 'Platform', value: knownPlatform ? knownPlatform.displayName : device.platform},
|
||||||
|
{name: 'Core Version', value: device.coreVersion},
|
||||||
|
{name: 'Enclosure Version', value: device.enclosureVersion}
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
getDeviceIcon(device: Device) {
|
||||||
|
const knownPlatform = this.platforms[device.platform];
|
||||||
|
// TODO: get unknown product icon from design team.
|
||||||
|
return knownPlatform ? knownPlatform.icon : '../assets/mark-1-icon.svg';
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,10 @@
|
||||||
|
<div fxLayout="row" fxLayoutAlign="center center">
|
||||||
|
<mat-tab-group mat-stretch-tabs>
|
||||||
|
<mat-tab [label]="'Devices'">
|
||||||
|
<account-device-list></account-device-list>
|
||||||
|
</mat-tab>
|
||||||
|
<mat-tab [label]="'Preferences'">
|
||||||
|
<account-device-preferences></account-device-preferences>
|
||||||
|
</mat-tab>
|
||||||
|
</mat-tab-group>
|
||||||
|
</div>
|
|
@ -0,0 +1 @@
|
||||||
|
|
|
@ -0,0 +1,56 @@
|
||||||
|
import { Component, OnInit } from '@angular/core';
|
||||||
|
import { MatDialog } from '@angular/material';
|
||||||
|
|
||||||
|
import { faPlus, faTrash } from '@fortawesome/free-solid-svg-icons';
|
||||||
|
|
||||||
|
import { DeviceService, Device } from './device.service';
|
||||||
|
import { RemoveComponent } from './remove/remove.component';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'account-device',
|
||||||
|
templateUrl: './device.component.html',
|
||||||
|
styleUrls: ['./device.component.scss']
|
||||||
|
})
|
||||||
|
export class DeviceComponent implements OnInit {
|
||||||
|
public addIcon = faPlus;
|
||||||
|
public deleteIcon = faTrash;
|
||||||
|
public devices: Device[];
|
||||||
|
public platforms = {
|
||||||
|
'mark-one': {icon: '../assets/mark-1-icon.svg', displayName: 'Mark I'},
|
||||||
|
'mark-two': {icon: '../assets/mark-2-icon.svg', displayName: 'Mark II'},
|
||||||
|
'picroft': {icon: '../assets/picroft-icon.svg', displayName: 'Picroft'},
|
||||||
|
'kde': {icon: '../assets/kde-icon.svg', displayName: 'KDE'}
|
||||||
|
};
|
||||||
|
private selectedDevice: Device;
|
||||||
|
|
||||||
|
constructor(public dialog: MatDialog, private deviceService: DeviceService) { }
|
||||||
|
|
||||||
|
ngOnInit() {
|
||||||
|
this.devices = this.deviceService.devices;
|
||||||
|
}
|
||||||
|
|
||||||
|
onRemovalClick (device: Device) {
|
||||||
|
const removalDialogRef = this.dialog.open(RemoveComponent, {data: false});
|
||||||
|
this.selectedDevice = device;
|
||||||
|
removalDialogRef.afterClosed().subscribe(
|
||||||
|
(result) => {
|
||||||
|
if (result) { this.deviceService.deleteDevice(device); }
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
defineStaticDeviceFields(device: Device) {
|
||||||
|
const knownPlatform = this.platforms[device.platform];
|
||||||
|
return [
|
||||||
|
{name: 'Platform', value: knownPlatform ? knownPlatform.displayName : device.platform},
|
||||||
|
{name: 'Core Version', value: device.coreVersion},
|
||||||
|
{name: 'Enclosure Version', value: device.enclosureVersion}
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
getDeviceIcon(device: Device) {
|
||||||
|
const knownPlatform = this.platforms[device.platform];
|
||||||
|
// TODO: get unknown product icon from design team.
|
||||||
|
return knownPlatform ? knownPlatform.icon : '../assets/mark-1-icon.svg';
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,91 @@
|
||||||
|
import { NgModule } from '@angular/core';
|
||||||
|
import { CommonModule } from '@angular/common';
|
||||||
|
import { DragDropModule } from '@angular/cdk/drag-drop';
|
||||||
|
import { FlexLayoutModule } from '@angular/flex-layout';
|
||||||
|
import { FormsModule } from '@angular/forms';
|
||||||
|
import {
|
||||||
|
MatButtonModule,
|
||||||
|
MatButtonToggleModule,
|
||||||
|
MatCardModule,
|
||||||
|
MatDialogModule,
|
||||||
|
MatExpansionModule,
|
||||||
|
MatFormFieldModule,
|
||||||
|
MatInputModule,
|
||||||
|
MatRadioModule,
|
||||||
|
MatSelectModule,
|
||||||
|
MatSlideToggleModule,
|
||||||
|
MatTabsModule,
|
||||||
|
MatToolbarModule
|
||||||
|
} from '@angular/material';
|
||||||
|
|
||||||
|
import { FontAwesomeModule } from '@fortawesome/angular-fontawesome';
|
||||||
|
|
||||||
|
import { AttrEditComponent } from './attribute/attr-edit.component';
|
||||||
|
import { AttrViewComponent } from './attribute/attr-view.component';
|
||||||
|
import { DeviceComponent } from './device.component';
|
||||||
|
import { DeviceListComponent } from './device-list/device-list.component';
|
||||||
|
import { DeviceService } from './device.service';
|
||||||
|
import { GeographyEditComponent } from './attribute/geography/geography-edit.component';
|
||||||
|
import { GeographyViewComponent } from './attribute/geography/geography-view.component';
|
||||||
|
import { GroupEditComponent } from './attribute/group/group-edit.component';
|
||||||
|
import { GroupViewComponent } from './attribute/group/group-view.component';
|
||||||
|
import { PlacementEditComponent } from './attribute/placement/placement-edit.component';
|
||||||
|
import { PlacementViewComponent } from './attribute/placement/placement-view.component';
|
||||||
|
import { RemoveComponent } from './remove/remove.component';
|
||||||
|
import { VoiceEditComponent } from './attribute/voice/voice-edit.component';
|
||||||
|
import { VoiceViewComponent } from './attribute/voice/voice-view.component';
|
||||||
|
import { PreferencesComponent } from './preferences/preferences.component';
|
||||||
|
import { WakeWordEditComponent } from './attribute/wake-word/wake-word-edit.component';
|
||||||
|
import { WakeWordViewComponent } from './attribute/wake-word/wake-word-view.component';
|
||||||
|
|
||||||
|
@NgModule({
|
||||||
|
declarations: [
|
||||||
|
AttrEditComponent,
|
||||||
|
AttrViewComponent,
|
||||||
|
DeviceComponent,
|
||||||
|
DeviceListComponent,
|
||||||
|
GeographyEditComponent,
|
||||||
|
GeographyViewComponent,
|
||||||
|
GroupEditComponent,
|
||||||
|
GroupViewComponent,
|
||||||
|
PlacementEditComponent,
|
||||||
|
PlacementViewComponent,
|
||||||
|
RemoveComponent,
|
||||||
|
VoiceEditComponent,
|
||||||
|
VoiceViewComponent,
|
||||||
|
PreferencesComponent,
|
||||||
|
WakeWordEditComponent,
|
||||||
|
WakeWordViewComponent
|
||||||
|
],
|
||||||
|
entryComponents: [
|
||||||
|
GeographyEditComponent,
|
||||||
|
GroupEditComponent,
|
||||||
|
PlacementEditComponent,
|
||||||
|
RemoveComponent,
|
||||||
|
VoiceEditComponent,
|
||||||
|
WakeWordEditComponent
|
||||||
|
],
|
||||||
|
imports: [
|
||||||
|
CommonModule,
|
||||||
|
DragDropModule,
|
||||||
|
FlexLayoutModule,
|
||||||
|
FontAwesomeModule,
|
||||||
|
FormsModule,
|
||||||
|
MatButtonModule,
|
||||||
|
MatButtonToggleModule,
|
||||||
|
MatCardModule,
|
||||||
|
MatDialogModule,
|
||||||
|
MatExpansionModule,
|
||||||
|
MatFormFieldModule,
|
||||||
|
MatInputModule,
|
||||||
|
MatRadioModule,
|
||||||
|
MatSelectModule,
|
||||||
|
MatSlideToggleModule,
|
||||||
|
MatTabsModule,
|
||||||
|
MatToolbarModule
|
||||||
|
],
|
||||||
|
providers: [
|
||||||
|
DeviceService
|
||||||
|
]
|
||||||
|
})
|
||||||
|
export class DeviceModule { }
|
|
@ -0,0 +1,113 @@
|
||||||
|
import { Injectable } from '@angular/core';
|
||||||
|
|
||||||
|
export interface DeviceAttribute {
|
||||||
|
id?: string;
|
||||||
|
name: string;
|
||||||
|
preDefined: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface Device {
|
||||||
|
coreVersion: string;
|
||||||
|
enclosureVersion: string;
|
||||||
|
group: DeviceAttribute;
|
||||||
|
id: string;
|
||||||
|
location: DeviceAttribute;
|
||||||
|
name: string;
|
||||||
|
placement: DeviceAttribute;
|
||||||
|
platform: string;
|
||||||
|
voice: DeviceAttribute;
|
||||||
|
wakeWord: DeviceAttribute;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Injectable({
|
||||||
|
providedIn: 'root'
|
||||||
|
})
|
||||||
|
export class DeviceService {
|
||||||
|
public devices: Device[] = [
|
||||||
|
{
|
||||||
|
coreVersion: '18.08',
|
||||||
|
enclosureVersion: '1.2.3',
|
||||||
|
group: {id: '1', name: 'None', preDefined: true},
|
||||||
|
id: 'abc-def-ghi',
|
||||||
|
location: {id: '1a2b-3c4d-5e6f', name: 'United States, 64101, CST', preDefined: false},
|
||||||
|
name: 'Mark',
|
||||||
|
placement: {id: 'bbb-bbb-bbb', name: 'Living Room', preDefined: false},
|
||||||
|
platform: 'mark-one',
|
||||||
|
voice: {id: '1a2b-3c4d-5e6f', name: 'British Male', preDefined: true},
|
||||||
|
wakeWord: {id: '1a2b-3c4d-5e6f', name: 'Hey Mycroft', preDefined: true},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
coreVersion: '18.08',
|
||||||
|
enclosureVersion: '1.2.3',
|
||||||
|
group: {id: '1', name: 'None', preDefined: true},
|
||||||
|
id: 'bcd-efg-hij',
|
||||||
|
location: {id: '1a2b-3c4d-5e6f', name: 'United States, 64101, CST', preDefined: false},
|
||||||
|
name: 'Marky Mark',
|
||||||
|
placement: {id: 'bbb-bbb-bbb', name: 'Kitchen', preDefined: true},
|
||||||
|
platform: 'mark-two',
|
||||||
|
voice: {id: '1a2b-3c4d-5e6f', name: 'British Male', preDefined: true},
|
||||||
|
wakeWord: {id: 'a1b2-c3d4-e5f6', name: 'Christopher', preDefined: true}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
coreVersion: '18.08',
|
||||||
|
enclosureVersion: '1.2.3',
|
||||||
|
group: {id: '2', name: 'Parent House', preDefined: false},
|
||||||
|
id: 'cde-fgh-ijk',
|
||||||
|
location: {id: '1a2b-3c4d-5e6f', name: 'United States, 64101, CST', preDefined: false},
|
||||||
|
name: 'American Pie',
|
||||||
|
placement: {id: 'ddd-ddd-ddd', name: 'Bedroom', preDefined: true},
|
||||||
|
platform: 'picroft',
|
||||||
|
voice: {id: '1a2b-3c4d-5e6f', name: 'British Male', preDefined: true},
|
||||||
|
wakeWord: {id: 'a1b2-c3d4-e5f6', name: 'Christopher', preDefined: true}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
coreVersion: '18.08',
|
||||||
|
enclosureVersion: '1.2.3',
|
||||||
|
group: {id: '2', name: 'Parent House', preDefined: false},
|
||||||
|
id: 'def-ghi-jkl',
|
||||||
|
location: {id: '1a2b-3c4d-5e6f', name: 'United States, 64101, CST', preDefined: false},
|
||||||
|
name: 'Kappa Delta Epsilon',
|
||||||
|
placement: {id: 'fff-fff-fff', name: 'Kitchen', preDefined: true},
|
||||||
|
platform: 'kde',
|
||||||
|
voice: {id: '1a2b-3c4d-5e6f', name: 'British Male', preDefined: true},
|
||||||
|
wakeWord: {id: 'abcd-efgh-ijkl', name: 'Hey Jarvis', preDefined: true}
|
||||||
|
}
|
||||||
|
];
|
||||||
|
|
||||||
|
public deviceGroups: DeviceAttribute[] = [
|
||||||
|
{ id: '1', name: 'None', preDefined: true},
|
||||||
|
{ id: null, name: 'Home', preDefined: true},
|
||||||
|
{ id: null, name: 'Office', preDefined: true},
|
||||||
|
{ id: '2', name: 'Parent House', preDefined: false}
|
||||||
|
];
|
||||||
|
|
||||||
|
public devicePlacements: DeviceAttribute[] = [
|
||||||
|
{ id: '1', name: 'None', preDefined: true},
|
||||||
|
{ id: null, name: 'Bedroom', preDefined: true},
|
||||||
|
{ id: null, name: 'Kitchen', preDefined: true},
|
||||||
|
{ id: '2', name: 'Living Room', preDefined: false}
|
||||||
|
];
|
||||||
|
|
||||||
|
public deviceGeographies: DeviceAttribute[] = [
|
||||||
|
{id: '1a2b-3c4d-5e6f', name: 'United States, 64101, CST', preDefined: false},
|
||||||
|
{id: 'a1b2-c3d4-e5f6', name: 'United Kingdom, ABCDE, BST', preDefined: false}
|
||||||
|
];
|
||||||
|
|
||||||
|
public deviceVoices: DeviceAttribute[] = [
|
||||||
|
{id: '1a2b-3c4d-5e6f', name: 'British Male', preDefined: true},
|
||||||
|
{id: 'a1b2-c3d4-e5f6', name: 'American Female', preDefined: true},
|
||||||
|
{id: 'abcd-efgh-ijkl', name: 'American Male', preDefined: true}
|
||||||
|
];
|
||||||
|
|
||||||
|
public deviceWakeWords: DeviceAttribute[] = [
|
||||||
|
{id: '1a2b-3c4d-5e6f', name: 'Hey Mycroft', preDefined: true},
|
||||||
|
{id: 'a1b2-c3d4-e5f6', name: 'Christopher', preDefined: true},
|
||||||
|
{id: 'abcd-efgh-ijkl', name: 'Hey Jarvis', preDefined: true}
|
||||||
|
];
|
||||||
|
|
||||||
|
constructor() { }
|
||||||
|
|
||||||
|
deleteDevice(device: Device): void {
|
||||||
|
console.log('deleting device... ');
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,51 @@
|
||||||
|
<mat-card id="basic-settings-card">
|
||||||
|
<mat-toolbar>
|
||||||
|
<span class="section-card-title">Basic Settings</span>
|
||||||
|
</mat-toolbar>
|
||||||
|
<div fxLayout="row wrap" fxLayoutAlign="space-between center" class="section-content">
|
||||||
|
<mat-slide-toggle [labelPosition]="'before'">Use device groups</mat-slide-toggle>
|
||||||
|
<span>
|
||||||
|
<mat-label>Measurement System</mat-label>
|
||||||
|
<mat-button-toggle-group>
|
||||||
|
<mat-button-toggle>Imperial</mat-button-toggle>
|
||||||
|
<mat-button-toggle>Metric</mat-button-toggle>
|
||||||
|
</mat-button-toggle-group>
|
||||||
|
</span>
|
||||||
|
<span>
|
||||||
|
<mat-label>Time Format</mat-label>
|
||||||
|
<mat-button-toggle-group>
|
||||||
|
<mat-button-toggle>12 Hour</mat-button-toggle>
|
||||||
|
<mat-button-toggle>24 Hour</mat-button-toggle>
|
||||||
|
</mat-button-toggle-group>
|
||||||
|
</span>
|
||||||
|
<span>
|
||||||
|
<mat-label>Date Format</mat-label>
|
||||||
|
<mat-button-toggle-group>
|
||||||
|
<mat-button-toggle>DD/MM/YYYY</mat-button-toggle>
|
||||||
|
<mat-button-toggle>MM/DD/YYYY</mat-button-toggle>
|
||||||
|
</mat-button-toggle-group>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</mat-card>
|
||||||
|
|
||||||
|
<mat-card id="default-settings-card">
|
||||||
|
<mat-toolbar>
|
||||||
|
<span>Defaults</span>
|
||||||
|
</mat-toolbar>
|
||||||
|
<div fxLayout="column" fxLayoutAlign="start start" class="section-content">
|
||||||
|
<mat-label>Default Location</mat-label>
|
||||||
|
<mat-select placeholder="None Selected"></mat-select>
|
||||||
|
</div>
|
||||||
|
</mat-card>
|
||||||
|
|
||||||
|
<mat-card id="advanced-settings-card">
|
||||||
|
<mat-toolbar>
|
||||||
|
<span class="section-card-title">Advanced Settings</span>
|
||||||
|
</mat-toolbar>
|
||||||
|
<div fxLayout="column" class="section-content">
|
||||||
|
<div class="mat-body" *ngFor="let paragraph of advancedSettingsDesc">
|
||||||
|
<p>{{paragraph}}</p>
|
||||||
|
</div>
|
||||||
|
<button mat-flat-button>VIEW DOCUMENTATION</button>
|
||||||
|
</div>
|
||||||
|
</mat-card>
|
|
@ -0,0 +1,33 @@
|
||||||
|
@import "~src/stylesheets/components/buttons";
|
||||||
|
@import "~src/stylesheets/components/cards";
|
||||||
|
|
||||||
|
#basic-settings-card {
|
||||||
|
@include section-card;
|
||||||
|
margin-top: 16px;
|
||||||
|
|
||||||
|
mat-button-toggle-group {
|
||||||
|
@include options-button-group;
|
||||||
|
|
||||||
|
mat-button-toggle {
|
||||||
|
width: 130px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
mat-label {
|
||||||
|
margin-bottom: 8px;
|
||||||
|
margin-top: 16px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#default-settings-card {
|
||||||
|
@include section-card;
|
||||||
|
}
|
||||||
|
#advanced-settings-card {
|
||||||
|
@include section-card;
|
||||||
|
button {
|
||||||
|
@include action-button-primary;
|
||||||
|
margin-left: auto;
|
||||||
|
margin-right: auto;
|
||||||
|
margin-top: 16px;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,26 @@
|
||||||
|
import { Component, OnInit } from '@angular/core';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'account-device-preferences',
|
||||||
|
templateUrl: './preferences.component.html',
|
||||||
|
styleUrls: ['./preferences.component.scss']
|
||||||
|
})
|
||||||
|
export class PreferencesComponent implements OnInit {
|
||||||
|
public advancedSettingsDesc = [
|
||||||
|
'Mycroft Core can be further configured ' +
|
||||||
|
'for development and experimentation purposes. Example configurations ' +
|
||||||
|
'include text-to-speech technologies, speech-to-text technologies and ' +
|
||||||
|
'wake word listeners.',
|
||||||
|
'These advanced options can be managed by editing a configuration file ' +
|
||||||
|
'on the device. Proceed with caution; a bad configuration file could ' +
|
||||||
|
'render your device unusable.',
|
||||||
|
'Follow the link below for documentation on the options available ' +
|
||||||
|
'and how to edit them.'
|
||||||
|
];
|
||||||
|
|
||||||
|
constructor() { }
|
||||||
|
|
||||||
|
ngOnInit() {
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,12 @@
|
||||||
|
<div mat-dialog-title class="mat-h2-primary">Remove Device</div>
|
||||||
|
|
||||||
|
<div mat-dialog-content>
|
||||||
|
<div class="mat-body">
|
||||||
|
Just double checking. Device removal cannot be undone.
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div mat-dialog-actions align="end">
|
||||||
|
<button id="device-remove-cancel-button" mat-button (click)="onCancelClick()">CANCEL</button>
|
||||||
|
<button id="device-remove-button" mat-button [mat-dialog-close]="true">REMOVE</button>
|
||||||
|
</div>
|
|
@ -0,0 +1,10 @@
|
||||||
|
@import '~src/stylesheets/components/buttons';
|
||||||
|
|
||||||
|
.mat-body{
|
||||||
|
margin-bottom: 16px;
|
||||||
|
width: 250px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#device-remove-button {
|
||||||
|
@include action-button-warn;
|
||||||
|
}
|
|
@ -0,0 +1,22 @@
|
||||||
|
import {Component, Inject, OnInit} from '@angular/core';
|
||||||
|
import { MatDialogRef, MAT_DIALOG_DATA } from '@angular/material';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'account-device-remove',
|
||||||
|
templateUrl: './remove.component.html',
|
||||||
|
styleUrls: ['./remove.component.scss']
|
||||||
|
})
|
||||||
|
export class RemoveComponent implements OnInit {
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
public dialogRef: MatDialogRef<RemoveComponent>,
|
||||||
|
@Inject(MAT_DIALOG_DATA) public data: boolean) {
|
||||||
|
}
|
||||||
|
|
||||||
|
ngOnInit() {
|
||||||
|
}
|
||||||
|
|
||||||
|
onCancelClick(): void {
|
||||||
|
this.dialogRef.close();
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,21 @@
|
||||||
|
<mat-card>
|
||||||
|
<mat-toolbar>
|
||||||
|
<span>Agreements</span>
|
||||||
|
</mat-toolbar>
|
||||||
|
<mat-card-content fxLayout="column" fxLayoutAlign="start none">
|
||||||
|
<ng-container *ngFor="let agreement of account.agreements">
|
||||||
|
<div *ngIf="agreement.type !== 'Open Dataset'" class="profile-text" fxLayout="row" fxLayout.lt-md="column" fxLayoutAlign="start center">
|
||||||
|
<span class="mat-subheading-2">{{agreement.type}}:</span>
|
||||||
|
<p class="mat-body">Accepted {{agreement.acceptDate}}</p>
|
||||||
|
</div>
|
||||||
|
</ng-container>
|
||||||
|
<!--<div fxLayout="row" fxLayoutAlign="start center">-->
|
||||||
|
<!--<span class="mat-subheading-2">Username:</span>-->
|
||||||
|
<!--<p class="mat-body">{{agreement.username}}</p>-->
|
||||||
|
<!--</div>-->
|
||||||
|
<!--<div fxLayout="column" fxLayoutAlign="center">-->
|
||||||
|
<!--<button mat-button>CHANGE USERNAME</button>-->
|
||||||
|
<!--<button mat-button>CHANGE PASSWORD</button>-->
|
||||||
|
<!--</div>-->
|
||||||
|
</mat-card-content>
|
||||||
|
</mat-card>
|
|
@ -0,0 +1,26 @@
|
||||||
|
@import "~src/stylesheets/components/cards";
|
||||||
|
|
||||||
|
mat-card {
|
||||||
|
@include section-card;
|
||||||
|
|
||||||
|
mat-card-content {
|
||||||
|
margin-left: 16px;
|
||||||
|
margin-right: 8px;
|
||||||
|
|
||||||
|
.mat-subheading-2 {
|
||||||
|
color: mat-color($mycroft-accent, A700);
|
||||||
|
font-weight: bold;
|
||||||
|
margin: 8px;
|
||||||
|
min-width: 120px;
|
||||||
|
}
|
||||||
|
.mat-body {
|
||||||
|
margin: 0;
|
||||||
|
min-width: 200px;
|
||||||
|
}
|
||||||
|
|
||||||
|
// button {
|
||||||
|
// @include action-button-primary;
|
||||||
|
// margin: 8px;
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,19 @@
|
||||||
|
import { Component, Input, OnInit } from '@angular/core';
|
||||||
|
|
||||||
|
import { Account } from '../profile.service';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'account-agreements',
|
||||||
|
templateUrl: './agreements.component.html',
|
||||||
|
styleUrls: ['./agreements.component.scss']
|
||||||
|
})
|
||||||
|
export class AgreementsComponent implements OnInit {
|
||||||
|
@Input() account: Account;
|
||||||
|
// public termsOfUseAccepted: string;
|
||||||
|
|
||||||
|
constructor() { }
|
||||||
|
|
||||||
|
ngOnInit() {
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,12 @@
|
||||||
|
<mat-card>
|
||||||
|
<mat-toolbar>
|
||||||
|
<span>Delete Account</span>
|
||||||
|
</mat-toolbar>
|
||||||
|
<div fxLayout="column" fxLayoutAlign="start center">
|
||||||
|
<span class="mat-h3">CAUTION</span>
|
||||||
|
<div id="delete-warning">
|
||||||
|
<div *ngFor="let paragraph of deleteWarning" class="mat-body-2">{{paragraph}}</div>
|
||||||
|
</div>
|
||||||
|
<button mat-raised-button color="warn">DELETE ACCOUNT</button>
|
||||||
|
</div>
|
||||||
|
</mat-card>
|
|
@ -0,0 +1,25 @@
|
||||||
|
@import "~src/stylesheets/components/cards";
|
||||||
|
|
||||||
|
mat-card {
|
||||||
|
@include section-card;
|
||||||
|
|
||||||
|
button {
|
||||||
|
color: white;
|
||||||
|
margin-bottom: 10px;
|
||||||
|
margin-left: auto;
|
||||||
|
margin-right: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
#delete-warning {
|
||||||
|
margin-bottom: 24px;
|
||||||
|
|
||||||
|
.mat-body-2 {
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.mat-h3 {
|
||||||
|
text-align: center;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,20 @@
|
||||||
|
import { Component, OnInit } from '@angular/core';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'account-delete',
|
||||||
|
templateUrl: './delete.component.html',
|
||||||
|
styleUrls: ['./delete.component.scss']
|
||||||
|
})
|
||||||
|
export class DeleteComponent implements OnInit {
|
||||||
|
public deleteWarning: string[];
|
||||||
|
|
||||||
|
constructor() { }
|
||||||
|
|
||||||
|
ngOnInit() {
|
||||||
|
this.deleteWarning = [
|
||||||
|
'Pressing the button below will delete your account and all data related to it from Mycroft servers.',
|
||||||
|
'It cannot be undone.'
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,21 @@
|
||||||
|
<mat-card>
|
||||||
|
<mat-toolbar>
|
||||||
|
<span>Profile</span>
|
||||||
|
</mat-toolbar>
|
||||||
|
<mat-card-content fxLayout="row" fxLayout.lt-md="column" fxLayoutAlign="space-between center">
|
||||||
|
<div fxFlex>
|
||||||
|
<div class="profile-text" fxLayout="row" fxLayoutAlign="start center">
|
||||||
|
<span class="mat-subheading-2">Email:</span>
|
||||||
|
<p class="mat-body">{{account.emailAddress}}</p>
|
||||||
|
</div>
|
||||||
|
<div fxLayout="row" fxLayoutAlign="start center">
|
||||||
|
<span class="mat-subheading-2">Username:</span>
|
||||||
|
<p class="mat-body">{{account.username}}</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div fxLayout="column" fxLayoutAlign="center">
|
||||||
|
<button mat-button>CHANGE USERNAME</button>
|
||||||
|
<button mat-button>CHANGE PASSWORD</button>
|
||||||
|
</div>
|
||||||
|
</mat-card-content>
|
||||||
|
</mat-card>
|
|
@ -0,0 +1,33 @@
|
||||||
|
@import "~@angular/material/theming";
|
||||||
|
@import "mycroft-colors";
|
||||||
|
@import "~src/stylesheets/components/buttons";
|
||||||
|
@import "~src/stylesheets/components/cards";
|
||||||
|
|
||||||
|
|
||||||
|
mat-card {
|
||||||
|
@include section-card;
|
||||||
|
|
||||||
|
mat-card-content {
|
||||||
|
margin-left: 16px;
|
||||||
|
margin-right: 8px;
|
||||||
|
|
||||||
|
.mat-subheading-2 {
|
||||||
|
color: mat-color($mycroft-accent, A700);
|
||||||
|
font-weight: bold;
|
||||||
|
margin: 8px;
|
||||||
|
min-width: 120px;
|
||||||
|
}
|
||||||
|
.mat-body {
|
||||||
|
margin: 0;
|
||||||
|
min-width: 200px;
|
||||||
|
}
|
||||||
|
|
||||||
|
button {
|
||||||
|
@include action-button-primary;
|
||||||
|
margin: 8px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,17 @@
|
||||||
|
import { Component, Input } from '@angular/core';
|
||||||
|
|
||||||
|
import { faEdit } from '@fortawesome/free-solid-svg-icons';
|
||||||
|
|
||||||
|
import { Account } from '../profile.service';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'account-login',
|
||||||
|
templateUrl: './login.component.html',
|
||||||
|
styleUrls: ['./login.component.scss']
|
||||||
|
})
|
||||||
|
export class LoginComponent {
|
||||||
|
@Input() account: Account;
|
||||||
|
public editIcon = faEdit;
|
||||||
|
|
||||||
|
constructor() { }
|
||||||
|
}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue