Skip to content

Commit

Permalink
initial commit
Browse files Browse the repository at this point in the history
  • Loading branch information
joeconwaystk committed Dec 1, 2017
1 parent 8cf28b4 commit ff08aa6
Show file tree
Hide file tree
Showing 42 changed files with 1,652 additions and 0 deletions.
12 changes: 12 additions & 0 deletions .gitignore
@@ -0,0 +1,12 @@
# Files and directories created by pub
.packages
.pub/
build/
# Remove the following pattern if you wish to check in your lock file
pubspec.lock

# Directory created by dartdoc
doc/api/

*.iml
.idea/
5 changes: 5 additions & 0 deletions Dockerfile
@@ -0,0 +1,5 @@
FROM nginx

COPY ./build/web /usr/share/nginx/html

EXPOSE 80
26 changes: 26 additions & 0 deletions README.md
@@ -0,0 +1,26 @@
## Tour of Heroes: HTTP

Welcome to the example app used in the
[Tour of Heroes: HTTP](https://webdev.dartlang.org/angular/tutorial/toh-pt6) page
of [Dart for the web](https://webdev.dartlang.org).

You can run a [hosted copy](https://webdev.dartlang.org/examples/toh-6) of this
sample. Or run your own copy:

1. Create a local copy of this repo (use the "Clone or download" button above).
2. Get the dependencies: `pub get`
3. Launch a development server: `pub serve`
4. In a browser, open [http://localhost:8080](http://localhost:8080)

In Dartium, you'll see the app right away. In other modern browsers,
you'll have to wait a bit while pub converts the app.

---

*Note:* The content of this repository is generated from the
[Angular docs repository][docs repo] by running the
[dart-doc-syncer](//github.com/dart-lang/dart-doc-syncer) tool.
If you find a problem with this sample's code, please open an [issue][].

[docs repo]: //github.com/dart-lang/site-webdev/tree/master/examples/ng/doc/toh-6
[issue]: //github.com/dart-lang/site-webdev/issues/new?title=examples/ng/doc/toh-6
15 changes: 15 additions & 0 deletions analysis_options.yaml
@@ -0,0 +1,15 @@
analyzer:
strong-mode: true
# exclude:
# - path/to/excluded/files/**

# Lint rules and documentation, see http://dart-lang.github.io/linter/lints
linter:
rules:
- cancel_subscriptions
- hash_and_equals
- iterable_contains_unrelated_type
- list_remove_unrelated_type
- test_types_in_equals
- unrelated_type_equality_checks
- valid_regexps
47 changes: 47 additions & 0 deletions k8s/deployment.yaml
@@ -0,0 +1,47 @@
apiVersion: v1
kind: Service
metadata:
name: web-service
namespace: aqueduct-tutorial
spec:
selector:
app: aqueduct-tutorial
ports:
- port: 80
targetPort: 80
---
apiVersion: apps/v1beta1
kind: Deployment
metadata:
name: web-deployment
namespace: aqueduct-tutorial
spec:
replicas: 1
template:
metadata:
labels:
app: aqueduct-tutorial
spec:
containers:
- name: aqueduct-tutorial
imagePullPolicy: Always
image: $IMAGE_NAME
ports:
- containerPort: 80
---
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: tutorial-ingress
namespace: aqueduct-tutorial
annotations:
kubernetes.io/ingress.class: "nginx"
spec:
rules:
- host: aqueduct-tutorial.stablekernel.io
http:
paths:
- path: /
backend:
serviceName: web-service
servicePort: 80
28 changes: 28 additions & 0 deletions lib/app_component.css
@@ -0,0 +1,28 @@
h1 {
font-size: 1.2em;
color: #999;
margin-bottom: 0;
}
h2 {
font-size: 2em;
margin-top: 0;
padding-top: 0;
}
nav a {
padding: 5px 10px;
text-decoration: none;
margin-top: 10px;
display: inline-block;
background-color: #eee;
border-radius: 4px;
}
nav a:visited, a:link {
color: #607D8B;
}
nav a:hover {
color: #039be5;
background-color: #CFD8DC;
}
nav a.router-link-active {
color: #039be5;
}
34 changes: 34 additions & 0 deletions lib/app_component.dart
@@ -0,0 +1,34 @@
import 'package:angular/angular.dart';
import 'package:angular_router/angular_router.dart';

import 'package:angular_tour_of_heroes/src/heroes_component.dart';
import 'package:angular_tour_of_heroes/src/hero_service.dart';
import 'package:angular_tour_of_heroes/src/dashboard_component.dart';
import 'package:angular_tour_of_heroes/src/hero_detail_component.dart';

@Component(
selector: 'my-app',
template: '''
<h1>{{title}}</h1>
<nav>
<a [routerLink]="['Dashboard']">Dashboard</a>
<a [routerLink]="['Heroes']">Heroes</a>
</nav>
<router-outlet></router-outlet>''',
styleUrls: const ['app_component.css'],
directives: const [ROUTER_DIRECTIVES],
providers: const [HeroService],
)
@RouteConfig(const [
const Route(
path: '/dashboard',
name: 'Dashboard',
component: DashboardComponent,
useAsDefault: true),
const Route(
path: '/detail/:id', name: 'HeroDetail', component: HeroDetailComponent),
const Route(path: '/heroes', name: 'Heroes', component: HeroesComponent)
])
class AppComponent {
final title = 'Tour of Heroes';
}
79 changes: 79 additions & 0 deletions lib/in_memory_data_service.dart
@@ -0,0 +1,79 @@
// Note: MockClient constructor API forces all InMemoryDataService members to
// be static.
import 'dart:async';
import 'dart:convert';
import 'dart:math';

import 'package:angular/angular.dart';
import 'package:http/http.dart';
import 'package:http/testing.dart';

import 'src/hero.dart';

@Injectable()
class InMemoryDataService extends MockClient {
static final _initialHeroes = [
{'id': 11, 'name': 'Mr. Nice'},
{'id': 12, 'name': 'Narco'},
{'id': 13, 'name': 'Bombasto'},
{'id': 14, 'name': 'Celeritas'},
{'id': 15, 'name': 'Magneta'},
{'id': 16, 'name': 'RubberMan'},
{'id': 17, 'name': 'Dynama'},
{'id': 18, 'name': 'Dr IQ'},
{'id': 19, 'name': 'Magma'},
{'id': 20, 'name': 'Tornado'}
];
static List<Hero> _heroesDb;
static int _nextId;

static Future<Response> _handler(Request request) async {
if (_heroesDb == null) resetDb();
var data;
switch (request.method) {
case 'GET':
final id =
int.parse(request.url.pathSegments.last, onError: (_) => null);
if (id != null) {
data = _heroesDb
.firstWhere((hero) => hero.id == id); // throws if no match
} else {
String prefix = request.url.queryParameters['name'] ?? '';
final regExp = new RegExp(prefix, caseSensitive: false);
data = _heroesDb.where((hero) => hero.name.contains(regExp)).toList();
}
break;
case 'POST':
var name = JSON.decode(request.body)['name'];
var newHero = new Hero(_nextId++, name);
_heroesDb.add(newHero);
data = newHero;
break;
case 'PUT':
var heroChanges = new Hero.fromJson(JSON.decode(request.body));
var targetHero = _heroesDb.firstWhere((h) => h.id == heroChanges.id);
targetHero.name = heroChanges.name;
data = targetHero;
break;
case 'DELETE':
var id = int.parse(request.url.pathSegments.last);
_heroesDb.removeWhere((hero) => hero.id == id);
// No data, so leave it as null.
break;
default:
throw 'Unimplemented HTTP method ${request.method}';
}
return new Response(JSON.encode({'data': data}), 200,
headers: {'content-type': 'application/json'});
}

static resetDb() {
_heroesDb = _initialHeroes.map((json) => new Hero.fromJson(json)).toList();
_nextId = _heroesDb.map((hero) => hero.id).fold(0, max) + 1;
}

static String lookUpName(int id) =>
_heroesDb.firstWhere((hero) => hero.id == id, orElse: null)?.name;

InMemoryDataService() : super(_handler);
}
61 changes: 61 additions & 0 deletions lib/src/dashboard_component.css
@@ -0,0 +1,61 @@
[class*='col-'] {
float: left;
padding-right: 20px;
padding-bottom: 20px;
}
[class*='col-']:last-of-type {
padding-right: 0;
}
a {
text-decoration: none;
}
*, *:after, *:before {
-webkit-box-sizing: border-box;
-moz-box-sizing: border-box;
box-sizing: border-box;
}
h3 {
text-align: center; margin-bottom: 0;
}
h4 {
position: relative;
}
.grid {
margin: 0;
}
.col-1-4 {
width: 25%;
}
.module {
padding: 20px;
text-align: center;
color: #eee;
max-height: 120px;
min-width: 120px;
background-color: #607D8B;
border-radius: 2px;
}
.module:hover {
background-color: #EEE;
cursor: pointer;
color: #607d8b;
}
.grid-pad {
padding: 10px 0;
}
.grid-pad > [class*='col-']:last-of-type {
padding-right: 20px;
}
@media (max-width: 600px) {
.module {
font-size: 10px;
max-height: 75px; }
}
@media (max-width: 1024px) {
.grid {
margin: 0;
}
.module {
min-width: 60px;
}
}
26 changes: 26 additions & 0 deletions lib/src/dashboard_component.dart
@@ -0,0 +1,26 @@
import 'dart:async';

import 'package:angular/angular.dart';
import 'package:angular_router/angular_router.dart';

import 'hero.dart';
import 'hero_service.dart';
import 'hero_search_component.dart';

@Component(
selector: 'my-dashboard',
templateUrl: 'dashboard_component.html',
styleUrls: const ['dashboard_component.css'],
directives: const [CORE_DIRECTIVES, HeroSearchComponent, ROUTER_DIRECTIVES],
)
class DashboardComponent implements OnInit {
List<Hero> heroes;

final HeroService _heroService;

DashboardComponent(this._heroService);

Future<Null> ngOnInit() async {
heroes = (await _heroService.getHeroes()).skip(1).take(4).toList();
}
}
9 changes: 9 additions & 0 deletions lib/src/dashboard_component.html
@@ -0,0 +1,9 @@
<h3>Top Heroes</h3>
<div class="grid grid-pad">
<a *ngFor="let hero of heroes" [routerLink]="['HeroDetail', {id: hero.id.toString()}]" class="col-1-4">
<div class="module hero">
<h4>{{hero.name}}</h4>
</div>
</a>
</div>
<hero-search></hero-search>
13 changes: 13 additions & 0 deletions lib/src/hero.dart
@@ -0,0 +1,13 @@
class Hero {
final int id;
String name;

Hero(this.id, this.name);

factory Hero.fromJson(Map<String, dynamic> hero) =>
new Hero(_toInt(hero['id']), hero['name']);

Map toJson() => {'id': id, 'name': name};
}

int _toInt(id) => id is int ? id : int.parse(id);
29 changes: 29 additions & 0 deletions lib/src/hero_detail_component.css
@@ -0,0 +1,29 @@
label {
display: inline-block;
width: 3em;
margin: .5em 0;
color: #607D8B;
font-weight: bold;
}
input {
height: 2em;
font-size: 1em;
padding-left: .4em;
}
button {
margin-top: 20px;
font-family: Arial;
background-color: #eee;
border: none;
padding: 5px 10px;
border-radius: 4px;
cursor: pointer; cursor: hand;
}
button:hover {
background-color: #cfd8dc;
}
button:disabled {
background-color: #eee;
color: #ccc;
cursor: auto;
}

0 comments on commit ff08aa6

Please sign in to comment.