diff --git a/src/feat-no-facade/src/lib/containers/smart-b-no-facade/smart-b-no-facade.container.html b/src/feat-no-facade/src/lib/containers/smart-b-no-facade/smart-b-no-facade.container.html
new file mode 100644
index 0000000..a27b75d
--- /dev/null
+++ b/src/feat-no-facade/src/lib/containers/smart-b-no-facade/smart-b-no-facade.container.html
@@ -0,0 +1,2 @@
+
+
\ No newline at end of file
diff --git a/src/feat-no-facade/src/lib/containers/smart-b-no-facade/smart-b-no-facade.container.scss b/src/feat-no-facade/src/lib/containers/smart-b-no-facade/smart-b-no-facade.container.scss
new file mode 100644
index 0000000..7a6beb5
--- /dev/null
+++ b/src/feat-no-facade/src/lib/containers/smart-b-no-facade/smart-b-no-facade.container.scss
@@ -0,0 +1,44 @@
+collapsable-sidebar {
+ height: 100%;
+ display: flex;
+}
+.collapsable-part {
+ min-width: 400px;
+ background: $color-purple-dark;
+ height: 100%;
+ display: flex;
+ flex-direction: column;
+ h2 {
+ padding-left: 10px;
+ color: $color-white;
+ }
+ .btn-collapsable {
+ position: fixed;
+ left: 364px;
+ margin-top: 0px;
+ z-index: 9999;
+ border-radius: 0;
+ }
+ &.is-collapsed {
+ width: 35px;
+ min-width: 0px;
+ .btn-collapsable {
+ left: 0px;
+ }
+ }
+ .table.table-striped {
+ tbody > tr:nth-of-type(odd) {
+ background: $color-purple-dark;
+ color: $color-white;
+ td {
+ border: none;
+ }
+ }
+ tbody > tr:nth-of-type(even) {
+ color: $color-white;
+ td {
+ border: none;
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/feat-no-facade/src/lib/containers/smart-b-no-facade/smart-b-no-facade.container.ts b/src/feat-no-facade/src/lib/containers/smart-b-no-facade/smart-b-no-facade.container.ts
new file mode 100644
index 0000000..7780bf5
--- /dev/null
+++ b/src/feat-no-facade/src/lib/containers/smart-b-no-facade/smart-b-no-facade.container.ts
@@ -0,0 +1,16 @@
+import { Component, ViewEncapsulation } from "@angular/core";
+@Component({
+ selector: "smart-b-no-facade",
+ encapsulation: ViewEncapsulation.None,
+ templateUrl: "./smart-b-no-facade.container.html"
+})
+export class SmartBNoFacadeContainer {
+ isCollapsed$ = this.sandbox.isCollapsed$;
+
+
+ public save(): void {
+ this.nameService.save(this.name).then(() => {
+ this.router.navigate([".."]);
+ });
+ }
+}
diff --git a/src/feat-no-facade/src/lib/feat-no-facade.module.ts b/src/feat-no-facade/src/lib/feat-no-facade.module.ts
new file mode 100644
index 0000000..e432324
--- /dev/null
+++ b/src/feat-no-facade/src/lib/feat-no-facade.module.ts
@@ -0,0 +1,18 @@
+import {NgModule} from "@angular/core";
+import {HttpModule} from "@angular/http";
+import {RouterModule} from "@angular/router";
+import {CommonSandbox} from "./common.sandbox";
+import {CommonModule} from "@angular/common";
+import {ReactiveFormsModule, FormsModule} from "@angular/forms";
+import {AuthenticatedGuard} from "./authenticated.guard";
+import {RealTime} from "./realtime";
+import { SmartBNoFacadeContainer } from "./containers/smart-b-no-facade/smart-b-no-facade.container";
+
+@NgModule({
+ imports: [FormsModule, ReactiveFormsModule, CommonModule, RouterModule, HttpModule],
+ declarations: [SmartBNoFacadeContainer],
+ exports: [],
+ providers: [CommonSandbox, AuthenticatedGuard, RealTime]
+})
+export class FeatNoFacadeModule {
+}
\ No newline at end of file
diff --git a/src/feat-test/src/index.ts b/src/feat-test/src/index.ts
new file mode 100644
index 0000000..5618216
--- /dev/null
+++ b/src/feat-test/src/index.ts
@@ -0,0 +1 @@
+export * from './lib/feat-test.module';
diff --git a/src/feat-test/src/lib/components/default-page/default-page.component.scss b/src/feat-test/src/lib/components/default-page/default-page.component.scss
new file mode 100644
index 0000000..482b5d7
--- /dev/null
+++ b/src/feat-test/src/lib/components/default-page/default-page.component.scss
@@ -0,0 +1,8 @@
+default-page {
+ display: flex;
+ flex-direction: row;
+ height: 100%;
+ width: 100%;
+ position: absolute;
+ padding-top: 50px;
+}
\ No newline at end of file
diff --git a/src/feat-test/src/lib/components/default-page/default-page.component.ts b/src/feat-test/src/lib/components/default-page/default-page.component.ts
new file mode 100644
index 0000000..05c671f
--- /dev/null
+++ b/src/feat-test/src/lib/components/default-page/default-page.component.ts
@@ -0,0 +1,8 @@
+import {Component} from "@angular/core";
+
+@Component({
+ selector: "default-page",
+ template: ``
+})
+export class DefaultPageComponent {
+}
\ No newline at end of file
diff --git a/src/feat-test/src/lib/components/form/form-group-content/form-group-content.component.ts b/src/feat-test/src/lib/components/form/form-group-content/form-group-content.component.ts
new file mode 100644
index 0000000..9c60b5d
--- /dev/null
+++ b/src/feat-test/src/lib/components/form/form-group-content/form-group-content.component.ts
@@ -0,0 +1,16 @@
+import {Input, Component, ChangeDetectionStrategy} from "@angular/core";
+@Component({
+ selector: "form-group-content",
+ changeDetection: ChangeDetectionStrategy.OnPush,
+ template: `
+
+ `
+})
+export class FormGroupContent {
+ @Input() label:string;
+}
\ No newline at end of file
diff --git a/src/feat-test/src/lib/components/form/form-group-footer/form-group-footer.component.ts b/src/feat-test/src/lib/components/form/form-group-footer/form-group-footer.component.ts
new file mode 100644
index 0000000..1807b88
--- /dev/null
+++ b/src/feat-test/src/lib/components/form/form-group-footer/form-group-footer.component.ts
@@ -0,0 +1,12 @@
+import {Component} from "@angular/core";
+@Component({
+ selector: "form-group-footer",
+ template: `
+
+ `
+})
+export class FormGroupFooter {}
\ No newline at end of file
diff --git a/src/feat-test/src/lib/components/form/form-group-password/form-group-password.component.ts b/src/feat-test/src/lib/components/form/form-group-password/form-group-password.component.ts
new file mode 100644
index 0000000..fbd6574
--- /dev/null
+++ b/src/feat-test/src/lib/components/form/form-group-password/form-group-password.component.ts
@@ -0,0 +1,24 @@
+import {Component, Input, ChangeDetectionStrategy} from "@angular/core";
+import {FormControl} from "@angular/forms";
+@Component({
+ selector: "form-group-password",
+ changeDetection: ChangeDetectionStrategy.OnPush,
+ template: `
+
+ `
+})
+export class FormGroupPassword {
+ @Input() control: FormControl;
+ @Input() label: string;
+ @Input() placeholder: string;
+}
\ No newline at end of file
diff --git a/src/feat-test/src/lib/components/form/form-group-textarea/form-group-textarea.component.ts b/src/feat-test/src/lib/components/form/form-group-textarea/form-group-textarea.component.ts
new file mode 100644
index 0000000..0a776f8
--- /dev/null
+++ b/src/feat-test/src/lib/components/form/form-group-textarea/form-group-textarea.component.ts
@@ -0,0 +1,24 @@
+import {Input, Component, ChangeDetectionStrategy} from "@angular/core";
+import {FormControl} from "@angular/forms";
+@Component({
+ selector: "form-group-textarea",
+ changeDetection: ChangeDetectionStrategy.OnPush,
+ template: `
+
+ `
+})
+export class FormGroupTextarea {
+ @Input() control: FormControl;
+ @Input() label: string;
+ @Input() placeholder: string;
+}
\ No newline at end of file
diff --git a/src/feat-test/src/lib/components/form/form-group-textbox/form-group-textbox.component.ts b/src/feat-test/src/lib/components/form/form-group-textbox/form-group-textbox.component.ts
new file mode 100644
index 0000000..ec2e89c
--- /dev/null
+++ b/src/feat-test/src/lib/components/form/form-group-textbox/form-group-textbox.component.ts
@@ -0,0 +1,24 @@
+import {Input, Component, ChangeDetectionStrategy} from "@angular/core";
+import {FormControl} from "@angular/forms";
+@Component({
+ selector: "form-group-textbox",
+ changeDetection: ChangeDetectionStrategy.OnPush,
+ template: `
+
+ `
+})
+export class FormGroupTextbox {
+ @Input() control: FormControl;
+ @Input() label: string;
+ @Input() placeholder: string;
+}
\ No newline at end of file
diff --git a/src/feat-test/src/lib/components/main/main.component.scss b/src/feat-test/src/lib/components/main/main.component.scss
new file mode 100644
index 0000000..bdae008
--- /dev/null
+++ b/src/feat-test/src/lib/components/main/main.component.scss
@@ -0,0 +1,15 @@
+main {
+ background: $color-background;
+ display: flex;
+ flex-direction: column;
+ flex-grow: 1;
+ width: 100%;
+ overflow: auto;
+ padding: 15px;
+ table.table-striped > tbody > tr:nth-of-type(odd) {
+ background-color: $color-white;
+ }
+ table.table-striped td {
+ border: none;
+ }
+}
\ No newline at end of file
diff --git a/src/feat-test/src/lib/components/main/main.component.ts b/src/feat-test/src/lib/components/main/main.component.ts
new file mode 100644
index 0000000..8edc810
--- /dev/null
+++ b/src/feat-test/src/lib/components/main/main.component.ts
@@ -0,0 +1,7 @@
+import {Component} from "@angular/core";
+@Component({
+ selector: "main",
+ template: ``
+})
+export class MainComponent {
+}
\ No newline at end of file
diff --git a/src/feat-test/src/lib/components/navbar/navbar.component.scss b/src/feat-test/src/lib/components/navbar/navbar.component.scss
new file mode 100644
index 0000000..f28c081
--- /dev/null
+++ b/src/feat-test/src/lib/components/navbar/navbar.component.scss
@@ -0,0 +1,19 @@
+.navbar.navbar-inverse {
+ background-color: $color-purple;
+ .navbar-nav li a {
+ color: $color-white;
+ &:hover {
+ background: $color-purple-light;
+ }
+ }
+ .navbar-brand {
+ color: $color-white;
+ }
+ .navbar-text {
+ color: $color-white;
+ }
+ .navbar-nav li a.router-link-active {
+ background: $color-purple-dark;
+ color: $color-white;
+ }
+}
\ No newline at end of file
diff --git a/src/feat-test/src/lib/components/navbar/navbar.component.ts b/src/feat-test/src/lib/components/navbar/navbar.component.ts
new file mode 100644
index 0000000..694b9c5
--- /dev/null
+++ b/src/feat-test/src/lib/components/navbar/navbar.component.ts
@@ -0,0 +1,49 @@
+import {Component, Output, EventEmitter, Input, ChangeDetectionStrategy} from "@angular/core";
+import {Account} from "../../../authentication/types/Account";
+@Component({
+ selector: "navbar",
+ changeDetection: ChangeDetectionStrategy.OnPush,
+ template: `
+ `
+})
+export class NavbarComponent {
+ @Input() account: Account;
+ @Output() logout = new EventEmitter();
+
+ logoutClicked(): void {
+ this.logout.emit(null);
+ }
+}
\ No newline at end of file
diff --git a/src/feat-test/src/lib/components/number-picker/number-picker.component.scss b/src/feat-test/src/lib/components/number-picker/number-picker.component.scss
new file mode 100644
index 0000000..3f91444
--- /dev/null
+++ b/src/feat-test/src/lib/components/number-picker/number-picker.component.scss
@@ -0,0 +1,17 @@
+number-picker {
+ min-width: 78px;
+ display: flex;
+ flex-direction: row;
+ .btn-primary {
+ background-color: $color-purple-light;
+ border: none;
+ &:hover {
+ background-color: $color-purple;
+ }
+ }
+ .amount {
+ width: 30px;
+ display: block;
+ text-align: center;
+ }
+}
\ No newline at end of file
diff --git a/src/feat-test/src/lib/components/number-picker/number-picker.component.ts b/src/feat-test/src/lib/components/number-picker/number-picker.component.ts
new file mode 100644
index 0000000..34af180
--- /dev/null
+++ b/src/feat-test/src/lib/components/number-picker/number-picker.component.ts
@@ -0,0 +1,26 @@
+import {Component, Input, Output, EventEmitter, ChangeDetectionStrategy} from "@angular/core";
+@Component({
+ selector: "number-picker",
+ changeDetection: ChangeDetectionStrategy.OnPush,
+ template: `
+
+ {{amount}}
+
+ `
+})
+export class NumberPickerComponent {
+ @Input() amount: number;
+ @Output() setAmount = new EventEmitter();
+
+ up(): void {
+ this.setAmount.emit(this.amount + 1);
+ }
+
+ down(): void {
+ this.setAmount.emit(this.amount - 1);
+ }
+}
\ No newline at end of file
diff --git a/src/feat-test/src/lib/components/panel/panel.component.scss b/src/feat-test/src/lib/components/panel/panel.component.scss
new file mode 100644
index 0000000..60f9026
--- /dev/null
+++ b/src/feat-test/src/lib/components/panel/panel.component.scss
@@ -0,0 +1,9 @@
+panel .panel-primary {
+ border: none;
+ .panel-heading {
+ background-color: $color-purple;
+ border-color: $color-purple-dark;
+ }
+ max-width: 500px;
+ margin: 0 auto;
+}
\ No newline at end of file
diff --git a/src/feat-test/src/lib/components/panel/panel.component.ts b/src/feat-test/src/lib/components/panel/panel.component.ts
new file mode 100644
index 0000000..74daf43
--- /dev/null
+++ b/src/feat-test/src/lib/components/panel/panel.component.ts
@@ -0,0 +1,18 @@
+import {Component, Input, ChangeDetectionStrategy} from "@angular/core";
+@Component({
+ selector: "panel",
+ changeDetection: ChangeDetectionStrategy.OnPush,
+ template: `
+
+ `
+})
+export class PanelComponent {
+ @Input() header: string;
+}
\ No newline at end of file
diff --git a/src/feat-test/src/lib/components/rating/rating.component.scss b/src/feat-test/src/lib/components/rating/rating.component.scss
new file mode 100644
index 0000000..56b4811
--- /dev/null
+++ b/src/feat-test/src/lib/components/rating/rating.component.scss
@@ -0,0 +1,3 @@
+rating i.over, rating i.starred {
+ color: $color-purple;
+}
\ No newline at end of file
diff --git a/src/feat-test/src/lib/components/rating/rating.component.ts b/src/feat-test/src/lib/components/rating/rating.component.ts
new file mode 100644
index 0000000..8820c20
--- /dev/null
+++ b/src/feat-test/src/lib/components/rating/rating.component.ts
@@ -0,0 +1,32 @@
+import {Component, EventEmitter, Output, Input, ChangeDetectionStrategy} from "@angular/core";
+@Component({
+ selector: "rating",
+ changeDetection: ChangeDetectionStrategy.OnPush,
+ template: `
+ = i"
+ [class.starred]="rating >= i"
+ (mouseover)="over(i)"
+ (mouseout)="out()"
+ (click)="update(i)">
+ `
+})
+export class Rating {
+ @Input() rating: number;
+ @Input() big: boolean;
+ @Output() setRate = new EventEmitter();
+
+ overValue: number;
+
+ update(value: number): void {
+ this.setRate.emit(value);
+ }
+
+ over(value: number): void {
+ this.overValue = value;
+ }
+
+ out(): void {
+ this.overValue = 0;
+ }
+}
\ No newline at end of file
diff --git a/src/feat-test/src/lib/components/spinner/spinner.component.scss b/src/feat-test/src/lib/components/spinner/spinner.component.scss
new file mode 100644
index 0000000..34ee357
--- /dev/null
+++ b/src/feat-test/src/lib/components/spinner/spinner.component.scss
@@ -0,0 +1,57 @@
+.spinner {
+ width: 70px;
+ height: 60px;
+ position: fixed;
+ top: 15px;
+ left: 0;
+ right: 0;
+ margin: auto;
+ z-index: 999999;
+ -webkit-user-select: none;
+ opacity: 0;
+}
+
+.spinner.active {
+ opacity: 1;
+}
+
+.spinner > div {
+ width: 18px;
+ height: 18px;
+ background-color: $color-purple-dark;
+
+ border-radius: 100%;
+ display: inline-block;
+ -webkit-animation: sk-bouncedelay 1.4s infinite ease-in-out both;
+ animation: sk-bouncedelay 1.4s infinite ease-in-out both;
+}
+
+.spinner .bounce1 {
+ -webkit-animation-delay: -0.32s;
+ animation-delay: -0.32s;
+}
+
+.spinner .bounce2 {
+ -webkit-animation-delay: -0.16s;
+ animation-delay: -0.16s;
+}
+
+@-webkit-keyframes sk-bouncedelay {
+ 0%, 80%, 100% {
+ -webkit-transform: scale(0)
+ }
+ 40% {
+ -webkit-transform: scale(1.0)
+ }
+}
+
+@keyframes sk-bouncedelay {
+ 0%, 80%, 100% {
+ -webkit-transform: scale(0);
+ transform: scale(0);
+ }
+ 40% {
+ -webkit-transform: scale(1.0);
+ transform: scale(1.0);
+ }
+}
\ No newline at end of file
diff --git a/src/feat-test/src/lib/components/spinner/spinner.component.ts b/src/feat-test/src/lib/components/spinner/spinner.component.ts
new file mode 100644
index 0000000..00c66a5
--- /dev/null
+++ b/src/feat-test/src/lib/components/spinner/spinner.component.ts
@@ -0,0 +1,14 @@
+import {Component, Input, ChangeDetectionStrategy} from "@angular/core";
+@Component({
+ selector: "spinner",
+ changeDetection: ChangeDetectionStrategy.OnPush,
+ template: `
+ `
+})
+export class SpinnerComponent {
+ @Input() spin: boolean;
+}
\ No newline at end of file
diff --git a/src/feat-test/src/lib/containers/smart-a/smart-a.container.html b/src/feat-test/src/lib/containers/smart-a/smart-a.container.html
new file mode 100644
index 0000000..4568a9f
--- /dev/null
+++ b/src/feat-test/src/lib/containers/smart-a/smart-a.container.html
@@ -0,0 +1,3 @@
+
+
+
\ No newline at end of file
diff --git a/src/feat-test/src/lib/containers/smart-a/smart-a.container.scss b/src/feat-test/src/lib/containers/smart-a/smart-a.container.scss
new file mode 100644
index 0000000..7a6beb5
--- /dev/null
+++ b/src/feat-test/src/lib/containers/smart-a/smart-a.container.scss
@@ -0,0 +1,44 @@
+collapsable-sidebar {
+ height: 100%;
+ display: flex;
+}
+.collapsable-part {
+ min-width: 400px;
+ background: $color-purple-dark;
+ height: 100%;
+ display: flex;
+ flex-direction: column;
+ h2 {
+ padding-left: 10px;
+ color: $color-white;
+ }
+ .btn-collapsable {
+ position: fixed;
+ left: 364px;
+ margin-top: 0px;
+ z-index: 9999;
+ border-radius: 0;
+ }
+ &.is-collapsed {
+ width: 35px;
+ min-width: 0px;
+ .btn-collapsable {
+ left: 0px;
+ }
+ }
+ .table.table-striped {
+ tbody > tr:nth-of-type(odd) {
+ background: $color-purple-dark;
+ color: $color-white;
+ td {
+ border: none;
+ }
+ }
+ tbody > tr:nth-of-type(even) {
+ color: $color-white;
+ td {
+ border: none;
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/feat-test/src/lib/containers/smart-a/smart-a.container.ts b/src/feat-test/src/lib/containers/smart-a/smart-a.container.ts
new file mode 100644
index 0000000..cfe1250
--- /dev/null
+++ b/src/feat-test/src/lib/containers/smart-a/smart-a.container.ts
@@ -0,0 +1,19 @@
+import { Component, ViewEncapsulation } from "@angular/core";
+import {GoodSandboxFacade} from '../../services/facade.service';
+import { SomeUtilService } from "../../services/some-util.service.";
+@Component({
+ selector: "smart-a",
+ encapsulation: ViewEncapsulation.None,
+ templateUrl: "./smart-a.container.html"
+})
+export class SmartAContainer {
+ isCollapsed$ = this.someUtilService.isCollapsed$;
+
+ constructor(private readonly someUtilService: SomeUtilService, private readonly facade: GoodSandboxFacade) {}
+
+ // public save(): void {
+ // this.nameService.save(this.name).then(() => {
+ // this.router.navigate([".."]);
+ // });
+ // }
+}
diff --git a/src/feat-test/src/lib/containers/smart-b-no-facade/smart-b-no-facade.container.html b/src/feat-test/src/lib/containers/smart-b-no-facade/smart-b-no-facade.container.html
new file mode 100644
index 0000000..4568a9f
--- /dev/null
+++ b/src/feat-test/src/lib/containers/smart-b-no-facade/smart-b-no-facade.container.html
@@ -0,0 +1,3 @@
+
+
+
\ No newline at end of file
diff --git a/src/feat-test/src/lib/containers/smart-b-no-facade/smart-b-no-facade.container.scss b/src/feat-test/src/lib/containers/smart-b-no-facade/smart-b-no-facade.container.scss
new file mode 100644
index 0000000..7a6beb5
--- /dev/null
+++ b/src/feat-test/src/lib/containers/smart-b-no-facade/smart-b-no-facade.container.scss
@@ -0,0 +1,44 @@
+collapsable-sidebar {
+ height: 100%;
+ display: flex;
+}
+.collapsable-part {
+ min-width: 400px;
+ background: $color-purple-dark;
+ height: 100%;
+ display: flex;
+ flex-direction: column;
+ h2 {
+ padding-left: 10px;
+ color: $color-white;
+ }
+ .btn-collapsable {
+ position: fixed;
+ left: 364px;
+ margin-top: 0px;
+ z-index: 9999;
+ border-radius: 0;
+ }
+ &.is-collapsed {
+ width: 35px;
+ min-width: 0px;
+ .btn-collapsable {
+ left: 0px;
+ }
+ }
+ .table.table-striped {
+ tbody > tr:nth-of-type(odd) {
+ background: $color-purple-dark;
+ color: $color-white;
+ td {
+ border: none;
+ }
+ }
+ tbody > tr:nth-of-type(even) {
+ color: $color-white;
+ td {
+ border: none;
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/feat-test/src/lib/containers/smart-b-no-facade/smart-b-no-facade.container.ts b/src/feat-test/src/lib/containers/smart-b-no-facade/smart-b-no-facade.container.ts
new file mode 100644
index 0000000..7780bf5
--- /dev/null
+++ b/src/feat-test/src/lib/containers/smart-b-no-facade/smart-b-no-facade.container.ts
@@ -0,0 +1,16 @@
+import { Component, ViewEncapsulation } from "@angular/core";
+@Component({
+ selector: "smart-b-no-facade",
+ encapsulation: ViewEncapsulation.None,
+ templateUrl: "./smart-b-no-facade.container.html"
+})
+export class SmartBNoFacadeContainer {
+ isCollapsed$ = this.sandbox.isCollapsed$;
+
+
+ public save(): void {
+ this.nameService.save(this.name).then(() => {
+ this.router.navigate([".."]);
+ });
+ }
+}
diff --git a/src/feat-test/src/lib/feat-test.module.ts b/src/feat-test/src/lib/feat-test.module.ts
new file mode 100644
index 0000000..3b54393
--- /dev/null
+++ b/src/feat-test/src/lib/feat-test.module.ts
@@ -0,0 +1,34 @@
+import {NgModule} from "@angular/core";
+import {HttpModule} from "@angular/http";
+import {RouterModule} from "@angular/router";
+import {DefaultPageComponent} from "./components/default-page/default-page.component";
+import {FormGroupContent} from "./components/form/form-group-content/form-group-content.component";
+import {FormGroupFooter} from "./components/form/form-group-footer/form-group-footer.component";
+import {FormGroupPassword} from "./components/form/form-group-password/form-group-password.component";
+import {FormGroupTextarea} from "./components/form/form-group-textarea/form-group-textarea.component";
+import {FormGroupTextbox} from "./components/form/form-group-textbox/form-group-textbox.component";
+import {MainComponent} from "./components/main/main.component";
+import {NavbarComponent} from "./components/navbar/navbar.component";
+import {NumberPickerComponent} from "./components/number-picker/number-picker.component";
+import {PanelComponent} from "./components/panel/panel.component";
+import {Rating} from "./components/rating/rating.component";
+import {SpinnerComponent} from "./components/spinner/spinner.component";
+import {CollapsableSidebarContainer} from "./containers/collapsable-sidebar/collapsable-sidebar.container";
+import {CommonSandbox} from "./common.sandbox";
+import {CommonModule} from "@angular/common";
+import {ReactiveFormsModule, FormsModule} from "@angular/forms";
+import {AuthenticatedGuard} from "./authenticated.guard";
+import {RealTime} from "./realtime";
+import { SmartAContainer } from "./containers/smart-a/smart-a.container";
+import { SmartBNoFacadeContainer } from "./containers/smart-b-no-facade/smart-b-no-facade.container";
+
+@NgModule({
+ imports: [FormsModule, ReactiveFormsModule, CommonModule, RouterModule, HttpModule],
+ declarations: [SmartAContainer, SmartBNoFacadeContainer, DefaultPageComponent, FormGroupContent, FormGroupFooter, FormGroupPassword, FormGroupTextarea, FormGroupTextbox,
+ MainComponent, NavbarComponent, NumberPickerComponent, PanelComponent, Rating, SpinnerComponent, CollapsableSidebarContainer],
+ exports: [DefaultPageComponent, FormGroupContent, FormGroupFooter, FormGroupPassword, FormGroupTextarea, FormGroupTextbox,
+ MainComponent, NavbarComponent, NumberPickerComponent, PanelComponent, Rating, SpinnerComponent, CollapsableSidebarContainer],
+ providers: [CommonSandbox, AuthenticatedGuard, RealTime]
+})
+export class FeatTestModule {
+}
\ No newline at end of file
diff --git a/src/feat-test/src/lib/services/facade.service.ts b/src/feat-test/src/lib/services/facade.service.ts
new file mode 100644
index 0000000..ca75a44
--- /dev/null
+++ b/src/feat-test/src/lib/services/facade.service.ts
@@ -0,0 +1,19 @@
+import { Injectable } from '@angular/core';
+@Injectable()
+export class GoodSandboxFacade {
+// // GOOD: Pass through observables direcly
+// public readonly users$ = this.authService.user$;
+// // GOOD: Pass through observables through initial function
+// public readonly countries$ = this.masterDataState.getCountries();
+// // GOOD: Query parts of state management framework
+// public readonly chatboxOpen$ this.store.select(selectChatbox());
+// // GOOD: Pass through public functions from certain services
+// public addUser(user: User): Observable{
+// return this.userService.add(user);
+// }
+// // GOOD: Sandbox facade abstracts the
+// // state management framework away
+// public storeUser(user: User): void{
+// this.store.dispatch(new addUserAction(user))
+// }
+}
diff --git a/src/feat-test/src/lib/services/some-util.service.ts b/src/feat-test/src/lib/services/some-util.service.ts
new file mode 100644
index 0000000..c853d35
--- /dev/null
+++ b/src/feat-test/src/lib/services/some-util.service.ts
@@ -0,0 +1,16 @@
+import {Injectable} from "@angular/core";
+import {ApplicationState} from "../statemanagement/state/ApplicationState";
+import {Store} from "@ngrx/store";
+import {ToggleSidebar} from "../statemanagement/actions/containers/sidebar";
+
+@Injectable()
+export class SomeUtilService {
+ isCollapsed$ = this.store.select(state => state.containers.collapsableSidebar.isCollapsed);
+
+ constructor(private store: Store) {
+ }
+
+ toggleSidebar(): void {
+ this.store.dispatch(new ToggleSidebar());
+ }
+}
\ No newline at end of file
diff --git a/src/feat-two-facades/src/lib/containers/smart-a/smart-a.container.html b/src/feat-two-facades/src/lib/containers/smart-a/smart-a.container.html
new file mode 100644
index 0000000..a27b75d
--- /dev/null
+++ b/src/feat-two-facades/src/lib/containers/smart-a/smart-a.container.html
@@ -0,0 +1,2 @@
+
+
\ No newline at end of file
diff --git a/src/feat-two-facades/src/lib/containers/smart-a/smart-a.container.scss b/src/feat-two-facades/src/lib/containers/smart-a/smart-a.container.scss
new file mode 100644
index 0000000..7a6beb5
--- /dev/null
+++ b/src/feat-two-facades/src/lib/containers/smart-a/smart-a.container.scss
@@ -0,0 +1,44 @@
+collapsable-sidebar {
+ height: 100%;
+ display: flex;
+}
+.collapsable-part {
+ min-width: 400px;
+ background: $color-purple-dark;
+ height: 100%;
+ display: flex;
+ flex-direction: column;
+ h2 {
+ padding-left: 10px;
+ color: $color-white;
+ }
+ .btn-collapsable {
+ position: fixed;
+ left: 364px;
+ margin-top: 0px;
+ z-index: 9999;
+ border-radius: 0;
+ }
+ &.is-collapsed {
+ width: 35px;
+ min-width: 0px;
+ .btn-collapsable {
+ left: 0px;
+ }
+ }
+ .table.table-striped {
+ tbody > tr:nth-of-type(odd) {
+ background: $color-purple-dark;
+ color: $color-white;
+ td {
+ border: none;
+ }
+ }
+ tbody > tr:nth-of-type(even) {
+ color: $color-white;
+ td {
+ border: none;
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/feat-two-facades/src/lib/containers/smart-a/smart-a.container.ts b/src/feat-two-facades/src/lib/containers/smart-a/smart-a.container.ts
new file mode 100644
index 0000000..4642ada
--- /dev/null
+++ b/src/feat-two-facades/src/lib/containers/smart-a/smart-a.container.ts
@@ -0,0 +1,19 @@
+import { Component, ViewEncapsulation } from "@angular/core";
+import {GoodSandboxFacade} from '../../services/facade.service';
+import { SomeUtilService } from "../../services/some-util.service";
+@Component({
+ selector: "smart-a",
+ encapsulation: ViewEncapsulation.None,
+ templateUrl: "./smart-a.container.html"
+})
+export class SmartAContainer {
+ isCollapsed$ = this.someUtilService.isCollapsed$;
+
+ constructor(private readonly someUtilService: SomeUtilService, private readonly facade: GoodSandboxFacade) {}
+
+ // public save(): void {
+ // this.nameService.save(this.name).then(() => {
+ // this.router.navigate([".."]);
+ // });
+ // }
+}
diff --git a/src/feat-two-facades/src/lib/containers/smart-c-bad-facade/smart-c-bad-facade.container.html b/src/feat-two-facades/src/lib/containers/smart-c-bad-facade/smart-c-bad-facade.container.html
new file mode 100644
index 0000000..a27b75d
--- /dev/null
+++ b/src/feat-two-facades/src/lib/containers/smart-c-bad-facade/smart-c-bad-facade.container.html
@@ -0,0 +1,2 @@
+
+
\ No newline at end of file
diff --git a/src/feat-two-facades/src/lib/containers/smart-c-bad-facade/smart-c-bad-facade.container.scss b/src/feat-two-facades/src/lib/containers/smart-c-bad-facade/smart-c-bad-facade.container.scss
new file mode 100644
index 0000000..7a6beb5
--- /dev/null
+++ b/src/feat-two-facades/src/lib/containers/smart-c-bad-facade/smart-c-bad-facade.container.scss
@@ -0,0 +1,44 @@
+collapsable-sidebar {
+ height: 100%;
+ display: flex;
+}
+.collapsable-part {
+ min-width: 400px;
+ background: $color-purple-dark;
+ height: 100%;
+ display: flex;
+ flex-direction: column;
+ h2 {
+ padding-left: 10px;
+ color: $color-white;
+ }
+ .btn-collapsable {
+ position: fixed;
+ left: 364px;
+ margin-top: 0px;
+ z-index: 9999;
+ border-radius: 0;
+ }
+ &.is-collapsed {
+ width: 35px;
+ min-width: 0px;
+ .btn-collapsable {
+ left: 0px;
+ }
+ }
+ .table.table-striped {
+ tbody > tr:nth-of-type(odd) {
+ background: $color-purple-dark;
+ color: $color-white;
+ td {
+ border: none;
+ }
+ }
+ tbody > tr:nth-of-type(even) {
+ color: $color-white;
+ td {
+ border: none;
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/feat-two-facades/src/lib/containers/smart-c-bad-facade/smart-c-bad-facade.container.ts b/src/feat-two-facades/src/lib/containers/smart-c-bad-facade/smart-c-bad-facade.container.ts
new file mode 100644
index 0000000..3ffd55f
--- /dev/null
+++ b/src/feat-two-facades/src/lib/containers/smart-c-bad-facade/smart-c-bad-facade.container.ts
@@ -0,0 +1,18 @@
+import { Component, ViewEncapsulation } from "@angular/core";
+import {BadSandboxFacade} from '../../services/bad-facade.service';
+
+@Component({
+ selector: "smart-c-bad-facade",
+ encapsulation: ViewEncapsulation.None,
+ templateUrl: "./smart-c-bad-facade.container.html"
+})
+export class SmartCBadFacadeContainer {
+
+
+ constructor(private readonly facade: BadSandboxFacade) {}
+ // public save(): void {
+ // this.nameService.save(this.name).then(() => {
+ // this.router.navigate([".."]);
+ // });
+ // }
+}
diff --git a/src/feat-two-facades/src/lib/feat-two-facades.module.ts b/src/feat-two-facades/src/lib/feat-two-facades.module.ts
new file mode 100644
index 0000000..1671629
--- /dev/null
+++ b/src/feat-two-facades/src/lib/feat-two-facades.module.ts
@@ -0,0 +1,34 @@
+import {NgModule} from "@angular/core";
+import {HttpModule} from "@angular/http";
+import {RouterModule} from "@angular/router";
+import {DefaultPageComponent} from "./components/default-page/default-page.component";
+import {FormGroupContent} from "./components/form/form-group-content/form-group-content.component";
+import {FormGroupFooter} from "./components/form/form-group-footer/form-group-footer.component";
+import {FormGroupPassword} from "./components/form/form-group-password/form-group-password.component";
+import {FormGroupTextarea} from "./components/form/form-group-textarea/form-group-textarea.component";
+import {FormGroupTextbox} from "./components/form/form-group-textbox/form-group-textbox.component";
+import {MainComponent} from "./components/main/main.component";
+import {NavbarComponent} from "./components/navbar/navbar.component";
+import {NumberPickerComponent} from "./components/number-picker/number-picker.component";
+import {PanelComponent} from "./components/panel/panel.component";
+import {Rating} from "./components/rating/rating.component";
+import {SpinnerComponent} from "./components/spinner/spinner.component";
+import {CollapsableSidebarContainer} from "./containers/collapsable-sidebar/collapsable-sidebar.container";
+import {CommonSandbox} from "./common.sandbox";
+import {CommonModule} from "@angular/common";
+import {ReactiveFormsModule, FormsModule} from "@angular/forms";
+import {AuthenticatedGuard} from "./authenticated.guard";
+import {RealTime} from "./realtime";
+import { SmartAContainer } from "./containers/smart-a/smart-a.container";
+import { SmartCBadFacadeContainer } from "./containers/smart-c-bad-facade/smart-c-bad-facade.container";
+
+@NgModule({
+ imports: [FormsModule, ReactiveFormsModule, CommonModule, RouterModule, HttpModule],
+ declarations: [SmartAContainer, SmartCBadFacadeContainer, DefaultPageComponent, FormGroupContent, FormGroupFooter, FormGroupPassword, FormGroupTextarea, FormGroupTextbox,
+ MainComponent, NavbarComponent, NumberPickerComponent, PanelComponent, Rating, SpinnerComponent, CollapsableSidebarContainer],
+ exports: [DefaultPageComponent, FormGroupContent, FormGroupFooter, FormGroupPassword, FormGroupTextarea, FormGroupTextbox,
+ MainComponent, NavbarComponent, NumberPickerComponent, PanelComponent, Rating, SpinnerComponent, CollapsableSidebarContainer],
+ providers: [CommonSandbox, AuthenticatedGuard, RealTime]
+})
+export class FeatTwoFacadesModule {
+}
\ No newline at end of file
diff --git a/src/feat-two-facades/src/lib/services/bad-facade.service.ts b/src/feat-two-facades/src/lib/services/bad-facade.service.ts
new file mode 100644
index 0000000..6ad41d3
--- /dev/null
+++ b/src/feat-two-facades/src/lib/services/bad-facade.service.ts
@@ -0,0 +1,35 @@
+import { Injectable } from '@angular/core';
+@Injectable()
+export class BadSandboxFacade {
+// // BAD: Sandbox facade can not hold state, only pass it through
+// public readonly user$ = new BehaviorSubject(null);
+// // BAD: Sandbox facade can not contain logic, not even map functionality
+// public readonly countries$ = this.masterDataState.getCountries().pipe(
+// map(resp => resp.elements)
+// );
+// // BAD: Custom selectors here is also logic
+// public readonly chatboxOpen$ this.store.select(() => createSelector(...)));
+// // BAD: constructing objects is also logic, only pass things through
+// public addUser(firstName: string, lastName: string): Observable{
+// return this.userService.add({firstName, lastName});
+// }
+// // BAD: Sandbox facade can not contain logic, also no navigation logic
+// public addCourse(course: Course): Observable {
+// return this.courseService.add(course).pipe(
+// tap(() => this.router.navigate('../'))
+// )
+// }
+// // BAD: Sandbox facade can not contain logic, also no state management logic
+// public addBook(book: Book): void {
+// this.bookService.add(book).subscribe(book => this.store.dispath(...))
+// }
+// // BAD: Sandbox facade can not contain specific orchestration logic
+// // this would be redundant and the urge of reusing would be too big
+// public addLearningSuite(learningSuite: LearningSuite)
+// : Observable<{book: Book, course: Course}> {
+// return combineLatest({
+// book: this.bookService.add(learningSuite.book),
+// course: this.courseService.add(learningSuite.course)
+// })
+// }
+}
diff --git a/src/feat-two-facades/src/lib/services/facade.service.ts b/src/feat-two-facades/src/lib/services/facade.service.ts
new file mode 100644
index 0000000..8e64a30
--- /dev/null
+++ b/src/feat-two-facades/src/lib/services/facade.service.ts
@@ -0,0 +1,19 @@
+import { Injectable } from '@angular/core';
+@Injectable()
+export class GoodSandboxFacade {
+ // // GOOD: Pass through observables direcly
+ // public readonly users$ = this.authService.user$;
+ // // GOOD: Pass through observables through initial function
+ // public readonly countries$ = this.masterDataState.getCountries();
+ // // GOOD: Query parts of state management framework
+ // public readonly chatboxOpen$ this.store.select(selectChatbox());
+ // // GOOD: Pass through public functions from certain services
+ // public addUser(user: User): Observable{
+ // return this.userService.add(user);
+ // }
+ // // GOOD: Sandbox facade abstracts the
+ // // state management framework away
+ // public storeUser(user: User): void{
+ // this.store.dispatch(new addUserAction(user))
+ // }
+}
diff --git a/src/feat-two-facades/src/lib/services/some-util.service.ts b/src/feat-two-facades/src/lib/services/some-util.service.ts
new file mode 100644
index 0000000..c853d35
--- /dev/null
+++ b/src/feat-two-facades/src/lib/services/some-util.service.ts
@@ -0,0 +1,16 @@
+import {Injectable} from "@angular/core";
+import {ApplicationState} from "../statemanagement/state/ApplicationState";
+import {Store} from "@ngrx/store";
+import {ToggleSidebar} from "../statemanagement/actions/containers/sidebar";
+
+@Injectable()
+export class SomeUtilService {
+ isCollapsed$ = this.store.select(state => state.containers.collapsableSidebar.isCollapsed);
+
+ constructor(private store: Store) {
+ }
+
+ toggleSidebar(): void {
+ this.store.dispatch(new ToggleSidebar());
+ }
+}
\ No newline at end of file