Merge branch 'rrt/dev' into rrt/testing

This commit is contained in:
Aaron Louie 2020-05-29 21:50:13 -04:00
commit 693be2e4ec
93 changed files with 535 additions and 474 deletions

View File

@ -34,7 +34,7 @@ env:
- API_URL=http://localhost:5000/v1.0
- BASE_HREF=/
- HOME_ROUTE=home
- IRB_URL=http://localhost:5001
- IRB_URL=http://localhost:5001/
- PORT0=4200
- PRODUCTION=false
script:

View File

@ -9,7 +9,7 @@ ADD package-lock.json /crc-bpmn/
COPY . /crc-bpmn/
ARG build_config=staging
ARG build_config=prod
RUN npm install && \
npm run build:$build_config
@ -17,18 +17,21 @@ RUN npm install && \
FROM nginx:alpine
RUN set -x && apk add --update --no-cache bash libintl gettext curl
COPY --from=builder /crc-bpmn/dist/* /usr/share/nginx/html/
COPY --from=builder /crc-bpmn/dist/* /etc/nginx/html/
COPY --from=builder /crc-bpmn/nginx.conf /etc/nginx/conf.d/default.conf
# Script for substituting environment variables
COPY ./docker/substitute-env-variables.sh ./entrypoint.sh
RUN chmod +x ./entrypoint.sh
# Substitute environment variables in nginx configuration and index.html
ENTRYPOINT ["./entrypoint.sh", \
"/usr/share/nginx/html/index.html,/etc/nginx/conf.d/default.conf", \
"PRODUCTION,API_URL,IRB_URL,HOME_ROUTE,BASE_HREF,PORT0", \
"/usr/share/nginx/html/index.html"]
# Fix for Angular routing
RUN echo "pushstate: enabled" > /etc/nginx/html/Staticfile
### STAGE 3: Profit! ###
CMD ["nginx", "-g", "daemon off;"]
# The entrypoint.sh script will run after the container finishes starting.
# Substitutes environment variables in nginx configuration and index.html,
# then starts/reloads nginx.
ENTRYPOINT ["./entrypoint.sh", \
"/etc/nginx/html/index.html,/etc/nginx/conf.d/default.conf", \
"PRODUCTION,API_URL,IRB_URL,HOME_ROUTE,BASE_HREF,DEPLOY_URL,PORT0", \
"/etc/nginx/html", \
"true"]

View File

@ -190,5 +190,8 @@
"@schematics/angular:component": {
"style": "scss"
}
},
"cli": {
"analytics": false
}
}

View File

@ -2,58 +2,68 @@ version: "3.3"
services:
db:
container_name: db
image: sartography/cr-connect-db:$E2E_TAG
image: sartography/cr-connect-db:dev
ports:
- "5432:5432"
environment:
- POSTGRES_USER=crc_user
- POSTGRES_PASSWORD=crc_pass
- POSTGRES_MULTIPLE_DATABASES=crc_test,crc_dev,pb_test,pb
- POSTGRES_USER=rrt_user
- POSTGRES_PASSWORD=rrt_pass
- POSTGRES_MULTIPLE_DATABASES=rrt
healthcheck:
test: ["CMD", "pg_isready"]
timeout: 20s
retries: 10
pb:
container_name: pb
depends_on:
- db
image: sartography/protocol-builder-mock:$E2E_TAG
environment:
- FLASK_APP=/protocol-builder-mock/app.py
- UPGRADE_DB=true
- DB_HOST=db
- DB_PORT=5432
- DB_PASSWORD=crc_pass
- DB_USER=crc_user
- DB_NAME=pb_test
ports:
- "5001:5001"
command: ./wait-for-it.sh db:5432 -t 0 -- ./docker_run.sh
ldap:
container_name: ldap
image: tuxmonteiro/ldap-mock
ports:
- "3890"
backend:
container_name: backend
depends_on:
- db
- pb
- ldap
image: sartography/cr-connect-workflow:$E2E_TAG
image: sartography/cr-connect-workflow:dev
environment:
- FLASK_APP=./crc/__init__.py
- UPGRADE_DB=true
- RESET_DB=true
- LDAP_URL=ldap
- PB_BASE_URL=http://pb:5001/pb/
- APPLICATION_ROOT=/api
- CORS_ALLOW_ORIGINS=localhost:5002,bpmn:5002,localhost:4200,frontend:4200
- DB_HOST=db
- DB_NAME=rrt
- DB_PASSWORD=rrt_pass
- DB_PORT=5432
- DB_PASSWORD=crc_pass
- DB_USER=crc_user
- DB_NAME=crc_test
- DB_USER=rrt_user
- LDAP_URL=ldap.virginia.edu
- PB_ENABLED=false
- PORT0=5000
- RESET_DB=true
- UPGRADE_DB=true
ports:
- "5000:5000"
command: ./wait-for-it.sh pb:5001 -t 0 -- ./docker_run.sh
command: ./wait-for-it.sh db:5432 -t 0 -- ./docker_run.sh
bpmn:
container_name: bpmn
depends_on:
- db
- backend
image: sartography/cr-connect-bpmn:dev
environment:
- API_URL=http://localhost:5000/api/v1.0
- BASE_HREF=/bpmn/
- DEPLOY_URL=/bpmn/
- HOME_ROUTE=home
- PORT0=5002
- PRODUCTION=false
ports:
- "5002:5002"
frontend:
container_name: frontend
depends_on:
- db
- backend
image: sartography/cr-connect-frontend:dev
environment:
- API_URL=http://localhost:5000/api/v1.0
- BASE_HREF=/app/
- DEPLOY_URL=/app/
- HOME_ROUTE=home
- PORT0=4200
- PRODUCTION=false
ports:
- "4200:4200"

View File

@ -5,33 +5,92 @@
# Parameters:
# $1: Comma-delimited list of file paths
# $2: Comma-delimited list of environment variables
# $3: File path to index.html (optional)
# $3: Absolute path to nginx html directory (optional)
# $4: Should restart nginx (optional)
#####################################################################
echo 'Substituting environment variables...'
num_args=0
# The first parameter is a comma-delimited list of paths to files which should be substituted
if [[ -z $1 ]]; then
echo 'ERROR: No target files given.'
exit 1
else
num_args=1
fi
# The second parameter is a comma-delimited list of environment variable names
if [[ -z $2 ]]; then
echo 'ERROR: No environment variables given.'
exit 1
else
num_args=2
fi
# The third parameter is the absolute path to the nginx html directory
if [[ -z $3 ]]; then
echo '' # It's optional. Don't print anything.
else
num_args=3
fi
# The fourth parameter, if 'true', is whether we should reload nginx
if [[ -z $4 ]]; then
echo '' # It's optional. Don't print anything.
else
num_args=4
fi
# Find & replace BASE_HREF in all files in the nginx html directory
if [[ "$2" == *"BASE_HREF"* ]] && [[ "$2" == *"DEPLOY_URL"* ]]; then
# Add trailing slash to $BASE_HREF if needed
length=${#BASE_HREF}
last_char=${BASE_HREF:length-1:1}
[[ $last_char != "/" ]] && BASE_HREF="$BASE_HREF/"; :
# Add trailing slash to $DEPLOY_URL if needed
length=${#DEPLOY_URL}
last_char=${DEPLOY_URL:length-1:1}
[[ $last_char != "/" ]] && DEPLOY_URL="$DEPLOY_URL/"; :
# The third parameter is the absolute path to the nginx html directory
if [[ $num_args -ge 3 ]]; then
# Replace all instances of __REPLACE_ME_WITH_BASE_HREF__ with $BASE_HREF
find "$3" \( -type d -name .git -prune \) -o -type f -print0 | \
xargs -0 sed -i 's@__REPLACE_ME_WITH_BASE_HREF__@'"$BASE_HREF"'@g'
echo 'Replacing base href...'
# Wait a few seconds in case find | sed needs more time
sleep 3
# Replace all instances of __REPLACE_ME_WITH_DEPLOY_URL__ with $DEPLOY_URL
find "$3" \( -type d -name .git -prune \) -o -type f -print0 | \
xargs -0 sed -i 's@__REPLACE_ME_WITH_DEPLOY_URL__@'"$DEPLOY_URL"'@g'
echo 'Replacing deploy url...'
# Wait a few seconds in case find | sed needs more time
sleep 3
fi
fi
# Convert "VAR1,VAR2,VAR3,..." to "\$VAR1 \$VAR2 \$VAR3 ..."
env_list="\\\$${2//,/ \\\$}" # "\" and "$" are escaped as "\\" and "\$"
for file_path in ${1//,/ }
do
echo "replacing $env_list in $file_path"
echo "replacing environment variables in $file_path"
# Replace strings in the given file(s) in env_list
envsubst "$env_list" < "$file_path" > "$file_path".tmp && mv "$file_path".tmp "$file_path"
echo '...'
# Wait a second in case envsubst needs more time
sleep 1
# If this is the nginx default.conf file, replace double slashes with single slashes
if [[ $file_path == *"/default.conf"* ]]; then
sed -i -e 's@//@/@g' "$file_path"
fi
done
echo 'Finished substituting environment variables.'
@ -40,17 +99,25 @@ do
echo "$env_var = ${!env_var}"
done
# The third parameter is the path to the index.html file
# Rewrite base href in index.html.
# Use @ as a sed delimiter because $BASE_HREF will contain a / character
if [[ -z $3 ]]; then
# Execute all other commands with parameters
exit 0
else
sed -i -e 's@<base href\=\"\/\">@<base href\=\"'"$BASE_HREF"'\">@' "$3"
# Execute all other commands with parameters
exec "${@:4}"
# Reload nginx
if [ $num_args -ge 4 ] && [ "$4" == "true" ]; then
# Check to see if nginx command is available
if hash nginx 2> /dev/null; then
# Check to see if nginx is already running
if [ -e /var/run/nginx.pid ]; then
echo "nginx is currently running. Reloading nginx..."
exec nginx -s reload
echo "nginx reloaded."
else
echo "nginx is not yet running. Starting nginx..."
exec nginx -g 'daemon off;'
echo "nginx started."
fi
else
echo "nginx command not found on this system."
fi
fi
# Execute all other commands with parameters
num_args=$((num_args + 1))
exec "${@:num_args}"

View File

@ -1,11 +1,12 @@
server {
listen $PORT0;
location / {
root /usr/share/nginx/html;
index index.html index.htm;
try_files $uri $uri/ /index.html =404;
}
port_in_redirect off;
include /etc/nginx/extra-conf.d/*.conf;
location $BASE_HREF/ {
alias /etc/nginx/html/;
index index.html index.htm;
try_files $uri$args $uri $BASE_HREF/index.html;
}
}

14
package-lock.json generated
View File

@ -3436,6 +3436,14 @@
"integrity": "sha512-GpSwvyXOcOOlV70vbnzjj4fW5xW/FdUF6nQEt1ENy7m4ZCczi1+/buVUPAqmGfqznsORNFzUMjctTIp8a9tuCQ==",
"dev": true
},
"@yellowspot/ng-truncate": {
"version": "1.5.1",
"resolved": "https://registry.npmjs.org/@yellowspot/ng-truncate/-/ng-truncate-1.5.1.tgz",
"integrity": "sha512-tAVlVqz1XGAbL3HKg8i/Sy++iilhvoujNkwE34IsVQ+ndiOJEgSmj8OntrsfrkBL2KlOs6L507nUz4MWzh+G0A==",
"requires": {
"tslib": "^1.9.0"
}
},
"JSONStream": {
"version": "1.3.5",
"resolved": "https://registry.npmjs.org/JSONStream/-/JSONStream-1.3.5.tgz",
@ -12291,9 +12299,9 @@
"integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg=="
},
"sartography-workflow-lib": {
"version": "0.0.180",
"resolved": "https://registry.npmjs.org/sartography-workflow-lib/-/sartography-workflow-lib-0.0.180.tgz",
"integrity": "sha512-d/ePxdkeIX/ZW3Sp5NIkZsitxRxS560PWorOd9RaojyJtMks2EgCwuN0Gs18NkT0Qrvk7fJHKYYV89k0/H0djQ=="
"version": "0.0.213",
"resolved": "https://registry.npmjs.org/sartography-workflow-lib/-/sartography-workflow-lib-0.0.213.tgz",
"integrity": "sha512-2y4UQk3zYeY0Xu3wqq3UptORxVN/Dp8MPyr7JMNBjM9XCdoDL+nIyhpOA7pS+VfraoEzbm9m4CQamQ9YSGRu6w=="
},
"sass": {
"version": "1.23.3",

View File

@ -5,8 +5,8 @@
"ng": "ng",
"start": "ng serve",
"build": "ng build",
"build:prod": "ng build --configuration=production",
"build:staging": "ng build --configuration=staging",
"build:prod": "ng build --configuration=production --prod --base-href=__REPLACE_ME_WITH_BASE_HREF__ --deploy-url=__REPLACE_ME_WITH_DEPLOY_URL__",
"build:staging": "ng build --configuration=staging --prod --base-href=__REPLACE_ME_WITH_BASE_HREF__ --deploy-url=__REPLACE_ME_WITH_DEPLOY_URL__",
"build:test": "ng build --configuration=test",
"test": "ng test",
"test:coverage": "ng test --codeCoverage=true --watch=false --browsers=ChromeHeadless",
@ -21,8 +21,8 @@
"e2e-wf:db-setup": "docker exec -it backend pipenv run flask load-example-data",
"e2e-wf:pb-setup": "docker exec -it pb pipenv run flask db upgrade",
"e2e-wf": "npm run e2e-wf:stop && npm run e2e-wf:clean && npm run e2e-wf:build && npm run e2e-wf:start && npm run e2e-wf:db-upgrade && npm run e2e-wf:db-setup && npm run e2e-wf:pb-setup",
"env": "chmod +x ./docker/substitute-env-variables.sh && ./docker/substitute-env-variables.sh src/index.html PRODUCTION,API_URL,IRB_URL,HOME_ROUTE,BASE_HREF,PORT0 src/index.html",
"ci": "npm run lint && npm run test:coverage && npm run env && npm run e2e:with-wf && sonar-scanner"
"env": "chmod +x ./docker/substitute-env-variables.sh && ./docker/substitute-env-variables.sh src/index.html PRODUCTION,API_URL,IRB_URL,HOME_ROUTE,BASE_HREF,PORT0",
"ci": "npm run lint && npm run test:coverage && sonar-scanner"
},
"private": true,
"dependencies": {
@ -39,6 +39,7 @@
"@angular/router": "^9.0.7",
"@ngx-formly/core": "^5.5.15",
"@ngx-formly/material": "^5.5.15",
"@yellowspot/ng-truncate": "^1.5.1",
"bpmn-js": "^6.4.2",
"bpmn-js-properties-panel": "^0.33.2",
"camunda-bpmn-moddle": "^4.4.0",
@ -53,7 +54,7 @@
"ngx-file-drop": "^8.0.8",
"ngx-markdown": "^9.0.0",
"rxjs": "~6.5.4",
"sartography-workflow-lib": "^0.0.180",
"sartography-workflow-lib": "0.0.213",
"tslib": "^1.11.1",
"uuid": "^7.0.2",
"zone.js": "^0.10.3"

View File

@ -1,6 +1,6 @@
// GLOBAL SCSS VARIABLES
$body-font-family: '"franklin-gothic-urw", sans-serif';
$heading-font-family: '"franklin-gothic-urw-cond", sans-serif';
$body-font-family: 'franklin-gothic-urw', sans-serif;
$heading-font-family: 'franklin-gothic-urw-cond', sans-serif;
// COLOR PALETTE
@ -11,6 +11,11 @@ $brand-gray-tint-2: #DADADA;
$brand-gray-tint-3: #F1F1EF;
$brand-gray-tint-4: scale-color($brand-gray, $lightness: 90%);
$body-color: $brand-gray;
$brand-gray-shade-1: scale-color($brand-gray, $lightness: -20%);
$brand-gray-shade-2: scale-color($brand-gray, $lightness: -40%);
$brand-gray-shade-3: scale-color($brand-gray, $lightness: -60%);
$brand-gray-shade-4: scale-color($brand-gray, $lightness: -80%);
$brand-gray-shade-5: scale-color($brand-gray, $lightness: -100%);
$body-color-muted: $brand-gray-tint-1;
$body-color-light: $brand-gray-tint-4;
$brand-gray-muted: $brand-gray-tint-1;
@ -48,20 +53,13 @@ $brand-accent-light: $brand-accent-tint-4;
$brand-warning: #DF1E43;
$brand-warning-muted: desaturate(scale-color($brand-warning, $lightness: 30%), 20%);
$brand-warning-light: scale-color($brand-warning, $lightness: 90%);
$easeDuration: 300ms;
$animationDuration: 500ms;
$tile-height-1x: 226px;
$tile-height-2x: 288px;
$uva-header-height: 40px;
$site-header-height: 64px;
$search-bar-height-sm: 64px;
$search-bar-height-md: 128px;
$search-bar-height-lg: 64px;
$header-height-sm: ($uva-header-height + $site-header-height + $search-bar-height-sm);
$header-height-md: ($uva-header-height + $site-header-height + $search-bar-height-md);
$header-height-lg: ($uva-header-height + $site-header-height + $search-bar-height-lg);
// Green
$brand-green: #64B343;
$brand-green-muted: #8EC774;
$brand-green-light: #B5D9A3;
// Dimensions
$easeDuration: 300ms;
$animationDuration: 500ms;
$header-height: 84px;

View File

@ -4,19 +4,19 @@
// Define a custom typography config that overrides the font-family
$custom-typography: mat-typography-config(
$font-family: $body-font-family,
$display-4: mat-typography-level(2.500rem, 1.0, 700, $heading-font-family),
$display-3: mat-typography-level(2.250rem, 1.0, 700, $heading-font-family),
$display-2: mat-typography-level(2.000rem, 1.0, 700, $heading-font-family),
$display-1: mat-typography-level(1.750rem, 1.0, 700, $heading-font-family),
$headline: mat-typography-level(48px, 1.0, 700, $heading-font-family),
$title: mat-typography-level(1.500rem, 1.0, 700, $body-font-family),
$subheading-2: mat-typography-level(1.375rem, 1.0, 500, $body-font-family),
$subheading-1: mat-typography-level(1.250rem, 1.0, 500, $body-font-family),
$body-2: mat-typography-level(1.000rem, 1.5, 500, $body-font-family),
$body-1: mat-typography-level(1.000rem, 1.5, 500, $body-font-family),
$caption: mat-typography-level(1.000rem, 1.5, 500, $body-font-family),
$button: mat-typography-level(1.000rem, 1.5, 500, $body-font-family),
$input: mat-typography-level(1.000rem, 1.5, 500, $body-font-family)
$display-4: mat-typography-level(3.75rem, 1.0925, 700, $body-font-family),
$display-3: mat-typography-level(2.4917rem, 1.1037, 700, $body-font-family),
$display-2: mat-typography-level(2.2148rem, 1.1287, 700, $body-font-family),
$display-1: mat-typography-level(1.9688rem, 1.1429, 700, $body-font-family),
$headline: mat-typography-level(1.7500rem, 1.1429, 700, $body-font-family), // h1
$title: mat-typography-level(1.5625rem, 1.1200, 500, $body-font-family), // h2
$subheading-2: mat-typography-level(1.3750rem, 1.0000, 700, $heading-font-family), // h3
$subheading-1: mat-typography-level(1.2500rem, 1.1000, 700, $body-font-family), // h4
$body-2: mat-typography-level(1.1250rem, 1.1111, 500, $body-font-family), // h5
$body-1: mat-typography-level(1.0000rem, 1.1250, 500, $body-font-family), // p
$caption: mat-typography-level(0.8750rem, 0.7143, 500, $body-font-family), // small
$button: mat-typography-level(1.0000rem, 1.1250, 500, $body-font-family),
$input: mat-typography-level(1.0000rem, 1.1250, 500, $body-font-family)
);
$mat-blue: (

View File

@ -1,3 +1,4 @@
import {APP_BASE_HREF} from '@angular/common';
import {HttpClientTestingModule, HttpTestingController} from '@angular/common/http/testing';
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import {FormsModule, ReactiveFormsModule} from '@angular/forms';
@ -37,6 +38,7 @@ describe('OpenFileDialogComponent', () => {
providers: [
ApiService,
{provide: 'APP_ENVIRONMENT', useClass: MockEnvironment},
{provide: APP_BASE_HREF, useValue: ''},
{
provide: MatDialogRef,
useValue: {

View File

@ -1,5 +1,6 @@
import {APP_BASE_HREF} from '@angular/common';
import {HttpClientTestingModule, HttpTestingController} from '@angular/common/http/testing';
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import {async, ComponentFixture, TestBed} from '@angular/core/testing';
import {FormsModule, ReactiveFormsModule} from '@angular/forms';
import {MAT_DIALOG_DATA, MatDialog, MatDialogModule, MatDialogRef} from '@angular/material/dialog';
import {MatFormFieldModule} from '@angular/material/form-field';
@ -13,7 +14,7 @@ import {FormlyMaterialModule} from '@ngx-formly/material';
import {ApiService, MockEnvironment, mockWorkflowSpec0, mockWorkflowSpecCategories} from 'sartography-workflow-lib';
import {WorkflowSpecDialogData} from '../../_interfaces/dialog-data';
import { WorkflowSpecDialogComponent } from './workflow-spec-dialog.component';
import {WorkflowSpecDialogComponent} from './workflow-spec-dialog.component';
describe('WorkflowSpecDialogComponent', () => {
let httpMock: HttpTestingController;
@ -37,10 +38,11 @@ describe('WorkflowSpecDialogComponent', () => {
ReactiveFormsModule,
RouterTestingModule,
],
declarations: [ WorkflowSpecDialogComponent ],
declarations: [WorkflowSpecDialogComponent],
providers: [
ApiService,
{provide: 'APP_ENVIRONMENT', useClass: MockEnvironment},
{provide: APP_BASE_HREF, useValue: ''},
{
provide: MatDialogRef,
useValue: {
@ -59,7 +61,7 @@ describe('WorkflowSpecDialogComponent', () => {
{provide: Router, useValue: mockRouter},
]
})
.compileComponents();
.compileComponents();
}));
beforeEach(() => {

View File

@ -7,8 +7,6 @@ import {HomeComponent} from './home/home.component';
import {ModelerComponent} from './modeler/modeler.component';
import {ProtocolBuilderComponent} from './protocol-builder/protocol-builder.component';
import {ReferenceFilesComponent} from './reference-files/reference-files.component';
import {SignInComponent} from './sign-in/sign-in.component';
import {SignOutComponent} from './sign-out/sign-out.component';
@Injectable()
export class ThisEnvironment implements AppEnvironment {
@ -16,7 +14,7 @@ export class ThisEnvironment implements AppEnvironment {
production = environment.production;
api = environment.api;
irbUrl = environment.irbUrl;
baseHref = environment.baseHref;
title = environment.title;
}
const routes: Routes = [
@ -46,15 +44,7 @@ const routes: Routes = [
component: ModelerComponent
},
{
path: 'sign-in',
component: SignInComponent
},
{
path: 'sign-out',
component: SignOutComponent
},
{
path: 'session/:token',
path: 'session',
component: SessionRedirectComponent
}
];
@ -71,7 +61,7 @@ const routes: Routes = [
exports: [RouterModule],
providers: [
{provide: 'APP_ENVIRONMENT', useClass: ThisEnvironment},
{provide: APP_BASE_HREF, useValue: environment.baseHref},
// {provide: APP_BASE_HREF, useValue: environment.baseHref},
]
})
export class AppRoutingModule {

View File

@ -1,3 +1,4 @@
import {APP_BASE_HREF} from '@angular/common';
import {HttpClient} from '@angular/common/http';
import {HttpClientTestingModule} from '@angular/common/http/testing';
import {Component} from '@angular/core';
@ -42,6 +43,7 @@ describe('AppComponent', () => {
HttpClient,
ApiService,
{provide: 'APP_ENVIRONMENT', useClass: MockEnvironment},
{provide: APP_BASE_HREF, useValue: ''},
],
})
.compileComponents();

View File

@ -1,4 +1,4 @@
import {APP_BASE_HREF} from '@angular/common';
import {APP_BASE_HREF, PlatformLocation} from '@angular/common';
import {HTTP_INTERCEPTORS, HttpClientModule} from '@angular/common/http';
import {Injectable, NgModule} from '@angular/core';
import {FlexLayoutModule} from '@angular/flex-layout';
@ -49,8 +49,6 @@ import {ModelerComponent} from './modeler/modeler.component';
import {NavbarComponent} from './navbar/navbar.component';
import {ProtocolBuilderComponent} from './protocol-builder/protocol-builder.component';
import {ReferenceFilesComponent} from './reference-files/reference-files.component';
import {SignInComponent} from './sign-in/sign-in.component';
import {SignOutComponent} from './sign-out/sign-out.component';
import {WorkflowSpecCardComponent} from './workflow-spec-card/workflow-spec-card.component';
import {WorkflowSpecListComponent} from './workflow-spec-list/workflow-spec-list.component';
@ -60,7 +58,22 @@ export class ThisEnvironment implements AppEnvironment {
production = environment.production;
api = environment.api;
irbUrl = environment.irbUrl;
baseHref = environment.baseHref;
title = environment.title;
}
/**
* This function is used internal to get a string instance of the `<base href="" />` value from `index.html`.
* This is an exported function, instead of a private function or inline lambda, to prevent this error:
*
* `Error encountered resolving symbol values statically.`
* `Function calls are not supported.`
* `Consider replacing the function or lambda with a reference to an exported function.`
*
* @param platformLocation an Angular service used to interact with a browser's URL
* @return a string instance of the `<base href="" />` value from `index.html`
*/
export function getBaseHref(platformLocation: PlatformLocation): string {
return platformLocation.getBaseHrefFromDOM();
}
@NgModule({
@ -78,8 +91,6 @@ export class ThisEnvironment implements AppEnvironment {
NavbarComponent,
NewFileDialogComponent,
OpenFileDialogComponent,
SignInComponent,
SignOutComponent,
WorkflowSpecCategoryDialogComponent,
WorkflowSpecDialogComponent,
WorkflowSpecListComponent,
@ -130,9 +141,9 @@ export class ThisEnvironment implements AppEnvironment {
providers: [
{provide: MAT_FORM_FIELD_DEFAULT_OPTIONS, useValue: {appearance: 'outline'}},
{provide: 'APP_ENVIRONMENT', useClass: ThisEnvironment},
{provide: APP_BASE_HREF, useValue: environment.baseHref},
{provide: HTTP_INTERCEPTORS, useClass: AuthInterceptor, multi: true},
{provide: HTTP_INTERCEPTORS, useClass: ErrorInterceptor, multi: true},
{provide: APP_BASE_HREF, useFactory: getBaseHref, deps: [PlatformLocation]}
]
})
export class AppModule {

View File

@ -1,3 +1,4 @@
import {APP_BASE_HREF} from '@angular/common';
import {HttpClientTestingModule, HttpTestingController} from '@angular/common/http/testing';
import {DebugNode} from '@angular/core';
import {async, ComponentFixture, TestBed} from '@angular/core/testing';
@ -31,6 +32,7 @@ describe('DiagramComponent', () => {
providers: [
ApiService,
{provide: 'APP_ENVIRONMENT', useClass: MockEnvironment},
{provide: APP_BASE_HREF, useValue: ''},
{provide: Router, useValue: mockRouter},
]
});

View File

@ -1,3 +1,4 @@
import {APP_BASE_HREF} from '@angular/common';
import {HttpHeaders} from '@angular/common/http';
import {HttpClientTestingModule, HttpTestingController} from '@angular/common/http/testing';
import {async, ComponentFixture, TestBed} from '@angular/core/testing';
@ -8,6 +9,7 @@ import {MatSnackBarModule} from '@angular/material/snack-bar';
import {BrowserDynamicTestingModule} from '@angular/platform-browser-dynamic/testing';
import {BrowserAnimationsModule} from '@angular/platform-browser/animations';
import {RouterTestingModule} from '@angular/router/testing';
import createClone from 'rfdc';
import {of} from 'rxjs';
import {
ApiService,
@ -22,7 +24,6 @@ import {DeleteFileDialogComponent} from '../_dialogs/delete-file-dialog/delete-f
import {DeleteFileDialogData} from '../_interfaces/dialog-data';
import {GetIconCodePipe} from '../_pipes/get-icon-code.pipe';
import {FileListComponent} from './file-list.component';
import createClone from 'rfdc';
describe('FileListComponent', () => {
@ -49,6 +50,7 @@ describe('FileListComponent', () => {
providers: [
ApiService,
{provide: 'APP_ENVIRONMENT', useClass: MockEnvironment},
{provide: APP_BASE_HREF, useValue: ''},
{
provide: MatDialogRef,
useValue: {

View File

@ -1,3 +1,3 @@
<footer>
CR Connect - University of Virginia
{{title}} - University of Virginia
</footer>

View File

@ -1,6 +1,7 @@
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { FooterComponent } from './footer.component';
import {APP_BASE_HREF} from '@angular/common';
import {async, ComponentFixture, TestBed} from '@angular/core/testing';
import {MockEnvironment} from 'sartography-workflow-lib';
import {FooterComponent} from './footer.component';
describe('FooterComponent', () => {
let component: FooterComponent;
@ -8,9 +9,14 @@ describe('FooterComponent', () => {
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [ FooterComponent ]
declarations: [FooterComponent],
providers: [
{provide: 'APP_ENVIRONMENT', useClass: MockEnvironment},
{provide: APP_BASE_HREF, useValue: ''},
],
})
.compileComponents();
.compileComponents();
}));
beforeEach(() => {

View File

@ -1,4 +1,5 @@
import { Component, OnInit } from '@angular/core';
import {Component, Inject, OnInit} from '@angular/core';
import {AppEnvironment} from 'sartography-workflow-lib';
@Component({
selector: 'app-footer',
@ -7,7 +8,11 @@ import { Component, OnInit } from '@angular/core';
})
export class FooterComponent implements OnInit {
constructor() { }
title: string;
constructor(@Inject('APP_ENVIRONMENT') private environment: AppEnvironment) {
this.title = environment.title;
}
ngOnInit() {
}

View File

@ -1,2 +1 @@
<app-sign-in *ngIf="!isSignedIn"></app-sign-in>
<app-workflow-spec-list *ngIf="isSignedIn"></app-workflow-spec-list>
<app-workflow-spec-list></app-workflow-spec-list>

View File

@ -1,3 +1,4 @@
import {APP_BASE_HREF} from '@angular/common';
import {HttpClient} from '@angular/common/http';
import {HttpClientTestingModule} from '@angular/common/http/testing';
import {Component} from '@angular/core';
@ -43,6 +44,7 @@ describe('HomeComponent', () => {
HttpClient,
ApiService,
{provide: 'APP_ENVIRONMENT', useClass: MockEnvironment},
{provide: APP_BASE_HREF, useValue: ''},
{provide: Router, useValue: mockRouter},
]
})

View File

@ -1,3 +1,4 @@
import {APP_BASE_HREF} from '@angular/common';
import {HttpErrorResponse, HttpHeaders, HttpResponse} from '@angular/common/http';
import {HttpClientTestingModule, HttpTestingController} from '@angular/common/http/testing';
import {DebugNode} from '@angular/core';
@ -75,6 +76,7 @@ describe('ModelerComponent', () => {
providers: [
ApiService,
{provide: 'APP_ENVIRONMENT', useClass: MockEnvironment},
{provide: APP_BASE_HREF, useValue: ''},
{
provide: MatDialogRef,
useValue: {

View File

@ -1,9 +1,12 @@
<nav *ngIf="user">
<nav class="mat-elevation-z6" id="globalHeader" *ngIf="user">
<a
[routerLink]="['/']"
class="site-title mat-display-1"
mat-button
>CR Connect</a>
>
<img class="logo" src="assets/logo/uva_rotunda.svg" alt="University of Virginia">
{{title}}
</a>
<div class="flex-spacer"></div>
<ng-container *ngFor="let link of navLinks">
<a *ngIf="!link.links"

View File

@ -1,5 +1,13 @@
@import "../../config";
#globalHeader {
position: fixed;
top: 0;
left: 0;
right: 0;
z-index: 2;
}
.flex-spacer {
flex-grow: 1;
}
@ -8,18 +16,23 @@ nav {
display: flex;
flex-wrap: wrap;
align-items: center;
padding: 8px 16px;
padding: 0px 16px;
background-color: $brand-primary;
color: white;
height: 48px;
height: $header-height;
.site-title {
color: white;
font-size: 1.5rem;
line-height: 48px;
font-size: 1.5625rem;
font-weight: 500;
line-height: 84px;
margin-bottom: 0;
background-color: $brand-primary;
text-transform: uppercase;
.logo {
margin-right: 1rem;
height: 72px;
}
}
}

View File

@ -1,3 +1,4 @@
import {APP_BASE_HREF} from '@angular/common';
import {HttpClientTestingModule, HttpTestingController} from '@angular/common/http/testing';
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import {MatIconModule} from '@angular/material/icon';
@ -32,6 +33,7 @@ describe('NavbarComponent', () => {
useValue: mockRouter
},
{provide: 'APP_ENVIRONMENT', useClass: MockEnvironment},
{provide: APP_BASE_HREF, useValue: ''},
],
})
.compileComponents();

View File

@ -19,6 +19,7 @@ interface NavItem {
export class NavbarComponent {
navLinks: NavItem[];
user: User;
title: string;
constructor(
private router: Router,
@ -26,6 +27,7 @@ export class NavbarComponent {
@Inject('APP_ENVIRONMENT') private environment: AppEnvironment,
) {
this._loadUser();
this.title = environment.title;
}
isLinkActive(path: string) {

View File

@ -2,11 +2,27 @@
<h1>Reference Files</h1>
<div *ngFor="let refFile of referenceFiles" fxLayout="row" fxLayoutGap="40px">
<h3>{{refFile.name}}</h3>
<div class="file-buttons" fxLayout="row" fxLayoutGap="10px">
<button mat-icon-button (click)="downloadFile(refFile)" color="primary"><mat-icon>save_alt</mat-icon></button>
<button mat-icon-button (click)="openFileDialog(refFile)" color="primary"><mat-icon>edit</mat-icon></button>
</div>
<mat-card class="mat-elevation-z0">
<mat-card-header>
<mat-card-title>
<h2>
<mat-icon>{{refFile.type | getIconCode}}</mat-icon>
{{refFile.name}}
</h2>
</mat-card-title>
</mat-card-header>
<mat-card-content>
<hr>
</mat-card-content>
<mat-card-footer>
<button mat-button (click)="downloadFile(refFile)" color="primary">
<mat-icon>save_alt</mat-icon> Download existing version
</button>
<button mat-button (click)="openFileDialog(refFile)" color="primary">
<mat-icon>edit</mat-icon> Upload a new version
</button>
</mat-card-footer>
</mat-card>
</div>
</div>

View File

@ -0,0 +1,6 @@
@import "../../config";
mat-card {
padding: 2em;
border: 1px solid $brand-gray;
}

View File

@ -1,6 +1,7 @@
import {APP_BASE_HREF} from '@angular/common';
import {HttpHeaders} from '@angular/common/http';
import {HttpClientTestingModule, HttpTestingController} from '@angular/common/http/testing';
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import {async, ComponentFixture, TestBed} from '@angular/core/testing';
import {MAT_DIALOG_DATA, MatDialogModule, MatDialogRef} from '@angular/material/dialog';
import {MatIconModule} from '@angular/material/icon';
import {MatSnackBarModule} from '@angular/material/snack-bar';
@ -8,12 +9,12 @@ import {BrowserDynamicTestingModule} from '@angular/platform-browser-dynamic/tes
import {BrowserAnimationsModule} from '@angular/platform-browser/animations';
import {Router} from '@angular/router';
import {RouterTestingModule} from '@angular/router/testing';
import * as FileSaver from 'file-saver';
import createClone from 'rfdc';
import {of} from 'rxjs';
import {ApiService, FileMeta, FileType, MockEnvironment, mockFileMetaReference0} from 'sartography-workflow-lib';
import {OpenFileDialogComponent} from '../_dialogs/open-file-dialog/open-file-dialog.component';
import * as FileSaver from 'file-saver';
import { ReferenceFilesComponent } from './reference-files.component';
import createClone from 'rfdc';
import {ReferenceFilesComponent} from './reference-files.component';
describe('ReferenceFilesComponent', () => {
let httpMock: HttpTestingController;
@ -53,6 +54,7 @@ describe('ReferenceFilesComponent', () => {
providers: [
ApiService,
{provide: 'APP_ENVIRONMENT', useClass: MockEnvironment},
{provide: APP_BASE_HREF, useValue: ''},
{
provide: MatDialogRef,
useValue: {
@ -70,7 +72,7 @@ describe('ReferenceFilesComponent', () => {
]
}
})
.compileComponents();
.compileComponents();
}));
beforeEach(() => {
@ -96,7 +98,12 @@ describe('ReferenceFilesComponent', () => {
it('should update existing file from file dialog', () => {
const openDialogSpy = spyOn(component.dialog, 'open')
.and.returnValue({afterClosed: () => of({fileMetaId: mockFileMetaReference0.id, file: mockFileMetaReference0.file})} as any);
.and.returnValue({
afterClosed: () => of({
fileMetaId: mockFileMetaReference0.id,
file: mockFileMetaReference0.file
})
} as any);
const _loadReferenceFilesSpy = spyOn((component as any), '_loadReferenceFiles').and.stub();
component.openFileDialog(mockFileMetaReference0);

View File

@ -1,15 +0,0 @@
<div class="full-height" fxLayout="column" fxLayoutAlign="center center">
<h1>Fake UVA NetBadge Sign In (for testing only)</h1>
<formly-form [fields]="fields" [form]="form" [model]="model">
<mat-error *ngIf="error">{{error}}</mat-error>
<button
(click)="signIn()"
[disabled]="form.invalid"
color="primary"
id="sign_in"
mat-flat-button
>
Sign in
</button>
</formly-form>
</div>

View File

@ -1,9 +0,0 @@
form {
min-width: 150px;
max-width: 500px;
width: 100%;
}
.full-width {
width: 100%;
}

View File

@ -1,100 +0,0 @@
import {HttpClientTestingModule, HttpTestingController} from '@angular/common/http/testing';
import {async, ComponentFixture, TestBed} from '@angular/core/testing';
import {FormsModule} from '@angular/forms';
import {MatFormFieldModule} from '@angular/material/form-field';
import {MatInputModule} from '@angular/material/input';
import {BrowserAnimationsModule, NoopAnimationsModule} from '@angular/platform-browser/animations';
import {ActivatedRoute, convertToParamMap, Router} from '@angular/router';
import {RouterTestingModule} from '@angular/router/testing';
import {FormlyModule} from '@ngx-formly/core';
import {FormlyMaterialModule} from '@ngx-formly/material';
import {of} from 'rxjs';
import {ApiService, MockEnvironment, mockUser} from 'sartography-workflow-lib';
import {EmailValidator, EmailValidatorMessage} from '../_forms/validators/formly.validator';
import {SignInComponent} from './sign-in.component';
describe('SignInComponent', () => {
let component: SignInComponent;
let fixture: ComponentFixture<SignInComponent>;
let httpMock: HttpTestingController;
const mockRouter = {navigate: jasmine.createSpy('navigate')};
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [SignInComponent],
imports: [
BrowserAnimationsModule,
FormlyModule.forRoot({
validators: [
{name: 'email', validation: EmailValidator},
],
validationMessages: [
{name: 'email', message: EmailValidatorMessage},
],
}),
FormlyMaterialModule,
HttpClientTestingModule,
FormsModule,
MatFormFieldModule,
MatInputModule,
NoopAnimationsModule,
RouterTestingModule,
],
providers: [
ApiService,
{
provide: ActivatedRoute,
useValue: {paramMap: of(convertToParamMap({study_id: '0', workflow_id: '0', task_id: '0'}))}
},
{
provide: Router,
useValue: mockRouter
},
{provide: 'APP_ENVIRONMENT', useClass: MockEnvironment},
],
})
.compileComponents();
}));
beforeEach(() => {
httpMock = TestBed.inject(HttpTestingController);
fixture = TestBed.createComponent(SignInComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
afterEach(() => {
httpMock.verify();
fixture.destroy();
});
it('should create', () => {
expect(component).toBeTruthy();
});
it('should fake sign in during testing', () => {
const redirectToLoginSpy = spyOn((component as any).api, 'redirectToLogin').and.stub();
(component as any).environment.production = false;
component.model = mockUser;
component.signIn();
expect(redirectToLoginSpy).toHaveBeenCalledWith(jasmine.any(String), mockUser);
expect(component.error).toBeUndefined();
});
it('should display an error if sign in is called on production', () => {
const redirectToLoginSpy = spyOn((component as any).api, 'redirectToLogin').and.stub();
(component as any).environment.production = true;
component.signIn();
expect(redirectToLoginSpy).not.toHaveBeenCalled();
expect(component.error).toBeTruthy();
});
it('should verify the user and redirect to home page on production', () => {
const getUserSpy = spyOn((component as any).api, 'getUser').and.returnValue(of(mockUser));
(component as any).environment.production = true;
(component as any)._redirectOnProduction();
expect(getUserSpy).toHaveBeenCalled();
expect(mockRouter.navigate).toHaveBeenCalledWith(['/']);
});
});

View File

@ -1,96 +0,0 @@
import {PlatformLocation} from '@angular/common';
import {Component, Inject, OnInit} from '@angular/core';
import {FormGroup} from '@angular/forms';
import {Router} from '@angular/router';
import {FormlyFieldConfig} from '@ngx-formly/core';
import {ApiService, AppEnvironment, User} from 'sartography-workflow-lib';
@Component({
selector: 'app-sign-in',
templateUrl: './sign-in.component.html',
styleUrls: ['./sign-in.component.scss']
})
export class SignInComponent implements OnInit {
form = new FormGroup({});
model: any = {};
fields: FormlyFieldConfig[] = [
{
key: 'uid',
type: 'input',
defaultValue: 'czn1z',
templateOptions: {
required: true,
label: 'UVA Computing ID',
},
},
{
key: 'email_address',
type: 'input',
defaultValue: 'czn1z@virginia.edu',
templateOptions: {
required: true,
type: 'email',
label: 'UVA Email Address',
},
validators: {validation: ['email']},
},
{
key: 'first_name',
type: 'input',
defaultValue: 'Addison',
templateOptions: {
label: 'First Name',
},
},
{
key: 'last_name',
type: 'input',
defaultValue: 'Minh',
templateOptions: {
label: 'First Name',
},
},
];
error: Error;
constructor(
@Inject('APP_ENVIRONMENT') private environment: AppEnvironment,
private router: Router,
private api: ApiService
) {
}
ngOnInit() {
this._redirectOnProduction();
}
signIn() {
this.error = undefined;
localStorage.removeItem('token');
// For testing purposes, create a user to simulate login.
if (!this.environment.production) {
localStorage.setItem('prev_url', location.origin);
this.model.redirect_url = location.origin + '/session';
this.api.redirectToLogin(this.model.redirect_url, this.model);
} else {
this.error = new Error('This feature does not work in production.');
}
}
// If this is production, verify the user and redirect to home page.
private _redirectOnProduction() {
if (this.environment.production) {
this.api.getUser().subscribe((user: User) => {
this.router.navigate(['/']);
}, e => {
this.error = e;
localStorage.removeItem('token');
this.router.navigate(['/']);
});
} else {
localStorage.removeItem('token');
}
}
}

View File

@ -1,7 +0,0 @@
<div class="full-height" fxLayout="column" fxLayoutAlign="center center">
<h1>You have been signed out.</h1>
<button
mat-flat-button
color="accent"
(click)="goHome()">Ok</button>
</div>

View File

@ -1,49 +0,0 @@
import {HttpClientTestingModule, HttpTestingController} from '@angular/common/http/testing';
import {async, ComponentFixture, TestBed} from '@angular/core/testing';
import {RouterTestingModule} from '@angular/router/testing';
import {ApiService, MockEnvironment} from 'sartography-workflow-lib';
import {SignOutComponent} from './sign-out.component';
describe('SignOutComponent', () => {
let component: SignOutComponent;
let fixture: ComponentFixture<SignOutComponent>;
let httpMock: HttpTestingController;
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [SignOutComponent],
imports: [
HttpClientTestingModule,
RouterTestingModule,
],
providers: [
ApiService,
{provide: 'APP_ENVIRONMENT', useClass: MockEnvironment},
],
})
.compileComponents();
}));
beforeEach(() => {
httpMock = TestBed.inject(HttpTestingController);
fixture = TestBed.createComponent(SignOutComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
afterEach(() => {
httpMock.verify();
fixture.destroy();
});
it('should create', () => {
expect(component).toBeTruthy();
});
it('should go home', () => {
const openUrlSpy = spyOn((component as any).api, 'openUrl').and.stub();
component.goHome();
expect(openUrlSpy).toHaveBeenCalledWith('/');
});
});

View File

@ -1,21 +0,0 @@
import {Component, OnInit} from '@angular/core';
import {ApiService} from 'sartography-workflow-lib';
@Component({
selector: 'app-sign-out',
templateUrl: './sign-out.component.html',
styleUrls: ['./sign-out.component.scss']
})
export class SignOutComponent implements OnInit {
constructor(private api: ApiService) {
localStorage.removeItem('token');
}
ngOnInit() {
}
goHome() {
this.api.openUrl('/');
}
}

View File

@ -1,3 +1,4 @@
import {APP_BASE_HREF} from '@angular/common';
import {HttpClientTestingModule} from '@angular/common/http/testing';
import {async, ComponentFixture, TestBed} from '@angular/core/testing';
import {MatCardModule} from '@angular/material/card';
@ -34,6 +35,7 @@ describe('WorkflowSpecCardComponent', () => {
providers: [
ApiService,
{provide: 'APP_ENVIRONMENT', useClass: MockEnvironment},
{provide: APP_BASE_HREF, useValue: ''},
{
provide: MatDialogRef,
useValue: {

View File

@ -1,3 +1,4 @@
import {APP_BASE_HREF} from '@angular/common';
import {HttpClientTestingModule, HttpTestingController} from '@angular/common/http/testing';
import {async, ComponentFixture, TestBed} from '@angular/core/testing';
import {MAT_BOTTOM_SHEET_DATA, MatBottomSheetModule, MatBottomSheetRef} from '@angular/material/bottom-sheet';
@ -15,11 +16,14 @@ import {
ApiService,
MockEnvironment,
mockWorkflowSpec0,
mockWorkflowSpec1, mockWorkflowSpec2,
mockWorkflowSpec1,
mockWorkflowSpec2,
mockWorkflowSpecCategories,
mockWorkflowSpecCategory0,
mockWorkflowSpecCategory1, mockWorkflowSpecCategory2,
mockWorkflowSpecs, moveArrayElementUp, WorkflowSpec, WorkflowSpecCategory
mockWorkflowSpecCategory1,
mockWorkflowSpecCategory2,
mockWorkflowSpecs,
WorkflowSpec
} from 'sartography-workflow-lib';
import {ApiError} from 'sartography-workflow-lib/lib/types/api';
import {DeleteWorkflowSpecDialogComponent} from '../_dialogs/delete-workflow-spec-dialog/delete-workflow-spec-dialog.component';
@ -32,7 +36,7 @@ import {
import {GetIconCodePipe} from '../_pipes/get-icon-code.pipe';
import {ApiErrorsComponent} from '../api-errors/api-errors.component';
import {FileListComponent} from '../file-list/file-list.component';
import {WorkflowSpecCategoryGroup, WorkflowSpecListComponent} from './workflow-spec-list.component';
import {WorkflowSpecListComponent} from './workflow-spec-list.component';
describe('WorkflowSpecListComponent', () => {
let httpMock: HttpTestingController;
@ -62,6 +66,7 @@ describe('WorkflowSpecListComponent', () => {
providers: [
ApiService,
{provide: 'APP_ENVIRONMENT', useClass: MockEnvironment},
{provide: APP_BASE_HREF, useValue: ''},
{
provide: MatDialogRef,
useValue: {
@ -366,7 +371,7 @@ describe('WorkflowSpecListComponent', () => {
const snackBarSpy = spyOn((component as any).snackBar, 'open').and.stub();
const moveUpSpy = spyOn(component, 'moveUp').and.callThrough();
const moveDownSpy = spyOn(component, 'moveDown').and.callThrough();
const expectedCatsAfter = [ mockWorkflowSpecCategory1, mockWorkflowSpecCategory0, mockWorkflowSpecCategory2 ];
const expectedCatsAfter = [mockWorkflowSpecCategory1, mockWorkflowSpecCategory0, mockWorkflowSpecCategory2];
expect((component as any)._reorder(99, 1, mockWorkflowSpecCategories)).toEqual([]);
expect(snackBarSpy).toHaveBeenCalled();

View File

@ -0,0 +1 @@
<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="24" height="24" viewBox="0 0 24 24"><path d="M13,9H18.5L13,3.5V9M6,2H14L20,8V20A2,2 0 0,1 18,22H6C4.89,22 4,21.1 4,20V4C4,2.89 4.89,2 6,2M6,20H15L18,20V12L14,16L12,14L6,20M8,9A2,2 0 0,0 6,11A2,2 0 0,0 8,13A2,2 0 0,0 10,11A2,2 0 0,0 8,9Z" /></svg>

After

Width:  |  Height:  |  Size: 486 B

View File

@ -0,0 +1 @@
<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="24" height="24" viewBox="0 0 24 24"><path d="M13,9H18.5L13,3.5V9M6,2H14L20,8V20A2,2 0 0,1 18,22H6C4.89,22 4,21.1 4,20V4C4,2.89 4.89,2 6,2M9,16A2,2 0 0,0 7,18A2,2 0 0,0 9,20A2,2 0 0,0 11,18V13H14V11H10V16.27C9.71,16.1 9.36,16 9,16Z" /></svg>

After

Width:  |  Height:  |  Size: 480 B

View File

@ -0,0 +1 @@
<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="24" height="24" viewBox="0 0 24 24"><path d="M13,9H18.5L13,3.5V9M6,2H14L20,8V20A2,2 0 0,1 18,22H6C4.89,22 4,21.1 4,20V4C4,2.89 4.89,2 6,2M17,19V13L14,15.2V13H7V19H14V16.8L17,19Z" /></svg>

After

Width:  |  Height:  |  Size: 427 B

View File

@ -0,0 +1 @@
<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="24" height="24" viewBox="0 0 24 24"><path d="M13,9H18.5L13,3.5V9M6,2H14L20,8V20A2,2 0 0,1 18,22H6C4.89,22 4,21.1 4,20V4C4,2.89 4.89,2 6,2M6.12,15.5L9.86,19.24L11.28,17.83L8.95,15.5L11.28,13.17L9.86,11.76L6.12,15.5M17.28,15.5L13.54,11.76L12.12,13.17L14.45,15.5L12.12,17.83L13.54,19.24L17.28,15.5Z" /></svg>

After

Width:  |  Height:  |  Size: 545 B

View File

@ -0,0 +1 @@
<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="24" height="24" viewBox="0 0 24 24"><path d="M6,2H14L20,8V20A2,2 0 0,1 18,22H6A2,2 0 0,1 4,20V4A2,2 0 0,1 6,2M13,3.5V9H18.5L13,3.5M17,11H13V13H14L12,14.67L10,13H11V11H7V13H8L11,15.5L8,18H7V20H11V18H10L12,16.33L14,18H13V20H17V18H16L13,15.5L16,13H17V11Z" /></svg>

After

Width:  |  Height:  |  Size: 501 B

View File

@ -0,0 +1 @@
<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="24" height="24" viewBox="0 0 24 24"><path d="M6,2H18A2,2 0 0,1 20,4V20A2,2 0 0,1 18,22H6A2,2 0 0,1 4,20V4A2,2 0 0,1 6,2M12,4A6,6 0 0,0 6,10C6,13.31 8.69,16 12.1,16L11.22,13.77C10.95,13.29 11.11,12.68 11.59,12.4L12.45,11.9C12.93,11.63 13.54,11.79 13.82,12.27L15.74,14.69C17.12,13.59 18,11.9 18,10A6,6 0 0,0 12,4M12,9A1,1 0 0,1 13,10A1,1 0 0,1 12,11A1,1 0 0,1 11,10A1,1 0 0,1 12,9M7,18A1,1 0 0,0 6,19A1,1 0 0,0 7,20A1,1 0 0,0 8,19A1,1 0 0,0 7,18M12.09,13.27L14.58,19.58L17.17,18.08L12.95,12.77L12.09,13.27Z" /></svg>

After

Width:  |  Height:  |  Size: 754 B

View File

@ -0,0 +1 @@
<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="24" height="24" viewBox="0 0 24 24"><path d="M13,9H18.5L13,3.5V9M6,2H14L20,8V20A2,2 0 0,1 18,22H6C4.89,22 4,21.1 4,20V4C4,2.89 4.89,2 6,2M6.12,15.5L9.86,19.24L11.28,17.83L8.95,15.5L11.28,13.17L9.86,11.76L6.12,15.5M17.28,15.5L13.54,11.76L12.12,13.17L14.45,15.5L12.12,17.83L13.54,19.24L17.28,15.5Z" /></svg>

After

Width:  |  Height:  |  Size: 545 B

View File

@ -0,0 +1 @@
<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="24" height="24" viewBox="0 0 24 24"><path d="M6,2H14L20,8V20A2,2 0 0,1 18,22H6A2,2 0 0,1 4,20V4A2,2 0 0,1 6,2M13,3.5V9H18.5L13,3.5M7,13L8.5,20H10.5L12,17L13.5,20H15.5L17,13H18V11H14V13H15L14.1,17.2L13,15V15H11V15L9.9,17.2L9,13H10V11H6V13H7Z" /></svg>

After

Width:  |  Height:  |  Size: 490 B

View File

@ -0,0 +1 @@
<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="24" height="24" viewBox="0 0 24 24"><path d="M6,2H14L20,8V20A2,2 0 0,1 18,22H6A2,2 0 0,1 4,20V4A2,2 0 0,1 6,2M13,3.5V9H18.5L13,3.5M7,13L8.5,20H10.5L12,17L13.5,20H15.5L17,13H18V11H14V13H15L14.1,17.2L13,15V15H11V15L9.9,17.2L9,13H10V11H6V13H7Z" /></svg>

After

Width:  |  Height:  |  Size: 490 B

View File

@ -0,0 +1 @@
<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="24" height="24" viewBox="0 0 24 24"><path d="M13,9H18.5L13,3.5V9M6,2H14L20,8V20A2,2 0 0,1 18,22H6C4.89,22 4,21.1 4,20V4C4,2.89 4.89,2 6,2M6,20H15L18,20V12L14,16L12,14L6,20M8,9A2,2 0 0,0 6,11A2,2 0 0,0 8,13A2,2 0 0,0 10,11A2,2 0 0,0 8,9Z" /></svg>

After

Width:  |  Height:  |  Size: 486 B

View File

@ -0,0 +1 @@
<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="24" height="24" viewBox="0 0 24 24"><path d="M13,9H18.5L13,3.5V9M6,2H14L20,8V20A2,2 0 0,1 18,22H6C4.89,22 4,21.1 4,20V4C4,2.89 4.89,2 6,2M6.12,15.5L9.86,19.24L11.28,17.83L8.95,15.5L11.28,13.17L9.86,11.76L6.12,15.5M17.28,15.5L13.54,11.76L12.12,13.17L14.45,15.5L12.12,17.83L13.54,19.24L17.28,15.5Z" /></svg>

After

Width:  |  Height:  |  Size: 545 B

View File

@ -0,0 +1 @@
<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="24" height="24" viewBox="0 0 24 24"><path d="M6,2C4.89,2 4,2.89 4,4V20A2,2 0 0,0 6,22H18A2,2 0 0,0 20,20V8L14,2H6M13,3.5L18.5,9H13V3.5M12,11A3,3 0 0,1 15,14C15,15.88 12.75,16.06 12.75,17.75H11.25C11.25,15.31 13.5,15.5 13.5,14A1.5,1.5 0 0,0 12,12.5A1.5,1.5 0 0,0 10.5,14H9A3,3 0 0,1 12,11M11.25,18.5H12.75V20H11.25V18.5Z" /></svg>

After

Width:  |  Height:  |  Size: 569 B

View File

@ -0,0 +1 @@
<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="24" height="24" viewBox="0 0 24 24"><path d="M6,2H18A2,2 0 0,1 20,4V20A2,2 0 0,1 18,22H6A2,2 0 0,1 4,20V4A2,2 0 0,1 6,2M12,4A6,6 0 0,0 6,10C6,13.31 8.69,16 12.1,16L11.22,13.77C10.95,13.29 11.11,12.68 11.59,12.4L12.45,11.9C12.93,11.63 13.54,11.79 13.82,12.27L15.74,14.69C17.12,13.59 18,11.9 18,10A6,6 0 0,0 12,4M12,9A1,1 0 0,1 13,10A1,1 0 0,1 12,11A1,1 0 0,1 11,10A1,1 0 0,1 12,9M7,18A1,1 0 0,0 6,19A1,1 0 0,0 7,20A1,1 0 0,0 8,19A1,1 0 0,0 7,18M12.09,13.27L14.58,19.58L17.17,18.08L12.95,12.77L12.09,13.27Z" /></svg>

After

Width:  |  Height:  |  Size: 754 B

View File

@ -0,0 +1 @@
<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="24" height="24" viewBox="0 0 24 24"><path d="M13,9H18.5L13,3.5V9M6,2H14L20,8V20A2,2 0 0,1 18,22H6C4.89,22 4,21.1 4,20V4C4,2.89 4.89,2 6,2M6.12,15.5L9.86,19.24L11.28,17.83L8.95,15.5L11.28,13.17L9.86,11.76L6.12,15.5M17.28,15.5L13.54,11.76L12.12,13.17L14.45,15.5L12.12,17.83L13.54,19.24L17.28,15.5Z" /></svg>

After

Width:  |  Height:  |  Size: 545 B

View File

@ -0,0 +1 @@
<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="24" height="24" viewBox="0 0 24 24"><path d="M13,9H18.5L13,3.5V9M6,2H14L20,8V20A2,2 0 0,1 18,22H6C4.89,22 4,21.1 4,20V4C4,2.89 4.89,2 6,2M6,20H15L18,20V12L14,16L12,14L6,20M8,9A2,2 0 0,0 6,11A2,2 0 0,0 8,13A2,2 0 0,0 10,11A2,2 0 0,0 8,9Z" /></svg>

After

Width:  |  Height:  |  Size: 486 B

View File

@ -0,0 +1 @@
<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="24" height="24" viewBox="0 0 24 24"><path d="M13,9H18.5L13,3.5V9M6,2H14L20,8V20A2,2 0 0,1 18,22H6C4.89,22 4,21.1 4,20V4C4,2.89 4.89,2 6,2M6,20H15L18,20V12L14,16L12,14L6,20M8,9A2,2 0 0,0 6,11A2,2 0 0,0 8,13A2,2 0 0,0 10,11A2,2 0 0,0 8,9Z" /></svg>

After

Width:  |  Height:  |  Size: 486 B

View File

@ -0,0 +1 @@
<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="24" height="24" viewBox="0 0 24 24"><path d="M13,9H18.5L13,3.5V9M6,2H14L20,8V20A2,2 0 0,1 18,22H6C4.89,22 4,21.1 4,20V4C4,2.89 4.89,2 6,2M6.12,15.5L9.86,19.24L11.28,17.83L8.95,15.5L11.28,13.17L9.86,11.76L6.12,15.5M17.28,15.5L13.54,11.76L12.12,13.17L14.45,15.5L12.12,17.83L13.54,19.24L17.28,15.5Z" /></svg>

After

Width:  |  Height:  |  Size: 545 B

View File

@ -0,0 +1 @@
<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="24" height="24" viewBox="0 0 24 24"><path d="M6,2H14L20,8V20A2,2 0 0,1 18,22H6A2,2 0 0,1 4,20V4A2,2 0 0,1 6,2M13,3.5V9H18.5L13,3.5M7,13L8.5,20H10.5L12,17L13.5,20H15.5L17,13H18V11H14V13H15L14.1,17.2L13,15V15H11V15L9.9,17.2L9,13H10V11H6V13H7Z" /></svg>

After

Width:  |  Height:  |  Size: 490 B

View File

@ -0,0 +1 @@
<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="24" height="24" viewBox="0 0 24 24"><path d="M13,9H18.5L13,3.5V9M6,2H14L20,8V20A2,2 0 0,1 18,22H6C4.89,22 4,21.1 4,20V4C4,2.89 4.89,2 6,2M17,19V13L14,15.2V13H7V19H14V16.8L17,19Z" /></svg>

After

Width:  |  Height:  |  Size: 427 B

View File

@ -0,0 +1 @@
<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="24" height="24" viewBox="0 0 24 24"><path d="M13,9H18.5L13,3.5V9M6,2H14L20,8V20A2,2 0 0,1 18,22H6C4.89,22 4,21.1 4,20V4C4,2.89 4.89,2 6,2M9,16A2,2 0 0,0 7,18A2,2 0 0,0 9,20A2,2 0 0,0 11,18V13H14V11H10V16.27C9.71,16.1 9.36,16 9,16Z" /></svg>

After

Width:  |  Height:  |  Size: 480 B

View File

@ -0,0 +1 @@
<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="24" height="24" viewBox="0 0 24 24"><path d="M13,9H18.5L13,3.5V9M6,2H14L20,8V20A2,2 0 0,1 18,22H6C4.89,22 4,21.1 4,20V4C4,2.89 4.89,2 6,2M17,19V13L14,15.2V13H7V19H14V16.8L17,19Z" /></svg>

After

Width:  |  Height:  |  Size: 427 B

View File

@ -0,0 +1 @@
<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="24" height="24" viewBox="0 0 24 24"><path d="M13,9H18.5L13,3.5V9M6,2H14L20,8V20A2,2 0 0,1 18,22H6C4.89,22 4,21.1 4,20V4C4,2.89 4.89,2 6,2M17,19V13L14,15.2V13H7V19H14V16.8L17,19Z" /></svg>

After

Width:  |  Height:  |  Size: 427 B

View File

@ -0,0 +1 @@
<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="24" height="24" viewBox="0 0 24 24"><path d="M6,2H18A2,2 0 0,1 20,4V20A2,2 0 0,1 18,22H6A2,2 0 0,1 4,20V4A2,2 0 0,1 6,2M12,4A6,6 0 0,0 6,10C6,13.31 8.69,16 12.1,16L11.22,13.77C10.95,13.29 11.11,12.68 11.59,12.4L12.45,11.9C12.93,11.63 13.54,11.79 13.82,12.27L15.74,14.69C17.12,13.59 18,11.9 18,10A6,6 0 0,0 12,4M12,9A1,1 0 0,1 13,10A1,1 0 0,1 12,11A1,1 0 0,1 11,10A1,1 0 0,1 12,9M7,18A1,1 0 0,0 6,19A1,1 0 0,0 7,20A1,1 0 0,0 8,19A1,1 0 0,0 7,18M12.09,13.27L14.58,19.58L17.17,18.08L12.95,12.77L12.09,13.27Z" /></svg>

After

Width:  |  Height:  |  Size: 754 B

View File

@ -0,0 +1 @@
<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="24" height="24" viewBox="0 0 24 24"><path d="M13,9H18.5L13,3.5V9M6,2H14L20,8V20A2,2 0 0,1 18,22H6C4.89,22 4,21.1 4,20V4C4,2.89 4.89,2 6,2M9,16A2,2 0 0,0 7,18A2,2 0 0,0 9,20A2,2 0 0,0 11,18V13H14V11H10V16.27C9.71,16.1 9.36,16 9,16Z" /></svg>

After

Width:  |  Height:  |  Size: 480 B

View File

@ -0,0 +1 @@
<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="24" height="24" viewBox="0 0 24 24"><path d="M14,9H19.5L14,3.5V9M7,2H15L21,8V20A2,2 0 0,1 19,22H7C5.89,22 5,21.1 5,20V4A2,2 0 0,1 7,2M11.93,12.44C12.34,13.34 12.86,14.08 13.46,14.59L13.87,14.91C13,15.07 11.8,15.35 10.53,15.84V15.84L10.42,15.88L10.92,14.84C11.37,13.97 11.7,13.18 11.93,12.44M18.41,16.25C18.59,16.07 18.68,15.84 18.69,15.59C18.72,15.39 18.67,15.2 18.57,15.04C18.28,14.57 17.53,14.35 16.29,14.35L15,14.42L14.13,13.84C13.5,13.32 12.93,12.41 12.53,11.28L12.57,11.14C12.9,9.81 13.21,8.2 12.55,7.54C12.39,7.38 12.17,7.3 11.94,7.3H11.7C11.33,7.3 11,7.69 10.91,8.07C10.54,9.4 10.76,10.13 11.13,11.34V11.35C10.88,12.23 10.56,13.25 10.05,14.28L9.09,16.08L8.2,16.57C7,17.32 6.43,18.16 6.32,18.69C6.28,18.88 6.3,19.05 6.37,19.23L6.4,19.28L6.88,19.59L7.32,19.7C8.13,19.7 9.05,18.75 10.29,16.63L10.47,16.56C11.5,16.23 12.78,16 14.5,15.81C15.53,16.32 16.74,16.55 17.5,16.55C17.94,16.55 18.24,16.44 18.41,16.25M18,15.54L18.09,15.65C18.08,15.75 18.05,15.76 18,15.78H17.96L17.77,15.8C17.31,15.8 16.6,15.61 15.87,15.29C15.96,15.19 16,15.19 16.1,15.19C17.5,15.19 17.9,15.44 18,15.54M8.83,17C8.18,18.19 7.59,18.85 7.14,19C7.19,18.62 7.64,17.96 8.35,17.31L8.83,17M11.85,10.09C11.62,9.19 11.61,8.46 11.78,8.04L11.85,7.92L12,7.97C12.17,8.21 12.19,8.53 12.09,9.07L12.06,9.23L11.9,10.05L11.85,10.09Z" /></svg>

After

Width:  |  Height:  |  Size: 1.5 KiB

View File

@ -0,0 +1 @@
<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="24" height="24" viewBox="0 0 24 24"><path d="M13,9H18.5L13,3.5V9M6,2H14L20,8V20A2,2 0 0,1 18,22H6C4.89,22 4,21.1 4,20V4C4,2.89 4.89,2 6,2M6.12,15.5L9.86,19.24L11.28,17.83L8.95,15.5L11.28,13.17L9.86,11.76L6.12,15.5M17.28,15.5L13.54,11.76L12.12,13.17L14.45,15.5L12.12,17.83L13.54,19.24L17.28,15.5Z" /></svg>

After

Width:  |  Height:  |  Size: 545 B

View File

@ -0,0 +1 @@
<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="24" height="24" viewBox="0 0 24 24"><path d="M6,2H18A2,2 0 0,1 20,4V20A2,2 0 0,1 18,22H6A2,2 0 0,1 4,20V4A2,2 0 0,1 6,2M12,4A6,6 0 0,0 6,10C6,13.31 8.69,16 12.1,16L11.22,13.77C10.95,13.29 11.11,12.68 11.59,12.4L12.45,11.9C12.93,11.63 13.54,11.79 13.82,12.27L15.74,14.69C17.12,13.59 18,11.9 18,10A6,6 0 0,0 12,4M12,9A1,1 0 0,1 13,10A1,1 0 0,1 12,11A1,1 0 0,1 11,10A1,1 0 0,1 12,9M7,18A1,1 0 0,0 6,19A1,1 0 0,0 7,20A1,1 0 0,0 8,19A1,1 0 0,0 7,18M12.09,13.27L14.58,19.58L17.17,18.08L12.95,12.77L12.09,13.27Z" /></svg>

After

Width:  |  Height:  |  Size: 754 B

View File

@ -0,0 +1 @@
<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="24" height="24" viewBox="0 0 24 24"><path d="M6,2H14L20,8V20A2,2 0 0,1 18,22H6A2,2 0 0,1 4,20V4A2,2 0 0,1 6,2M13,3.5V9H18.5L13,3.5M7,13L8.5,20H10.5L12,17L13.5,20H15.5L17,13H18V11H14V13H15L14.1,17.2L13,15V15H11V15L9.9,17.2L9,13H10V11H6V13H7Z" /></svg>

After

Width:  |  Height:  |  Size: 490 B

View File

@ -0,0 +1 @@
<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="24" height="24" viewBox="0 0 24 24"><path d="M13,9H18.5L13,3.5V9M6,2H14L20,8V20A2,2 0 0,1 18,22H6C4.89,22 4,21.1 4,20V4C4,2.89 4.89,2 6,2M6.12,15.5L9.86,19.24L11.28,17.83L8.95,15.5L11.28,13.17L9.86,11.76L6.12,15.5M17.28,15.5L13.54,11.76L12.12,13.17L14.45,15.5L12.12,17.83L13.54,19.24L17.28,15.5Z" /></svg>

After

Width:  |  Height:  |  Size: 545 B

View File

@ -0,0 +1 @@
<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="24" height="24" viewBox="0 0 24 24"><path d="M13,9H18.5L13,3.5V9M6,2H14L20,8V20A2,2 0 0,1 18,22H6C4.89,22 4,21.1 4,20V4C4,2.89 4.89,2 6,2M6,20H15L18,20V12L14,16L12,14L6,20M8,9A2,2 0 0,0 6,11A2,2 0 0,0 8,13A2,2 0 0,0 10,11A2,2 0 0,0 8,9Z" /></svg>

After

Width:  |  Height:  |  Size: 486 B

View File

@ -0,0 +1 @@
<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="24" height="24" viewBox="0 0 24 24"><path d="M13,9H18.5L13,3.5V9M6,2H14L20,8V20A2,2 0 0,1 18,22H6C4.89,22 4,21.1 4,20V4C4,2.89 4.89,2 6,2M6,20H15L18,20V12L14,16L12,14L6,20M8,9A2,2 0 0,0 6,11A2,2 0 0,0 8,13A2,2 0 0,0 10,11A2,2 0 0,0 8,9Z" /></svg>

After

Width:  |  Height:  |  Size: 486 B

View File

@ -0,0 +1 @@
<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="24" height="24" viewBox="0 0 24 24"><path d="M6,2H14L20,8V20A2,2 0 0,1 18,22H6A2,2 0 0,1 4,20V4A2,2 0 0,1 6,2M13,3.5V9H18.5L13,3.5M8,11V13H9V19H8V20H12V19H11V17H13A3,3 0 0,0 16,14A3,3 0 0,0 13,11H8M13,13A1,1 0 0,1 14,14A1,1 0 0,1 13,15H11V13H13Z" /></svg>

After

Width:  |  Height:  |  Size: 495 B

View File

@ -0,0 +1 @@
<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="24" height="24" viewBox="0 0 24 24"><path d="M6,2H14L20,8V20A2,2 0 0,1 18,22H6A2,2 0 0,1 4,20V4A2,2 0 0,1 6,2M13,3.5V9H18.5L13,3.5M8,11V13H9V19H8V20H12V19H11V17H13A3,3 0 0,0 16,14A3,3 0 0,0 13,11H8M13,13A1,1 0 0,1 14,14A1,1 0 0,1 13,15H11V13H13Z" /></svg>

After

Width:  |  Height:  |  Size: 495 B

View File

@ -0,0 +1 @@
<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="24" height="24" viewBox="0 0 24 24"><path d="M13,9H18.5L13,3.5V9M6,2H14L20,8V20A2,2 0 0,1 18,22H6C4.89,22 4,21.1 4,20V4C4,2.89 4.89,2 6,2M6,20H15L18,20V12L14,16L12,14L6,20M8,9A2,2 0 0,0 6,11A2,2 0 0,0 8,13A2,2 0 0,0 10,11A2,2 0 0,0 8,9Z" /></svg>

After

Width:  |  Height:  |  Size: 486 B

View File

@ -0,0 +1 @@
<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="24" height="24" viewBox="0 0 24 24"><path d="M13,9H18.5L13,3.5V9M6,2H14L20,8V20A2,2 0 0,1 18,22H6C4.89,22 4,21.1 4,20V4C4,2.89 4.89,2 6,2M6.12,15.5L9.86,19.24L11.28,17.83L8.95,15.5L11.28,13.17L9.86,11.76L6.12,15.5M17.28,15.5L13.54,11.76L12.12,13.17L14.45,15.5L12.12,17.83L13.54,19.24L17.28,15.5Z" /></svg>

After

Width:  |  Height:  |  Size: 545 B

View File

@ -0,0 +1 @@
<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="24" height="24" viewBox="0 0 24 24"><path d="M6,2H14L20,8V20A2,2 0 0,1 18,22H6A2,2 0 0,1 4,20V4A2,2 0 0,1 6,2M13,3.5V9H18.5L13,3.5M7,13L8.5,20H10.5L12,17L13.5,20H15.5L17,13H18V11H14V13H15L14.1,17.2L13,15V15H11V15L9.9,17.2L9,13H10V11H6V13H7Z" /></svg>

After

Width:  |  Height:  |  Size: 490 B

View File

@ -0,0 +1 @@
<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="24" height="24" viewBox="0 0 24 24"><path d="M13,9H18.5L13,3.5V9M6,2H14L20,8V20A2,2 0 0,1 18,22H6C4.89,22 4,21.1 4,20V4C4,2.89 4.89,2 6,2M6.12,15.5L9.86,19.24L11.28,17.83L8.95,15.5L11.28,13.17L9.86,11.76L6.12,15.5M17.28,15.5L13.54,11.76L12.12,13.17L14.45,15.5L12.12,17.83L13.54,19.24L17.28,15.5Z" /></svg>

After

Width:  |  Height:  |  Size: 545 B

View File

@ -0,0 +1 @@
<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="24" height="24" viewBox="0 0 24 24"><path d="M13,9H18.5L13,3.5V9M6,2H14L20,8V20A2,2 0 0,1 18,22H6C4.89,22 4,21.1 4,20V4C4,2.89 4.89,2 6,2M6,20H15L18,20V12L14,16L12,14L6,20M8,9A2,2 0 0,0 6,11A2,2 0 0,0 8,13A2,2 0 0,0 10,11A2,2 0 0,0 8,9Z" /></svg>

After

Width:  |  Height:  |  Size: 486 B

View File

@ -0,0 +1 @@
<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="24" height="24" viewBox="0 0 24 24"><path d="M13,9H18.5L13,3.5V9M6,2H14L20,8V20A2,2 0 0,1 18,22H6C4.89,22 4,21.1 4,20V4C4,2.89 4.89,2 6,2M6,20H15L18,20V12L14,16L12,14L6,20M8,9A2,2 0 0,0 6,11A2,2 0 0,0 8,13A2,2 0 0,0 10,11A2,2 0 0,0 8,9Z" /></svg>

After

Width:  |  Height:  |  Size: 486 B

View File

@ -0,0 +1 @@
<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="24" height="24" viewBox="0 0 24 24"><path d="M6,2H18A2,2 0 0,1 20,4V20A2,2 0 0,1 18,22H6A2,2 0 0,1 4,20V4A2,2 0 0,1 6,2M12,4A6,6 0 0,0 6,10C6,13.31 8.69,16 12.1,16L11.22,13.77C10.95,13.29 11.11,12.68 11.59,12.4L12.45,11.9C12.93,11.63 13.54,11.79 13.82,12.27L15.74,14.69C17.12,13.59 18,11.9 18,10A6,6 0 0,0 12,4M12,9A1,1 0 0,1 13,10A1,1 0 0,1 12,11A1,1 0 0,1 11,10A1,1 0 0,1 12,9M7,18A1,1 0 0,0 6,19A1,1 0 0,0 7,20A1,1 0 0,0 8,19A1,1 0 0,0 7,18M12.09,13.27L14.58,19.58L17.17,18.08L12.95,12.77L12.09,13.27Z" /></svg>

After

Width:  |  Height:  |  Size: 754 B

View File

@ -0,0 +1 @@
<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="24" height="24" viewBox="0 0 24 24"><path d="M13,9H18.5L13,3.5V9M6,2H14L20,8V20A2,2 0 0,1 18,22H6C4.89,22 4,21.1 4,20V4C4,2.89 4.89,2 6,2M6,20H15L18,20V12L14,16L12,14L6,20M8,9A2,2 0 0,0 6,11A2,2 0 0,0 8,13A2,2 0 0,0 10,11A2,2 0 0,0 8,9Z" /></svg>

After

Width:  |  Height:  |  Size: 486 B

View File

@ -0,0 +1 @@
<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="24" height="24" viewBox="0 0 24 24"><path d="M6,2H14L20,8V20A2,2 0 0,1 18,22H6A2,2 0 0,1 4,20V4A2,2 0 0,1 6,2M13,3.5V9H18.5L13,3.5M7,13L8.5,20H10.5L12,17L13.5,20H15.5L17,13H18V11H14V13H15L14.1,17.2L13,15V15H11V15L9.9,17.2L9,13H10V11H6V13H7Z" /></svg>

After

Width:  |  Height:  |  Size: 490 B

View File

@ -0,0 +1 @@
<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="24" height="24" viewBox="0 0 24 24"><path d="M6,2C4.89,2 4,2.89 4,4V20A2,2 0 0,0 6,22H18A2,2 0 0,0 20,20V8L14,2H6M13,3.5L18.5,9H13V3.5M12,11A3,3 0 0,1 15,14C15,15.88 12.75,16.06 12.75,17.75H11.25C11.25,15.31 13.5,15.5 13.5,14A1.5,1.5 0 0,0 12,12.5A1.5,1.5 0 0,0 10.5,14H9A3,3 0 0,1 12,11M11.25,18.5H12.75V20H11.25V18.5Z" /></svg>

After

Width:  |  Height:  |  Size: 569 B

View File

@ -0,0 +1 @@
<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="24" height="24" viewBox="0 0 24 24"><path d="M13,9H18.5L13,3.5V9M6,2H14L20,8V20A2,2 0 0,1 18,22H6C4.89,22 4,21.1 4,20V4C4,2.89 4.89,2 6,2M9,16A2,2 0 0,0 7,18A2,2 0 0,0 9,20A2,2 0 0,0 11,18V13H14V11H10V16.27C9.71,16.1 9.36,16 9,16Z" /></svg>

After

Width:  |  Height:  |  Size: 480 B

View File

@ -0,0 +1 @@
<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="24" height="24" viewBox="0 0 24 24"><path d="M6,2H14L20,8V20A2,2 0 0,1 18,22H6A2,2 0 0,1 4,20V4A2,2 0 0,1 6,2M13,3.5V9H18.5L13,3.5M17,11H13V13H14L12,14.67L10,13H11V11H7V13H8L11,15.5L8,18H7V20H11V18H10L12,16.33L14,18H13V20H17V18H16L13,15.5L16,13H17V11Z" /></svg>

After

Width:  |  Height:  |  Size: 501 B

View File

@ -0,0 +1 @@
<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="24" height="24" viewBox="0 0 24 24"><path d="M6,2H14L20,8V20A2,2 0 0,1 18,22H6A2,2 0 0,1 4,20V4A2,2 0 0,1 6,2M13,3.5V9H18.5L13,3.5M17,11H13V13H14L12,14.67L10,13H11V11H7V13H8L11,15.5L8,18H7V20H11V18H10L12,16.33L14,18H13V20H17V18H16L13,15.5L16,13H17V11Z" /></svg>

After

Width:  |  Height:  |  Size: 501 B

View File

@ -0,0 +1 @@
<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="24" height="24" viewBox="0 0 24 24"><path d="M13,9H18.5L13,3.5V9M6,2H14L20,8V20A2,2 0 0,1 18,22H6C4.89,22 4,21.1 4,20V4C4,2.89 4.89,2 6,2M6.12,15.5L9.86,19.24L11.28,17.83L8.95,15.5L11.28,13.17L9.86,11.76L6.12,15.5M17.28,15.5L13.54,11.76L12.12,13.17L14.45,15.5L12.12,17.83L13.54,19.24L17.28,15.5Z" /></svg>

After

Width:  |  Height:  |  Size: 545 B

View File

@ -0,0 +1 @@
<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="24" height="24" viewBox="0 0 24 24"><path d="M6,2H18A2,2 0 0,1 20,4V20A2,2 0 0,1 18,22H6A2,2 0 0,1 4,20V4A2,2 0 0,1 6,2M12,4A6,6 0 0,0 6,10C6,13.31 8.69,16 12.1,16L11.22,13.77C10.95,13.29 11.11,12.68 11.59,12.4L12.45,11.9C12.93,11.63 13.54,11.79 13.82,12.27L15.74,14.69C17.12,13.59 18,11.9 18,10A6,6 0 0,0 12,4M12,9A1,1 0 0,1 13,10A1,1 0 0,1 12,11A1,1 0 0,1 11,10A1,1 0 0,1 12,9M7,18A1,1 0 0,0 6,19A1,1 0 0,0 7,20A1,1 0 0,0 8,19A1,1 0 0,0 7,18M12.09,13.27L14.58,19.58L17.17,18.08L12.95,12.77L12.09,13.27Z" /></svg>

After

Width:  |  Height:  |  Size: 754 B

View File

@ -0,0 +1,145 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
height="43.79221"
width="43.330002"
version="1.1"
viewBox="0 0 43.330002 43.79221"
data-name="Layer 1"
id="Layer_1"
sodipodi:docname="uva_rotunda.svg"
inkscape:version="0.92.4 (f8dce91, 2019-08-02)">
<sodipodi:namedview
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1"
objecttolerance="10"
gridtolerance="10"
guidetolerance="10"
inkscape:pageopacity="0"
inkscape:pageshadow="2"
inkscape:window-width="705"
inkscape:window-height="480"
id="namedview21"
showgrid="false"
fit-margin-top="8"
fit-margin-left="8"
fit-margin-right="8"
fit-margin-bottom="8"
inkscape:zoom="7.9215345"
inkscape:cx="21.665"
inkscape:cy="21.896104"
inkscape:window-x="912"
inkscape:window-y="253"
inkscape:window-maximized="0"
inkscape:current-layer="Layer_1" />
<metadata
id="metadata107">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title>Artboard 1</dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
<defs
id="defs4">
<style
id="style2">.cls-1,.cls-2{fill:#e57200;}.cls-2,.cls-3{fill-rule:evenodd;}.cls-3,.cls-4{fill:#232d4b;}</style>
</defs>
<title
id="title6">Artboard 1</title>
<polygon
transform="translate(4,1.562208)"
style="fill:#e57200"
id="polygon8"
points="22.87,30.46 22.87,19.25 25.23,19.25 25.23,30.46 "
class="cls-1" />
<polygon
transform="translate(4,1.562208)"
style="fill:#e57200"
id="polygon10"
points="10.16,30.46 10.16,19.25 12.44,19.25 12.44,30.46 "
class="cls-1" />
<polygon
transform="translate(4,1.562208)"
style="fill:#e57200"
id="polygon12"
points="13.23,30.46 13.23,19.25 15.66,19.25 15.66,30.46 "
class="cls-1" />
<polygon
transform="translate(4,1.562208)"
style="fill:#e57200"
id="polygon14"
points="16.44,30.46 16.44,19.25 18.87,19.25 18.87,30.46 "
class="cls-1" />
<polygon
transform="translate(4,1.562208)"
style="fill:#e57200"
id="polygon16"
points="22.09,19.25 22.09,30.46 19.66,30.46 19.66,19.25 "
class="cls-1" />
<polygon
transform="translate(4,1.562208)"
style="fill:#e57200"
id="polygon18"
points="11.13,18.46 17.84,14.33 24.22,18.46 "
class="cls-1" />
<polygon
transform="translate(4,1.562208)"
style="fill:#e57200"
id="polygon20"
points="9.62,18.46 4.01,18.46 4.01,14.29 16.41,14.29 "
class="cls-1" />
<polygon
transform="translate(4,1.562208)"
style="fill:#e57200"
id="polygon22"
points="19.23,14.29 31.31,14.29 31.31,18.46 25.67,18.46 "
class="cls-1" />
<path
style="fill:#e57200"
id="path24"
d="M 33.58,15.052206 H 9.74 a 13.6,13.6 0 0 1 23.84,0 z"
class="cls-1"
inkscape:connector-curvature="0" />
<path
style="fill:#e57200;fill-rule:evenodd"
id="path26"
d="m 8,22.752206 v -0.65 l 0.16,0.11 -0.11,0.35 v 0.19 z m 4.64,9.27 H 11.6 l 0.53,-0.38 0.52,0.38 z m 0.73,0 h -0.71 l -0.2,-0.62 0.54,-0.39 h -0.67 l -0.2,-0.63 -0.21,0.63 h -0.66 l 0.54,0.39 -0.21,0.62 H 8 v -9.19 l 0.5,-0.37 0.53,0.39 -0.2,-0.63 0.53,-0.38 H 8.71 l -0.2,-0.63 -0.09,0.28 -0.13,0.35 H 8 v -1 h 5.38 v 11.18 z m -5.37,-6.76 0.53,0.39 -0.2,0.63 0.53,-0.39 0.53,0.39 -0.2,-0.63 0.53,-0.39 H 9.07 l -0.2,-0.62 -0.2,0.62 z m 1.84,3.57 -0.21,0.63 0.53,-0.39 0.54,0.39 -0.21,-0.63 0.51,-0.39 h -0.62 l -0.21,-0.63 -0.2,0.63 H 9.31 l 0.54,0.39 z"
class="cls-2"
inkscape:connector-curvature="0" />
<polygon
transform="translate(4,1.562208)"
style="fill:#e57200;fill-rule:evenodd"
id="polygon28"
points="9.38,31.25 9.38,34.23 4.01,34.23 4.01,31.25 "
class="cls-2" />
<polygon
transform="translate(4,1.562208)"
style="fill:#e57200;fill-rule:evenodd"
id="polygon30"
points="26.01,31.25 31.31,31.25 31.31,34.23 26.01,34.23 "
class="cls-2" />
<path
style="fill:#e57200;fill-rule:evenodd"
id="path32"
d="m 22,35.792206 h -0.6 l 0.3,-0.22 z m -4.06,-0.87 -0.21,0.62 0.54,-0.38 0.53,0.38 -0.2,-0.62 0.53,-0.39 h -0.66 l -0.2,-0.63 -0.27,0.66 h -0.66 l 0.54,0.39 z m 3.43,0.41 -0.15,0.46 h -7 v -3 H 15 l -0.15,0.46 h -0.66 l 0.54,0.39 -0.21,0.63 0.54,-0.39 0.53,0.39 -0.2,-0.63 0.53,-0.39 h -0.66 l -0.15,-0.46 h 13.11 l -0.16,0.46 H 27.4 l 0.54,0.39 -0.21,0.63 0.54,-0.39 0.53,0.39 -0.2,-0.63 0.53,-0.39 h -0.66 l -0.15,-0.46 h 0.91 v 3 h -7.07 l -0.16,-0.46 0.54,-0.38 h -0.66 l -0.21,-0.63 -0.2,0.63 h -0.66 l 0.53,0.38 z m 4,-0.41 0.54,-0.39 h -0.66 l -0.25,-0.63 -0.2,0.63 h -0.66 l 0.53,0.39 -0.2,0.62 0.53,-0.38 0.54,0.38 -0.21,-0.62 z"
class="cls-2"
inkscape:connector-curvature="0" />
<path
style="fill:#e57200;fill-rule:evenodd"
id="path34"
d="m 35.31,22.132206 v 0.51 l -0.14,-0.42 z m 0,9.89 H 30 v -11.21 h 5.3 v 1 h -0.26 l -0.21,-0.63 -0.2,0.63 H 34 l 0.53,0.38 -0.2,0.63 0.53,-0.39 0.47,0.34 v 2.49 h -0.62 l -0.21,-0.62 -0.2,0.62 h -0.66 l 0.53,0.39 -0.2,0.63 0.53,-0.39 0.54,0.39 -0.21,-0.63 0.5,-0.36 v 6.73 z m -3.55,0 -0.2,-0.62 0.53,-0.39 h -0.66 l -0.2,-0.63 -0.21,0.63 h -0.66 l 0.54,0.39 -0.2,0.62 0.53,-0.38 z m 1.75,-3.19 0.53,-0.39 h -0.66 l -0.2,-0.63 -0.2,0.63 h -0.66 l 0.53,0.39 -0.2,0.63 0.53,-0.39 0.53,0.39 z"
class="cls-2"
inkscape:connector-curvature="0" />
</svg>

After

Width:  |  Height:  |  Size: 5.8 KiB

View File

@ -9,5 +9,5 @@ export const environment: AppEnvironment = {
production: _has(ENV, 'production', '$PRODUCTION') ? (ENV.production === 'true') : false,
api: _has(ENV, 'api', '$API_URL') ? ENV.api : 'http://localhost:5000/v1.0',
irbUrl: _has(ENV, 'irbUrl', '$IRB_URL') ? ENV.irbUrl : 'http://localhost:5001',
baseHref: _has(ENV, 'baseHref', '$BASE_HREF') ? ENV.baseHref : '/',
title: _has(ENV, 'title', '$TITLE') ? ENV.title : 'Research Ramp-Up Toolkit Configurator',
};

View File

@ -10,7 +10,6 @@ describe('Environments', () => {
expect(environment.api).toEqual('apiRoot');
expect(environment.irbUrl).toEqual('irbUrl');
expect(environment.homeRoute).toEqual('home');
expect(environment.baseHref).toEqual('/');
});
it('should check if environment variables are defined', () => {
@ -19,37 +18,31 @@ describe('Environments', () => {
production: '$PRODUCTION',
api: '$API_URL',
irbUrl: '$IRB_URL',
baseHref: '$BASE_HREF',
};
expect(_has(env, 'homeRoute', '$HOME_ROUTE')).toBeFalse();
expect(_has(env, 'production', '$PRODUCTION')).toBeFalse();
expect(_has(env, 'api', '$API_URL')).toBeFalse();
expect(_has(env, 'irbUrl', '$IRB_URL')).toBeFalse();
expect(_has(env, 'baseHref', '$BASE_HREF')).toBeFalse();
env.homeRoute = undefined;
env.production = undefined;
env.api = undefined;
env.irbUrl = undefined;
env.baseHref = undefined;
expect(_has(env, 'homeRoute', '$HOME_ROUTE')).toBeFalse();
expect(_has(env, 'production', '$PRODUCTION')).toBeFalse();
expect(_has(env, 'api', '$API_URL')).toBeFalse();
expect(_has(env, 'irbUrl', '$IRB_URL')).toBeFalse();
expect(_has(env, 'baseHref', '$BASE_HREF')).toBeFalse();
env.homeRoute = 'something';
env.production = 'something';
env.api = 'something';
env.irbUrl = 'something';
env.baseHref = 'something';
expect(_has(env, 'homeRoute', '$HOME_ROUTE')).toBeTrue();
expect(_has(env, 'production', '$PRODUCTION')).toBeTrue();
expect(_has(env, 'api', '$API_URL')).toBeTrue();
expect(_has(env, 'irbUrl', '$IRB_URL')).toBeTrue();
expect(_has(env, 'baseHref', '$BASE_HREF')).toBeTrue();
});
});

View File

@ -15,8 +15,8 @@
</script>
<meta content="width=device-width, initial-scale=1" name="viewport">
<link href="favicon.ico" rel="icon" type="image/x-icon">
<link href="https://fonts.googleapis.com/css?family=Roboto:300,400,500&display=swap" rel="stylesheet">
<link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet">
<link rel="stylesheet" href="https://use.typekit.net/kwp6dli.css">
<link href="assets/css/diagram-js.css" rel="stylesheet">
<link href="assets/css/dmn-js-decision-table.css" rel="stylesheet">
<link href="assets/css/dmn-js-decision-table-controls.css" rel="stylesheet">

View File

@ -7,11 +7,6 @@
$primary: map-get($theme, primary);
$accent: map-get($theme, accent);
h1 {
text-transform: uppercase;
color: $brand-accent;
}
html, body {
height: 100%;
margin: 0;
@ -21,7 +16,12 @@
body {
margin: 0;
padding-top: 64px;
padding-top: $header-height;
}
.mat-display-4 {
color: $brand-primary;
border-bottom: 1px solid $brand-gray-light;
}
mat-radio-button, .mat-checkbox {