Compare commits
2098 Commits
7.2.14
...
zone.js-0.
Author | SHA1 | Date | |
---|---|---|---|
5eb7426216 | |||
7b3bcc23af | |||
b356fb01d5 | |||
f2219081e3 | |||
70ad91ed8b | |||
75ac724842 | |||
4c45aa39e4 | |||
c5d1e1a3da | |||
b1fe1aa8fa | |||
9177ffaf58 | |||
f4fe1f65be | |||
029f1be204 | |||
91008bd979 | |||
f0395836b6 | |||
4b16d98955 | |||
ab86a58f27 | |||
4ec50811d4 | |||
c34abf2cbc | |||
c6b180380a | |||
7814ef55c5 | |||
f72772b038 | |||
0bf810022a | |||
bc04d18420 | |||
7a53b9090e | |||
db08fd2607 | |||
3998335188 | |||
f4cd2b75b4 | |||
5909c442b7 | |||
f5fa9dc6b8 | |||
87665fe324 | |||
16ac611a84 | |||
beaab27a49 | |||
87168acf39 | |||
65544ac742 | |||
57c4788bc7 | |||
7e49beb8cd | |||
036294d566 | |||
98515e1ecf | |||
c52ade2878 | |||
4adf95ed6f | |||
a1fc4deff3 | |||
e0969b2480 | |||
c596795e64 | |||
a6cb20cbe7 | |||
6fbfb5a159 | |||
16aa6ceff8 | |||
b5aa0473fc | |||
e76690be29 | |||
6c4d91297e | |||
f41242f18e | |||
e2fd628618 | |||
2c2135d331 | |||
7e3a60ad31 | |||
85d38ae564 | |||
4ad323a4d6 | |||
a4601eca68 | |||
e84b51d2b6 | |||
8f5c396a7c | |||
0c3bb6a731 | |||
cc0bd11a5e | |||
5d24a75ac9 | |||
799d1fd333 | |||
6bc9c78d76 | |||
bb4e230eae | |||
48d11d5fa0 | |||
1a5c7112e0 | |||
352f9672c0 | |||
76584804c8 | |||
2c78da00ae | |||
bb8a18e72d | |||
82e0b4a4fb | |||
574990e0fd | |||
aa9eb55e3c | |||
052ef654d2 | |||
58be2ff884 | |||
7912db3829 | |||
0ee09cdd7e | |||
b2937b16c3 | |||
a4b4f35533 | |||
b0866769b0 | |||
699283c4ee | |||
bb635c09fd | |||
c15e6750d5 | |||
87bf1791a9 | |||
8c4bd61b2f | |||
230e9766f6 | |||
2b4d5c7548 | |||
271d2b51a9 | |||
7b0bee73de | |||
c9ce485ce0 | |||
ba4ca5f9a5 | |||
4155ed439a | |||
2b9a4cc6a6 | |||
016b3f16a3 | |||
87b1a2af4d | |||
a2cd401a2e | |||
93af1f8456 | |||
5193acb0a3 | |||
532c1cb485 | |||
ef0b2cc74d | |||
a794143820 | |||
ba83d33dd0 | |||
17d87d4e10 | |||
9d9c9e43e5 | |||
c0386757b1 | |||
5c18f23788 | |||
7afd2603c9 | |||
81c2a94310 | |||
297222f892 | |||
64488b12ac | |||
8b6fbf8655 | |||
383ab8515d | |||
11a4454ab3 | |||
04587a33c5 | |||
b4b7af86c2 | |||
f440bd1793 | |||
3859bcc70c | |||
30efb6b8ea | |||
05a43ca869 | |||
b51d8dd438 | |||
ea2d453118 | |||
17bfedd224 | |||
540b01402f | |||
8852b793df | |||
d1df0a94d4 | |||
00cc905b98 | |||
337b6fe003 | |||
ef4a15bc0b | |||
0d4f8c7dd9 | |||
b74df20c2a | |||
4ecff42e7f | |||
55a14e4866 | |||
c7850fff3b | |||
456f2e70af | |||
4da5e9a156 | |||
812c231b0c | |||
3ed7463ad7 | |||
8154433130 | |||
07cd65b5ec | |||
cd6fc8bf06 | |||
fcdd784667 | |||
a981dd2aab | |||
b4e68025f8 | |||
680d38513b | |||
21328f2373 | |||
dd8cf19352 | |||
8bedf50073 | |||
32886cf9ac | |||
fcef39048a | |||
1315d23aa4 | |||
8ce288a852 | |||
f936590573 | |||
876cd603f1 | |||
aca339e864 | |||
f4cd3740b2 | |||
6d861f240b | |||
1f79c827a0 | |||
e0c36620c1 | |||
80394ce08b | |||
99c9bcab03 | |||
fa354888b1 | |||
d82adbe8c4 | |||
09c57ecf95 | |||
282abdb02d | |||
19bbf4bc8e | |||
53c6b78c51 | |||
91699259b2 | |||
41f372fe79 | |||
8e8c1ad47d | |||
b61784948a | |||
b4644d7bb0 | |||
7a0f8ac36c | |||
5e0f982961 | |||
f5b0c8a323 | |||
d2b0ac7de8 | |||
a2d26c6f2a | |||
62332b80da | |||
e3f3b106ac | |||
fd23663a29 | |||
71be1da0ad | |||
6a5cc8f95c | |||
2c406fb1a9 | |||
0b23adca80 | |||
671f64324b | |||
f1f8d70a41 | |||
8301028319 | |||
ba5309c1f8 | |||
fa5d8ca041 | |||
24ca8ba7ce | |||
af4925f374 | |||
77578266fd | |||
7bf7244ba3 | |||
1a98d51f98 | |||
82682bb93f | |||
d72479b628 | |||
dd0815095f | |||
48093823cb | |||
51cb5925c5 | |||
a36cacae79 | |||
1b5096d5a9 | |||
875eedbfb0 | |||
75cdda5f0a | |||
6363db89d0 | |||
573f57ac90 | |||
41cf066906 | |||
661c6e6f10 | |||
84dd2679a9 | |||
dc6406e5e8 | |||
deb77bd3df | |||
d5f96a887d | |||
68cd0cab8c | |||
9b3af1468d | |||
be0bc799f3 | |||
0d23cedab8 | |||
6bf5ec241d | |||
cdb5ea4200 | |||
bfedfa79ed | |||
911a8160ec | |||
8479cb4233 | |||
250887244e | |||
9b035e4038 | |||
ccc76f7498 | |||
f310a5960e | |||
b5c893916d | |||
132c61dfd4 | |||
5640cedc82 | |||
faac51fd2e | |||
214ae0ea4c | |||
dcdecfa9a8 | |||
4299ecf9be | |||
21e8ac1e02 | |||
01cf04c85f | |||
5c5cee9f39 | |||
2f336f15be | |||
e122b44269 | |||
9ce9561737 | |||
2545445ffb | |||
300f1b289a | |||
975845596d | |||
2cdbe9b2ef | |||
988afad2af | |||
1537aec1f9 | |||
7555a46e23 | |||
38d7acee4d | |||
10f48278c2 | |||
d4e6263453 | |||
86c46908d4 | |||
fa6cbb3ffe | |||
e20b92ba37 | |||
c7a9987067 | |||
1bdec3ed6a | |||
620cd5c148 | |||
76391f8999 | |||
02523debe5 | |||
70fd4300f4 | |||
3125376ec1 | |||
2cd5294394 | |||
3c548189b1 | |||
ae91f45b27 | |||
f74e0fd825 | |||
f1ea78ba09 | |||
87a2366eeb | |||
0f5da82cfd | |||
66f269c077 | |||
b613f90146 | |||
2fe6f350cb | |||
514ebf402a | |||
7c0667d215 | |||
f6bf8928f2 | |||
6debe9dfb9 | |||
0d52a27f41 | |||
697046c2b2 | |||
53a0b26348 | |||
8c00fced1c | |||
a50c1bb7bc | |||
f3c69e7f6b | |||
c9f5f3d802 | |||
a96976e88f | |||
ebfbc04000 | |||
e1af6e3c70 | |||
9e946c9715 | |||
0d97143965 | |||
df1d3fbd7b | |||
e946594bf8 | |||
abe4433202 | |||
c79bffaacb | |||
e58e5ec6a6 | |||
e688e02ee4 | |||
d7eaae6f22 | |||
1c3ee41902 | |||
f78bda9ff0 | |||
6454f76cf6 | |||
28ae22ecb9 | |||
c1135ee18f | |||
1114053daa | |||
95830ee584 | |||
661a57d9e2 | |||
660a091f41 | |||
7d31f7b540 | |||
ab4a23d0e0 | |||
a39f4e2301 | |||
8e2e9dcee6 | |||
9d5abfb3d9 | |||
fd7dd4d9fc | |||
01919fbaae | |||
80d4fc5e26 | |||
eda09e69ea | |||
0937062a64 | |||
6f073885b0 | |||
f03475cac8 | |||
848e53efd0 | |||
6bf8b1007c | |||
98ded949dd | |||
a5a1f4f52f | |||
8c1a041411 | |||
b1ba2d6f4e | |||
1714451a6d | |||
1f6fcb6cd3 | |||
60235b5aef | |||
d18c58816f | |||
222dde129d | |||
257e9646d0 | |||
a5e06ba629 | |||
9a6d298ca7 | |||
6ec621b72d | |||
07ebe9624f | |||
b4014e9a39 | |||
73e3f565e0 | |||
757d4c33df | |||
edd775eabc | |||
c613596658 | |||
f4655ea98a | |||
f6aa60c03c | |||
7fec1771fc | |||
c9b588b349 | |||
37f69eddc7 | |||
0fa72a8bc8 | |||
48b77459ef | |||
989bfd2e97 | |||
aeec66b657 | |||
e68490c5e4 | |||
95c5b1a7f6 | |||
8e201f713a | |||
ac34a1429b | |||
739e5a4f53 | |||
bf94932c7a | |||
6cb3b50a03 | |||
0e92332491 | |||
f5127f601d | |||
1b613c3ebf | |||
3f7e823b80 | |||
e9ead2bc09 | |||
b6b1aec22b | |||
1aff524b63 | |||
077809398c | |||
f9404d9e7c | |||
b766987b98 | |||
c62c5e2999 | |||
f2ae452f01 | |||
79903b1842 | |||
0051ddf0f3 | |||
3a8f74e392 | |||
8555016eec | |||
45e11915dc | |||
1a0e500eea | |||
35c1750fcc | |||
53f356427f | |||
d20b0f4b93 | |||
79d4b16f8a | |||
0fd9d086e4 | |||
4f9b16783b | |||
018a5168a5 | |||
cf86ed7b29 | |||
dbb150a9bd | |||
9e5377a2e3 | |||
0cdf5980e2 | |||
6ceb9034dc | |||
f9fb921f91 | |||
1b059e595f | |||
ff29cccb77 | |||
c7f9a95a3f | |||
06efc340b6 | |||
3fecab64b1 | |||
34e0d621fd | |||
cc2f175617 | |||
96baff3a85 | |||
090eac068a | |||
d09d8e0adf | |||
a57f3e7bbf | |||
197584d1af | |||
18c0ba5272 | |||
1bd4891c9a | |||
3a7bfc721e | |||
f74373f2dd | |||
2f35dbfd3b | |||
31df5139c5 | |||
7569a2e0d9 | |||
7dad3284e3 | |||
0cf09fc981 | |||
877b2285f9 | |||
0d4a0b6519 | |||
4feb9b1c72 | |||
cb6dea473f | |||
5ab809ddf9 | |||
fbff03b476 | |||
411524d341 | |||
0a0b4c1d8f | |||
5887ddfa3c | |||
d80ae6ba0d | |||
44cf981407 | |||
5fd39283ec | |||
1f2b39ad7d | |||
24e172d779 | |||
b68850215a | |||
9abf114fbb | |||
8d3365e4fc | |||
8cec8f5584 | |||
741a5dc5f7 | |||
de996c6d56 | |||
d750b1e10d | |||
d2c83ea81b | |||
bf031fc56b | |||
b1d45ee6d2 | |||
f26f036286 | |||
0ffdb48f62 | |||
cb6ad971c3 | |||
d70b1ff177 | |||
3aff79c251 | |||
d8665e639b | |||
c016e2c4ec | |||
452f121486 | |||
728db88280 | |||
9a807bd26a | |||
eccc41c5cf | |||
509352fc36 | |||
349935a434 | |||
6357d4a0d3 | |||
29786e856d | |||
bf6bedd714 | |||
f094bb54a7 | |||
4c12d742dc | |||
04a9f28c3d | |||
d9b9ed56b6 | |||
7c8a62d64d | |||
de651122a5 | |||
4a96ddfb54 | |||
8ced321bb6 | |||
2a0f497e94 | |||
392473ec79 | |||
345a3cd9aa | |||
bd37622050 | |||
48de6e87f0 | |||
3b551e0fcd | |||
be8fbac942 | |||
98a38ec98b | |||
4f055d4257 | |||
c59717571e | |||
f5b2ae616f | |||
1660b34e2d | |||
b40f6f3eae | |||
3327bd8eab | |||
ea9a381c8c | |||
b2437c4500 | |||
d6538eb2fd | |||
0926119977 | |||
39f2c9f46b | |||
60a8888b4f | |||
4537816c1d | |||
bf73fb7420 | |||
1ec092ba32 | |||
30d1f292c9 | |||
b70d20b510 | |||
066ec33342 | |||
5b80ab372d | |||
638ba4a2cf | |||
7ec8806dc5 | |||
7d6f4885b2 | |||
b1506a3271 | |||
b15a403c71 | |||
37c598db04 | |||
ad94e02981 | |||
00ffc03523 | |||
e53cf81689 | |||
089fcbf369 | |||
68ff2cc323 | |||
164d160b22 | |||
1353bf0277 | |||
6dc884f2ab | |||
05eabb19d6 | |||
f4916730b5 | |||
67012509a8 | |||
28a1caa0ed | |||
f015dbe1ba | |||
029a93963a | |||
20898f9f4f | |||
ef861958a9 | |||
16d7dde2ad | |||
1fd2cc6340 | |||
5ced8fbbd5 | |||
23152c37c8 | |||
4a2405929c | |||
eef4ca5dd3 | |||
321da5cc83 | |||
c2cf500da9 | |||
4c03208537 | |||
78b5bd5174 | |||
1195dabb84 | |||
2945f47977 | |||
a44b510087 | |||
572b54967c | |||
6f433887e0 | |||
537502d685 | |||
e5c3695dbd | |||
3cf318b498 | |||
54d4105264 | |||
dd59b1d371 | |||
124e49752f | |||
fc2dd5482e | |||
e4b81a6957 | |||
3efdd39a18 | |||
582ef2e7b4 | |||
214fef2ee4 | |||
531fcaa99a | |||
8a60239ae7 | |||
10705684c8 | |||
bdc6818716 | |||
5f95796b61 | |||
f2709ac3f9 | |||
cce9b9912f | |||
2ae26ce20b | |||
d47de60944 | |||
acfcf90528 | |||
c99d379cc8 | |||
0151ad432b | |||
1b0be8d656 | |||
47244ba2b8 | |||
0d66844ad6 | |||
b945bc3a9e | |||
4ae0ee86cb | |||
6c86ae710a | |||
f3ce8eeb83 | |||
876ceb3688 | |||
ee12c45473 | |||
1f4c380f58 | |||
b9f0720c95 | |||
71b8b355a6 | |||
f45684ff95 | |||
5b134caf2d | |||
fcacb2a4a2 | |||
933772ed69 | |||
a03a9236f2 | |||
6de4cbdd41 | |||
61365a94ed | |||
3a9d2473ca | |||
6200732e23 | |||
304a12f027 | |||
acaf1aa530 | |||
282167a37f | |||
eb85c8a742 | |||
2002db28ff | |||
6c1ae294dc | |||
b8298f1b2d | |||
3def652e18 | |||
909557d5f8 | |||
957f594d7c | |||
8f120aff33 | |||
4cfba58072 | |||
aa53d6cc6d | |||
be28a6ad8e | |||
39c0152b76 | |||
d7887ab4ab | |||
2236ea4359 | |||
0ddf2e7a5b | |||
2dc4e8801c | |||
9914998e76 | |||
00866186a7 | |||
9e85d7ff0b | |||
28e6aa723a | |||
bb47ad295a | |||
169d51beb8 | |||
8b0ebe17b3 | |||
a400429faa | |||
e720675f8b | |||
d316a18dc6 | |||
79141f4424 | |||
28fd5ab12b | |||
c61df39323 | |||
abcb2cf9a0 | |||
a9379e0ed2 | |||
6da19599de | |||
46f547499d | |||
2864108510 | |||
e95f460f39 | |||
75a23ab623 | |||
071ee64d91 | |||
efdbbe1aa6 | |||
c0c8d2349c | |||
4277600d5e | |||
f185ff3792 | |||
ec455e1cf1 | |||
825efa8721 | |||
3a9cf3f2ba | |||
152d99eef0 | |||
b635fe80cc | |||
b44b14368f | |||
d0672c252e | |||
3938563565 | |||
00ea3983e3 | |||
ae93ba1140 | |||
2e21997016 | |||
24c61cb63e | |||
d0ca7c792d | |||
6c88eb7477 | |||
0fa76219ac | |||
6af9b8fb92 | |||
0b5f480eca | |||
2905bf5548 | |||
e8d3246c6e | |||
7e3137e7ed | |||
c7f1b0a97f | |||
8ca208ff59 | |||
089bfdf95f | |||
d92fb25161 | |||
aaf8145c48 | |||
04d13429f0 | |||
230e32905c | |||
c4dd2d115b | |||
4ca95641ee | |||
8e8e89a119 | |||
f84c4b066a | |||
2f1a862b83 | |||
24c06091f2 | |||
364250e7a6 | |||
00ce9aab5b | |||
8e73f9b0aa | |||
f7960c024c | |||
9873356bd0 | |||
0f9230d018 | |||
19dfadb717 | |||
0bcb2320ba | |||
0cab43785b | |||
54289aec2d | |||
57c8f78c8f | |||
8c80b851c8 | |||
ceea0b418c | |||
f730c72318 | |||
63523f7964 | |||
a9242c4fc2 | |||
94aeeec1dc | |||
645e305733 | |||
f53d0fd2d0 | |||
96a828993f | |||
71498a407a | |||
8cba4e1f6b | |||
5a07aa484d | |||
3f6bf6dfd1 | |||
c3c0df9d56 | |||
cb34514d05 | |||
017bf0b794 | |||
f348deae92 | |||
10217bb3bc | |||
a181e8e7d8 | |||
6ae0084255 | |||
2271f200d7 | |||
4e13700ad2 | |||
d9ce8a4ab5 | |||
42262e4e8c | |||
bea85ffe9c | |||
5268ae61a0 | |||
98f86de8da | |||
f4c536ae36 | |||
182e2c7449 | |||
cd1277cfb7 | |||
9277afce61 | |||
410151b07f | |||
073d258deb | |||
9f5288dad3 | |||
e3d5d41140 | |||
0df719a461 | |||
4229b41057 | |||
d7f7826363 | |||
9b93bd625f | |||
1f8325d6c4 | |||
5650e3847b | |||
11eef85133 | |||
f957c7c1cd | |||
e575892774 | |||
f9bb53a761 | |||
c1d5fbd0ad | |||
ca591641c7 | |||
2ba799ddc7 | |||
22294dfad1 | |||
d1b7d36646 | |||
0629ebd9e9 | |||
45c2429d30 | |||
78146c1890 | |||
e1f51eaa55 | |||
e5905bb035 | |||
b9251fd707 | |||
c0ec1d63ff | |||
4bde40f7c2 | |||
4271d35dc4 | |||
506f478f08 | |||
8a3a556c0c | |||
ce2713f5b1 | |||
7edfcf948f | |||
83291f01b0 | |||
725148a44d | |||
696e520842 | |||
5fee9daa5b | |||
1a56cd5c0b | |||
60e9d2da4f | |||
ca9b3eed9e | |||
a48d288ff8 | |||
d9c39dcab0 | |||
ca2462cff7 | |||
ab6036272c | |||
1794a8e42a | |||
86a3f90954 | |||
2bfb6a02e2 | |||
bd3164f88a | |||
b3edf494a4 | |||
5f1b6372c7 | |||
5d824c4153 | |||
ca755a6b72 | |||
2deac0a412 | |||
9147092a15 | |||
8027b3e19b | |||
3a836c362d | |||
ee603a3b01 | |||
b0c1282fbe | |||
446e3573e3 | |||
0d6c9d36a1 | |||
205a45e9a8 | |||
7a7781e925 | |||
b2962db4cb | |||
bd2ce9cd56 | |||
6a8cca7975 | |||
6a1441f727 | |||
d1d0f4a1ad | |||
70177e544b | |||
4f9c935473 | |||
ea70d41ac2 | |||
e2e637d70a | |||
911e0b8820 | |||
6c018001d3 | |||
0aa0f11a2b | |||
f6ee1c2219 | |||
d6b474f2f8 | |||
ac3dc3cfc6 | |||
bc6c671e6b | |||
b0578061ce | |||
54058ba3a7 | |||
91c7b451d5 | |||
387fbb8106 | |||
5b32f55a3a | |||
b507d076be | |||
cc2e4b639b | |||
6227d0bb3b | |||
ddadb8e22c | |||
def73a6728 | |||
f98093a30d | |||
77aff0b7bb | |||
712d60e467 | |||
3ea8d651cc | |||
faf8fdde14 | |||
4191344cb4 | |||
a80637e9a1 | |||
b71cd7b4ee | |||
147a15a419 | |||
1eb7e9b804 | |||
17c4ed9d0f | |||
675f3909d7 | |||
3e4698564a | |||
8c37cdc38a | |||
ad642e31cd | |||
09975120fd | |||
39bfd1a11f | |||
4e8c2c3422 | |||
ef85336719 | |||
138ca5a246 | |||
db62ccf9eb | |||
b0eefc872e | |||
4f0110e75a | |||
f24fd56ed1 | |||
411c505dae | |||
1102b02406 | |||
00bf636afa | |||
82c77ce232 | |||
632847d34d | |||
e682b4453c | |||
84be7c52dc | |||
98cf3e8fcd | |||
cb9ee3411f | |||
d144a3bd91 | |||
66b87cef33 | |||
c65ac7fbad | |||
ed12d7e949 | |||
cf40105fc0 | |||
38a3a5a1f1 | |||
902a53a4f6 | |||
e38115536f | |||
6d35c5094a | |||
4a2fb86b1e | |||
8bbf481d60 | |||
c5bba8d9f2 | |||
e02684e609 | |||
ec56354306 | |||
5c13feebfd | |||
30b04424a3 | |||
f8cdda63d4 | |||
b6f48dbe19 | |||
609024f93d | |||
9c056b974a | |||
c0ec8425c2 | |||
b02cb3dc01 | |||
2e66ddfdce | |||
7fbe138b1f | |||
0c47dc0466 | |||
2bd9214435 | |||
433b7b02a4 | |||
a4f3f3f81d | |||
6233cd55f7 | |||
c3aea737ff | |||
eaa49bdc04 | |||
96b76dc3f1 | |||
afd2417ecd | |||
699ecac2c2 | |||
c7ff728723 | |||
d96f62fdc4 | |||
b9fead7f83 | |||
648adb1894 | |||
9810c6c0f9 | |||
8e83b3bec1 | |||
3246399bff | |||
0f4f315f8e | |||
0a530e6b47 | |||
dc5577dcb1 | |||
a6809e0e7d | |||
ddb935fac7 | |||
afd4a4ed4d | |||
60afe88bcc | |||
2d372f48db | |||
45c6360e5a | |||
6b39c9cf32 | |||
c5799491e7 | |||
b14537a004 | |||
630aaa6bfb | |||
7c8f4e3202 | |||
15eb1e0ce1 | |||
780081def0 | |||
5a724b34bd | |||
03d914a6c2 | |||
98f8b0f328 | |||
5a1d21ebb4 | |||
cbd5d28f71 | |||
9f54d76ef5 | |||
e5201f92fc | |||
3487055d10 | |||
1c07061246 | |||
d11b0c0c41 | |||
1293da1cf7 | |||
7c1f73ac7b | |||
0e201ea9d8 | |||
53be333439 | |||
19081dc9a3 | |||
9e4c0bd815 | |||
deca6a60dd | |||
63013f1aeb | |||
8bfaaf164a | |||
1f469cd7bb | |||
7041e61562 | |||
7316212c1e | |||
aaa16f286d | |||
3e569767e3 | |||
abf69dec5b | |||
701da0099b | |||
f9497bf28b | |||
d7e5535d00 | |||
8d3d75e454 | |||
39345b6fae | |||
06859f1335 | |||
717aa7c6e4 | |||
9cd90532c1 | |||
ff2a55f14f | |||
0abd5f5f03 | |||
cd6581e4f0 | |||
76110d71d3 | |||
a4fb0486c1 | |||
8a13f6b278 | |||
ee7c5ed620 | |||
2ff3d2d421 | |||
33016b8929 | |||
b2c03b8cd4 | |||
fd4c939394 | |||
6759aa68dc | |||
ab4be7bf80 | |||
2b6e107b1e | |||
6a55ba28b2 | |||
33524d9d9c | |||
b99a070f88 | |||
799a5a4915 | |||
4b2407a4db | |||
ed19464be0 | |||
c67f6a7e60 | |||
d4c4a89431 | |||
12c9bd257d | |||
e8768acacc | |||
303eae918d | |||
50f7ab2a06 | |||
22b89ea58a | |||
e8921365b7 | |||
009acd2a6c | |||
333bfa0ffb | |||
eb0e29b269 | |||
71daa11357 | |||
a81fd5f750 | |||
57f7996b6d | |||
27ba4ac982 | |||
6c76dfc568 | |||
78ba503fb9 | |||
1df9908579 | |||
c456b73302 | |||
632669f069 | |||
33963ca0d3 | |||
7b27009e20 | |||
d46a7c8468 | |||
71ec99856a | |||
e958447100 | |||
931d356a10 | |||
e4c1c88cbc | |||
1e5a818719 | |||
e57ed61448 | |||
aaa8a3a957 | |||
80161d5033 | |||
6a66af7a27 | |||
9745f55a65 | |||
c9810064cb | |||
1727fe24fb | |||
4eb6b02f08 | |||
96b800c8bc | |||
dd69e4e780 | |||
401b8eedd5 | |||
8badf9808a | |||
f8c7c3c09c | |||
b17d1a9aa3 | |||
60f6d9e733 | |||
416b0d29b9 | |||
2b836c81a2 | |||
ac3ce0d793 | |||
6c33058856 | |||
50fb629012 | |||
309ffe7e16 | |||
fea2a0f2ac | |||
e0dcd11a49 | |||
3514543e4b | |||
d9162a872d | |||
06056b4a6d | |||
3c11646dd3 | |||
a2f8f5595f | |||
a28b3e3359 | |||
495a4c1754 | |||
17f7bdbd60 | |||
531fa00992 | |||
c412374854 | |||
9724247ad8 | |||
568140fb03 | |||
7951c4feb2 | |||
0f1da49b86 | |||
a5c9fa3c8f | |||
6feef368f6 | |||
c34c223122 | |||
26a8c5961e | |||
41225289d7 | |||
3612ddb433 | |||
09fab58109 | |||
b3102b9de1 | |||
cfe6581fc8 | |||
bef5043a5a | |||
b5295ad277 | |||
769d960db1 | |||
21be0fb926 | |||
9bcc1e8dce | |||
a06f0340d2 | |||
66b72bfa58 | |||
00075647be | |||
ce789b75a4 | |||
7baf45fe88 | |||
f3e0cc89ed | |||
cfa6e8e008 | |||
02debebcff | |||
ed8d60d060 | |||
9ea0d64d8b | |||
dfcf759e33 | |||
21835af70c | |||
2790352d04 | |||
bb6a3632f6 | |||
2d859a8c3a | |||
70fffba054 | |||
e185d3a4ad | |||
6f3052b799 | |||
c18fa7b5bd | |||
693b350567 | |||
0b27c09b51 | |||
861d6f1523 | |||
dc10355d61 | |||
6cd3743b44 | |||
a24f4b51b3 | |||
84baa0bb08 | |||
e721c08c7f | |||
37a154e4e6 | |||
415de9a291 | |||
b3dda0ebc1 | |||
41737bb4d3 | |||
afe3e72601 | |||
5e3bbf79a6 | |||
d2b64cc008 | |||
9eb8274991 | |||
17b3f11e07 | |||
10734ac607 | |||
68a9fe817c | |||
64e5628897 | |||
849b327986 | |||
a827bc2e3a | |||
083fb99033 | |||
55ea8da6eb | |||
7ea0d1bd3a | |||
bdcbd9ed4b | |||
b48d6e1b13 | |||
68f9d705f8 | |||
229f035969 | |||
c9f7cdaafd | |||
7b55ba58b9 | |||
cd449021c1 | |||
4bb0259bc0 | |||
66239b9d09 | |||
a770aa231d | |||
cf4718c366 | |||
07aeafa75c | |||
7a67f8935d | |||
bc88816c10 | |||
0d0445063a | |||
ddfdf3cd26 | |||
d6d081e120 | |||
38c778e371 | |||
3249020466 | |||
d6e27a41ed | |||
1a4d4a0e13 | |||
3121409957 | |||
fd122b0739 | |||
9a364a82fb | |||
a530ed11e8 | |||
2d7435daae | |||
b460b26308 | |||
ea90435a6b | |||
ea0e832e5f | |||
7c4afb0da7 | |||
603df13b14 | |||
f9b7b6d2f1 | |||
dafbbf8b64 | |||
d59f02d902 | |||
20bf4ca382 | |||
aae6f7b40b | |||
5f50562be5 | |||
efcd6af17d | |||
56c345baec | |||
19ff32036e | |||
37cc514f0f | |||
067657c1e9 | |||
8714daf276 | |||
d5e3f2c64b | |||
bc99b774ba | |||
a3ec058f6b | |||
4605df83e1 | |||
c0ad9e104d | |||
a9020a028f | |||
e769f9cfe4 | |||
4a665ca50b | |||
e9fab63385 | |||
5454227057 | |||
0244a2433e | |||
86aba1e8f3 | |||
ae4a86e3b5 | |||
ce4da3f8e5 | |||
e79f57a6b8 | |||
c439e14d39 | |||
a8d84660e5 | |||
4525619a73 | |||
4742385e95 | |||
d87b035ebb | |||
b759d63389 | |||
fe759ee0cf | |||
105cfaf5e4 | |||
2ab194c999 | |||
7b5d326d77 | |||
8e70ca39cc | |||
9d090cb3db | |||
3d5b98631a | |||
e8df000e97 | |||
604f37b679 | |||
4d912b6b12 | |||
bf2db12fc9 | |||
dfb220ea6b | |||
04b5ea089c | |||
7561698675 | |||
8ef690c342 | |||
3facdebd07 | |||
1db8bf312e | |||
f7738ad8d6 | |||
fc8048ddaf | |||
b2aadffbbc | |||
8ed13a37f0 | |||
1877e6c3f8 | |||
1a9ab2727e | |||
bf0704d685 | |||
1fb670e06c | |||
f50928f5b7 | |||
fe448e8222 | |||
7c297e05f3 | |||
487d4157ac | |||
90df7de54d | |||
8ef46f38f4 | |||
7b70760c8d | |||
6ab8c0b371 | |||
80379697e2 | |||
a5c747f46d | |||
410ccacf38 | |||
e76cf8c775 | |||
9be4ab51ea | |||
4990b935b4 | |||
08231f0bfa | |||
a3e105487d | |||
2064508876 | |||
0c59342cd0 | |||
018477e2c4 | |||
1f0eadfab6 | |||
f2dc32e5c7 | |||
019e65abfb | |||
0ffa2f2e73 | |||
a5a35ff54a | |||
7b20cec986 | |||
eb00a37eb8 | |||
75748d6044 | |||
9a7f5601fa | |||
955e4e704e | |||
73da2792c9 | |||
1625d86178 | |||
c4c34fe60e | |||
29fae6de08 | |||
ccb70e1c64 | |||
940fbf796c | |||
ec01594e97 | |||
ac0553e802 | |||
fe76494759 | |||
9d4b7d7d41 | |||
fa8669ac00 | |||
3f32c0e674 | |||
b7c17ff207 | |||
c5daaa91cf | |||
360730ce59 | |||
fca1724ebf | |||
3c53713616 | |||
c09d0ed627 | |||
af52536419 | |||
1c251e59d7 | |||
ec8b74da56 | |||
6085f335e8 | |||
7315a68ac6 | |||
e6117a3a49 | |||
a8b432d55d | |||
37b9f06f1e | |||
9d1423df7e | |||
df354d1b34 | |||
4227126305 | |||
e20a29a153 | |||
76119b84dc | |||
defc30c7ab | |||
869e1cdcec | |||
ed4675e5a1 | |||
4b39bdf7e5 | |||
146256a4e0 | |||
1d88c2bb81 | |||
99aa9674b2 | |||
6b6fdffc12 | |||
a29ce57732 | |||
4b9eb6185f | |||
ca20f571b8 | |||
a5b8420234 | |||
49dccf4bfc | |||
3a6ba00286 | |||
c37ec8b255 | |||
fc305305e1 | |||
b012ab210b | |||
b3ffdf92c5 | |||
7b0e9eddd1 | |||
a746b5b1ea | |||
b6f6b1178f | |||
37c5a26421 | |||
142ac41cac | |||
d4728c40d9 | |||
a68b1a1894 | |||
014841dfef | |||
63d18064fe | |||
fd5cd100a3 | |||
aa6db0d191 | |||
b14df413eb | |||
22c71b69ce | |||
d95e059480 | |||
ad9415af1d | |||
4f2773eaef | |||
f4f20daee3 | |||
36a1550e00 | |||
5ad2097be8 | |||
809452b921 | |||
f535f31d78 | |||
e3a401d20c | |||
423ac01dcf | |||
c7e4931f32 | |||
b73e02005b | |||
9a1959269f | |||
f71dae8f63 | |||
941c99ad7f | |||
3ef2002bd8 | |||
479ae51d1f | |||
eccbc785b3 | |||
29f57e315e | |||
c866c11bf8 | |||
15e84950ec | |||
7060d9038b | |||
14ce8a9c31 | |||
f856a6597b | |||
887faffa25 | |||
0bd4261f23 | |||
f96efd1c98 | |||
22ddbf4b02 | |||
268c3fe816 | |||
dc6192c8e5 | |||
7102ea80a9 | |||
6b98b534c8 | |||
c5d9035bab | |||
d5a8be76f2 | |||
9c1ced102e | |||
54286b8c27 | |||
84406e4d6d | |||
c29d2a4f16 | |||
84f3dfbca4 | |||
3bee0f684d | |||
881807dc36 | |||
20a9dbef8e | |||
25166d4f41 | |||
6215799055 | |||
ff9550542c | |||
69265b7b5d | |||
b446095c4d | |||
1efad3772e | |||
e8bb8f4912 | |||
4486dabf01 | |||
01577b0bed | |||
7c57293bee | |||
3063547975 | |||
72ecc45363 | |||
7d174969c2 | |||
79e2ca0c0e | |||
586234bb01 | |||
5fded9fcc8 | |||
866d500324 | |||
04cf4ef0c7 | |||
aa57bdbf90 | |||
78adcfe0ee | |||
48214e2a05 | |||
95989a12dd | |||
c5f1d08a43 | |||
3403027698 | |||
c875851bb4 | |||
d2f015f57e | |||
05a9090ded | |||
bfc40da6aa | |||
43ce6ec84a | |||
842d615928 | |||
a352b73962 | |||
fa82d2d6f1 | |||
83ba587c18 | |||
dcafddefb8 | |||
c0757d1d44 | |||
a06824aef6 | |||
ba602dbaec | |||
b1df9a30f4 | |||
3e5c1bcb9f | |||
b50283ed67 | |||
a23a0bc3a4 | |||
7ac58bec8a | |||
ff8e4dddb2 | |||
f01d1c4c8d | |||
b5629d98d8 | |||
ac76e5d8dd | |||
0bc26fc4e8 | |||
c532646f5b | |||
9fe522f3e2 | |||
4a1640bdd5 | |||
8cd72441f1 | |||
ea09430039 | |||
cd83a43462 | |||
1d4dde2adc | |||
58198075f2 | |||
2e43e15e12 | |||
5874247494 | |||
d207c4894a | |||
5fdf24e843 | |||
03d2e5cb1d | |||
2b974d4012 | |||
3a6e443e19 | |||
cb20b3b40a | |||
f7c867ebc2 | |||
76979e12c9 | |||
772b24ccc3 | |||
91a161aa13 | |||
efa10e33a9 | |||
daf8251998 | |||
a6ae759b46 | |||
827e89cfc4 | |||
40833ba54b | |||
34bdebcdd2 | |||
034de06ab1 | |||
2dd44d712d | |||
f16fca41d6 | |||
b8d87490f5 | |||
d127d05dc3 | |||
7b944c46d3 | |||
c4c3c1231b | |||
41de05e1ae | |||
dad5a258b8 | |||
ce68b4d839 | |||
dc335194ab | |||
f380263393 | |||
5a4c402663 | |||
262ba67525 | |||
dc9f0af080 | |||
8f8f9a6e61 | |||
25a2fef303 | |||
dbd9ecfd4c | |||
f01247f0a4 | |||
846c431eb7 | |||
edb6c2d814 | |||
3cb497c6ac | |||
bd65f58784 | |||
1930e8a072 | |||
7a11242388 | |||
65de0d6d0e | |||
ef1b9e6d71 | |||
65d3ddabf3 | |||
0b8aad2ca0 | |||
0071048cf9 | |||
9f7a9c607e | |||
22880eae16 | |||
3d48cde3b1 | |||
61495a138d | |||
319ed5168a | |||
f79cd5963e | |||
350802b207 | |||
10ba91b1d3 | |||
f75acbd99b | |||
395fb186a4 | |||
f0989b786b | |||
c64b13e593 | |||
7bae49b419 | |||
929fe029c2 | |||
ba6aa93aa3 | |||
f0f81f482e | |||
3144bf4d73 | |||
bb050a8ae0 | |||
75357ecb32 | |||
c1392ce618 | |||
15c065f9a0 | |||
fafabc0b92 | |||
ad4a9bf03f | |||
43181ea568 | |||
9dac04ff50 | |||
7f3e3a8c45 | |||
6ccf743627 | |||
230a941c3f | |||
7c20bf8845 | |||
82820b0b2c | |||
1778bd3470 | |||
33f71e8ce3 | |||
cbfc1f238e | |||
c7fe3a92de | |||
9ca356559b | |||
7c1b9ff5ec | |||
599e2e22bc | |||
2df2168c0a | |||
8043db570f | |||
de036d29e3 | |||
94223a09e5 | |||
65d839da03 | |||
32ae84da28 | |||
93a7836f7a | |||
9defc00b14 | |||
1145bdb478 | |||
f4d652568d | |||
3cc9ba24c6 | |||
3f2b51b837 | |||
d8704a3069 | |||
64e6aaa4f1 | |||
e1aaa7ec48 | |||
0ea216b993 | |||
ebffde7143 | |||
9ae14db343 | |||
95d9aa22ef | |||
df627e65df | |||
72d043f669 | |||
be121bba85 | |||
58436fd81a | |||
3336de0970 | |||
d0b6622b9a | |||
13b96ac91d | |||
623fd3fb5e | |||
bcdd4b5729 | |||
05c25ccca7 | |||
cfb2d176f8 | |||
d0e81eb593 | |||
09d894c283 | |||
81c3104f76 | |||
68da4658ff | |||
b9eb662c4a | |||
04ae1251c7 | |||
1832e0f293 | |||
9cecb0b5d2 | |||
bca0b44ff2 | |||
e5e4e63e71 | |||
96b597cfd0 | |||
669b4410f2 | |||
1eccf64b15 | |||
2d804198d5 | |||
fd4e1d69ee | |||
02ee8c7bc5 | |||
67ad8a2632 | |||
25aae64274 | |||
eb39633823 | |||
71d0eeb966 | |||
295a143ae0 | |||
ad6475ffac | |||
3c1a1620e3 | |||
a4638d5a81 | |||
ae16378ee7 | |||
73b9cd75b9 | |||
71e64e93e6 | |||
d8ae8993d8 | |||
19afb791b4 | |||
5e68e35112 | |||
745c9c5ca7 | |||
a834c745d7 | |||
4131715df5 | |||
692ddfcbb5 | |||
e0f3fd72dd | |||
00a8b07896 | |||
80c7aff5cc | |||
6788d86709 | |||
ababc5b4a4 | |||
af8d58cb51 | |||
9e82cebe5b | |||
90b304612e | |||
caefc5d4c4 | |||
1923c2f99c | |||
a17fd43fd5 | |||
0cc5804169 | |||
55b144bdf5 | |||
980bb52d36 | |||
6b511a33f6 | |||
3c7ce823a3 | |||
fdca0013d5 | |||
1e6ed52cba | |||
04a1923af7 | |||
911599d9a3 | |||
c1094cf46f | |||
2e3cc45c74 | |||
6fcf286344 | |||
fcc8c5690f | |||
8accc98d28 | |||
aa8d0809d3 | |||
80a5934af6 | |||
7cbc36fdac | |||
63e5d2787b | |||
83fd66d1d0 | |||
627cecdfe2 | |||
b41da03f00 | |||
65c2deacbb | |||
841a1d32e1 | |||
362c41de89 | |||
cf848c6ea0 | |||
47574fef11 | |||
b0afc4c638 | |||
1df3aefb81 | |||
8cec4b3ff7 | |||
9e5d1357fe | |||
3bb3d6d3e6 | |||
3d39100c85 | |||
3842dd6a6d | |||
36df9056af | |||
2c6a6f18c2 | |||
423b39e216 | |||
a529f53031 | |||
99d8582882 | |||
d2742cf473 | |||
f8b67712bc | |||
3477610f6d | |||
09af7ea4f5 | |||
dba2a406fd | |||
fb194d5146 | |||
0a4811c4ad | |||
13685131bc | |||
1a326d5690 | |||
28bdeeef3e | |||
6fa4235543 | |||
6d057cc05d | |||
2f27a8051b | |||
77eee42963 | |||
553f80ff46 | |||
5cafd44654 | |||
cb0a8b566f | |||
cf6d63ca63 | |||
1d20088291 | |||
7e895b9179 | |||
39d0311e4e | |||
644e7a28d8 | |||
f8b9e61469 | |||
2ea030c2c5 | |||
49fb8c3cb0 | |||
0c7581da89 | |||
06ec95f2ef | |||
91b7152852 | |||
fc8f4f8029 | |||
2afc40608d | |||
ac58d01a8e | |||
d68a98f0cd | |||
08de52b9f0 | |||
cffd86260a | |||
497619f25d | |||
c0dac184cd | |||
e6a00be014 | |||
4f46bfb779 | |||
a5ea55a636 | |||
0d6fdec4bd | |||
54ca24b47d | |||
8c3f1717a8 | |||
8d15dd8b70 | |||
2424184d42 | |||
eeb560ac88 | |||
1b0580a9ec | |||
673ac2945c | |||
81df5dcfc0 | |||
6050cd0c1b | |||
0cb02d906e | |||
0957d8cb3f | |||
1b82e11e69 | |||
cdabda1fc0 | |||
188f20fb16 | |||
3eec314ba9 | |||
e6c51b3e06 | |||
f358188ec1 | |||
5db3a6b198 | |||
94b8aaeba8 | |||
fe8301c462 | |||
e5861e1c79 | |||
2bf0d1a56f | |||
2ca77da4ca | |||
a9afe629c7 | |||
1e64f37257 | |||
99e3a04ea2 | |||
570f735a2a | |||
872a3656fe | |||
9ec8aa5eb7 | |||
5f2ae784da | |||
0a95f8af9f | |||
531aa5f8db | |||
bfee33edb9 | |||
1941d7c743 | |||
21b5940abd | |||
2852beaded | |||
206a21704d | |||
46e6363686 | |||
457e07ccb1 | |||
05a14f8a8b | |||
19f13b1ad4 | |||
d29f781685 | |||
0770978dfb | |||
863dbeeb7c | |||
425e0ee416 | |||
81329c85b3 | |||
fcd1f61476 | |||
e9bedc63bb | |||
7115e7c427 | |||
aadc332be2 | |||
c916b360bf | |||
fed8c1d160 | |||
fb9a4a668c | |||
f7591f1302 | |||
44de68ce40 | |||
2c00cb8f0f | |||
1ff3699d99 | |||
0e4705aec3 | |||
6e4ef91ceb | |||
ceada7785e | |||
d91ea2c499 | |||
faf0b255d0 | |||
90670252de | |||
94f042beba | |||
9d109929be | |||
e0d2ca261b | |||
4b7264f60f | |||
6f9dd1bf28 | |||
c3fadadaa9 | |||
b65fe62be1 | |||
f2a734bd06 | |||
00e24b3000 | |||
1950e2d9ba | |||
7660d0d74a | |||
264ef72800 | |||
f889317f93 | |||
df3cea41de | |||
36284713b2 | |||
ce83231ce9 | |||
2caa419990 | |||
71fa1f2a45 | |||
50732e1564 | |||
3de06dd794 | |||
9ce0c23c77 | |||
08f55b35a5 | |||
2b9811dad4 | |||
df74da02c6 | |||
8d90142a0f | |||
851cf16134 | |||
353362f5a4 | |||
0e6f799aec | |||
6709db9677 | |||
43081a01d8 | |||
e3032a0d17 | |||
01bb3c5820 | |||
43467c95ab | |||
69ecb96569 | |||
e991d825f5 | |||
ed032e08c1 | |||
ae8b7b1fdb | |||
62a13e795a | |||
22d3226491 | |||
5ebc0da640 | |||
eed59b713a | |||
b2a6bf2a80 | |||
0709f8411d | |||
d42f32cc61 | |||
2ea4f690e4 | |||
d4add5428b | |||
8f15cdbc7c | |||
baf103c98f | |||
3f73dfa151 | |||
7c5c1fae62 | |||
89eac702b5 | |||
5a2c3ff8b5 | |||
ed0cf7e2cb | |||
4ceb655c11 | |||
5a6f0d0af9 | |||
979582a2ed | |||
63b744bb6a | |||
fe4d811086 | |||
4142db0828 | |||
7a6237bc50 | |||
ebaceb37e0 | |||
62c0deac42 | |||
57034aa13d | |||
cec1fa04c2 | |||
0d1e065a1c | |||
8d11627e6c | |||
4a92fa9471 | |||
744b0205e2 | |||
40da1be1e1 | |||
c10d86cbc0 | |||
b91a25bfb2 | |||
e11ac7f24b | |||
4aa189da67 | |||
dde7e2f253 | |||
8edd9cd6c0 | |||
76a6eacb4e | |||
9ef8d2b823 | |||
07fb4b5677 | |||
728fe69625 | |||
7219639ff3 | |||
f2621dbb37 | |||
3c7fdc6a9e | |||
5cdbdc9ee0 | |||
16a78f97f5 | |||
ee74835619 | |||
5a257d02a6 | |||
e4fb93c28a | |||
b7738ef9e4 | |||
463a7894ae | |||
fc88a79b32 | |||
a98d66078d | |||
1e5012b2cc | |||
3d522716c4 | |||
52d3795336 | |||
4dfcbc6afa | |||
71b9d5539b | |||
7a22019b3d | |||
f6805de8eb | |||
72c36956de | |||
895a8d6f3b | |||
814ee260f5 | |||
bfd48d156d | |||
5c4d95541e | |||
8930f60a4b | |||
36902e2f0e | |||
ec6e7303dd | |||
1b33142595 | |||
1b6d8a78b0 | |||
6656328538 | |||
9efb39c8a2 | |||
f640941e1d | |||
c0b383590e | |||
35e45dc894 | |||
b35ef184a7 | |||
b1e099b657 | |||
a9c881e243 | |||
038303eed1 | |||
a227c528ca | |||
0eef958735 | |||
51a592cdfc | |||
fdc6e159b4 | |||
7d9aa67d8c | |||
495a9dd445 | |||
778d5739e2 | |||
66ce3b2f2f | |||
76cedb8bf3 | |||
ad499628cb | |||
24f5428187 | |||
a228d65412 | |||
dc8e461303 | |||
eeadb37b19 | |||
41e68f7a7a | |||
dabcb3e17b | |||
bcf17bc91c | |||
d45d3a3ef9 | |||
f99a668b04 | |||
70e426ba1b | |||
ec414b432e | |||
9af18c2fd0 | |||
2bb518c694 | |||
b87bf39eb4 | |||
227f7e44d6 | |||
22f76df8f2 | |||
e18a52e24a | |||
f38deb0f07 | |||
d940b5541f | |||
8e75a40735 | |||
59cc724e3b | |||
8ced999e47 | |||
4c8d17ffd4 | |||
3e6a1f0bc4 | |||
40d64b6b58 | |||
c84739dc55 | |||
bb94434d85 | |||
ebac5dba38 | |||
29513296fb | |||
98e5af1480 | |||
66335c36e6 | |||
6e16338302 | |||
9a3739142f | |||
e98d508df2 | |||
5639891e90 | |||
9d81bd39ca | |||
9d3dae42e9 | |||
1699c88655 | |||
074400da60 | |||
7d954dffd0 | |||
cac9199d7c | |||
a789a3f532 | |||
5dbc7d9a63 | |||
fd8dbd5e40 | |||
7033f39c61 | |||
3deda898d0 | |||
f8c70011b1 | |||
adfc55e2c3 | |||
a1f36e5f14 | |||
3b48d13af8 | |||
f7c551e16b | |||
e4f67dfe66 | |||
d83307adab | |||
873750609f | |||
664ea50b46 | |||
99886bd159 | |||
3d5a919ac5 | |||
ef6728207b | |||
2da82db3bc | |||
7421534873 | |||
7496630a94 | |||
6e949f9e98 | |||
6ad1c47df8 | |||
76144f156c | |||
fdc2b0bf77 | |||
54532dfdf1 | |||
2a02f4beb2 | |||
bf97d3b73e | |||
46aec4a58f | |||
c522e03fe9 | |||
b2811e50c5 | |||
e2c98fbe11 | |||
02975e9166 | |||
3414316fc8 | |||
67a41d8bff | |||
e50c5293fc | |||
056d35c97c | |||
465abab213 | |||
c1fb9c265c | |||
d4ecffe475 | |||
736cfa4e09 | |||
cbd626413c | |||
317cc922ac | |||
f9b103825a | |||
32c61f434c | |||
22a43cff4d | |||
9098225ff0 | |||
9f9024b7a1 | |||
03c8528fcb | |||
5430d2bc66 | |||
a95e81978b | |||
5552661fd7 | |||
030350f53e | |||
583061d043 | |||
0a564c3158 | |||
b9854e582f | |||
cf8770f3cc | |||
d8f2318811 | |||
1fd673504c | |||
8f1198ffcd | |||
fe9b3ea251 | |||
50df897fdc | |||
33e49c2894 | |||
ea1b5c100f | |||
18a9afc738 | |||
589dd479e2 | |||
661a98aeda | |||
988243437a | |||
3b9553bb17 | |||
522e4ea898 | |||
b6819fe9bb | |||
6c3b57a968 | |||
37f8263430 | |||
a84a9ba705 | |||
d73734dcb7 | |||
e0fbe8611e | |||
94e305f48e | |||
1964be0b17 | |||
41b2499f17 | |||
da85cee07c | |||
2fc5f002e0 | |||
19a2b783cf | |||
9e5016c845 | |||
070fca1591 | |||
d336bff200 | |||
f99082fd3c | |||
75074d009f | |||
197676a6dd | |||
1fb6731285 | |||
1df8be5573 | |||
6324ad45e7 | |||
7439b46c5a | |||
9a965c9145 | |||
351ef2a6de | |||
0b6eaca3c2 | |||
058aafcc0c | |||
7980f1d2ea | |||
6bd20e8b2f | |||
366a6bf192 | |||
5b08a880f7 | |||
7db035842d | |||
9dabeea807 | |||
73dcd72afb | |||
7bdf3fe41c | |||
38343a2388 | |||
45bf911df8 | |||
ab2bf83398 | |||
2b9cc8503d | |||
a58fd210e9 | |||
6940992932 | |||
c1c87462fd | |||
73616ab237 | |||
a0cdefb5fb | |||
f8ad4d1e99 | |||
5a582a8afd | |||
e172e97e13 | |||
0d6913f037 | |||
896cf35afb | |||
1f7d3b9a57 | |||
8a08ff1571 | |||
50cf2ac6d8 | |||
80967ce82c | |||
1a85de302d | |||
808898d015 | |||
f59f18c13e | |||
a570fdf0f0 | |||
e7d5c12ea4 | |||
1e5e62ef56 | |||
bac71ef419 | |||
da1d19b40f | |||
9a81f0d9a8 | |||
c61ea1d5bd | |||
47665c9937 | |||
3b7a571cc5 | |||
f983e99fb2 | |||
4f009e7a03 | |||
29bff0f02e | |||
3a31a2795e | |||
ce3a746644 | |||
bc02e31185 | |||
6072ca87e1 | |||
9460218f36 | |||
850b86749c | |||
a24120011e | |||
d49d1e7d73 | |||
2e5752eb06 | |||
da8ee29e72 | |||
693045165c | |||
e62eeed7d4 | |||
06e5bf1661 | |||
60fecc1284 | |||
b6510a320b | |||
fa53150692 | |||
b5c2ef2877 | |||
ddd8cd0573 | |||
cfb41452ce | |||
f1fb62d1e5 | |||
d12db4e114 | |||
68bdbf0520 | |||
857fcfe048 | |||
60fb27c4ab | |||
4c0104c846 | |||
72f2428cd8 | |||
d577b8df75 | |||
cd0451305a | |||
e8495b460f | |||
2c9f0139a3 | |||
fc881390d0 | |||
1ec01d6758 | |||
4bb5f638bc | |||
0897ebac9e | |||
657cf733a2 | |||
d6aca79410 | |||
e4c899e4ba | |||
5e6e96d844 | |||
9c2f6d72d6 | |||
638375b7ca | |||
c5b67b95b7 | |||
78bc21c63a | |||
48a03fcc80 | |||
6fff74e576 | |||
978ffa9d32 | |||
6a9a48b0ac | |||
da2880d7c4 | |||
fca185e191 | |||
e082fc24b2 | |||
133fe5e561 | |||
2afbcafab7 | |||
605f450251 | |||
9260b5e0b4 | |||
9a128a8068 | |||
cd51775390 | |||
fe4d3a1619 | |||
b73d6781da | |||
0c6fa1df52 | |||
ce51dfb499 | |||
8ebdb437dc | |||
b0caf02d4f | |||
091a8a6fd5 | |||
61bc61fc59 | |||
df292c2ce0 | |||
51e716b6f2 | |||
94893accdb | |||
6c6d43086f | |||
8c3f98fdbb | |||
89a39bb22a | |||
12f509c218 | |||
76104f395f | |||
18ccfc6d73 | |||
3ea9f0974a | |||
a100472b5d | |||
a6f7fe394a | |||
e31afb7118 | |||
d505468fb7 | |||
f854eb7dec | |||
b0f3c20a4c | |||
26a8c095d0 | |||
bccf8da35f | |||
acb2caced0 | |||
96f4969a2b | |||
aebec4b156 | |||
9277142d54 | |||
b78351cc7e | |||
885f1af509 | |||
b05baa59e0 | |||
ad6569c744 | |||
feebe03523 | |||
e8a57f0ee6 | |||
a6ba789599 | |||
3bafc002ae | |||
afaea110c7 | |||
dffcb9cda3 | |||
ee60c7679a | |||
e0e92cfef6 | |||
65e72e958e | |||
76ed13bffe | |||
7374dfd1fa | |||
c5ab3e8fd2 | |||
142553abc6 | |||
6003145422 | |||
3cf1b62722 | |||
5a0deb8d69 | |||
4694c93315 | |||
94c0b7a362 | |||
0136274f33 | |||
8934b736c8 | |||
11325bad4a | |||
d0c3e252a3 | |||
e1e4887feb | |||
6f9881f85f | |||
6beeb76ac0 | |||
1f904bffbc | |||
9b2b9b3bef | |||
91a8a4fb28 | |||
582395b8f5 | |||
76580b98f0 | |||
5609764886 | |||
29e3144269 | |||
d68ad3e617 | |||
d6cfe2ed7e | |||
eb1aae4043 | |||
935ce63b73 | |||
31fdff7121 | |||
c7d1890aaa | |||
c7346bfdba | |||
d2b2d813d5 | |||
72fc0a747d | |||
cea3b8f885 | |||
5e7c71e51c | |||
4e17212d44 | |||
c3aa24c3f9 | |||
1de4031d9c | |||
1c39ad38d3 | |||
0b9094ec63 | |||
ac157170c8 | |||
f4a9f5dae8 | |||
2a6108af97 | |||
37b716b298 | |||
f6c91c5a5a | |||
b621a69cda | |||
3fba6eff79 | |||
b9c6df6da7 | |||
1a7f92c423 | |||
a0840242d7 | |||
090801532e | |||
b541c48688 | |||
b432eb1cae | |||
cc5fb914bc | |||
d72ae7b71e | |||
aaa97f11d7 | |||
4b5b1f6d16 | |||
c2f19515d6 | |||
6e7c46af1b | |||
917c09cfc8 | |||
f5471107d9 | |||
e6ab55daa0 | |||
7db05c408c | |||
483f8250bf | |||
8e530a03b6 | |||
b47c43af45 | |||
4fc41517d1 | |||
c80071dd59 | |||
98472da03f | |||
7ac8b02ec5 | |||
0199e26167 | |||
17291e66a0 | |||
7de7b7a16a | |||
bb5ddee710 | |||
04ca3bcf10 | |||
c1dacdd890 | |||
9de9c8ad03 | |||
4613864fc8 | |||
ac5f5ed0a6 | |||
8122970f63 | |||
8473d68ea8 | |||
4caf6540d1 | |||
a75c734471 | |||
e775313188 | |||
996435b79a | |||
45880532bf | |||
e08feb7e54 | |||
8a3cebde8b | |||
d80c32310a | |||
3ac249b2ab | |||
e94e7eef4c | |||
654055b22f |
@ -4,3 +4,5 @@ aio/content
|
|||||||
aio/node_modules
|
aio/node_modules
|
||||||
aio/tools/examples/shared/node_modules
|
aio/tools/examples/shared/node_modules
|
||||||
integration/bazel
|
integration/bazel
|
||||||
|
integration/bazel-schematics/demo
|
||||||
|
packages/bazel/node_modules
|
||||||
|
53
.bazelrc
53
.bazelrc
@ -10,8 +10,10 @@ build:angular-team --remote_http_cache=https://storage.googleapis.com/angular-te
|
|||||||
|
|
||||||
# Make compilation fast, by keeping a few copies of the compilers
|
# Make compilation fast, by keeping a few copies of the compilers
|
||||||
# running as daemons, and cache SourceFile AST's to reduce parse time.
|
# running as daemons, and cache SourceFile AST's to reduce parse time.
|
||||||
build --strategy=TypeScriptCompile=worker
|
|
||||||
build --strategy=AngularTemplateCompile=worker
|
build --strategy=AngularTemplateCompile=worker
|
||||||
|
# TODO(alexeagle): re-enable after fixing worker instability with rxjs typings
|
||||||
|
# build --strategy=TypeScriptCompile=worker
|
||||||
|
build --strategy=TypeScriptCompile=standalone
|
||||||
|
|
||||||
# Enable debugging tests with --config=debug
|
# Enable debugging tests with --config=debug
|
||||||
test:debug --test_arg=--node_options=--inspect-brk --test_output=streamed --test_strategy=exclusive --test_timeout=9999 --nocache_test_results
|
test:debug --test_arg=--node_options=--inspect-brk --test_output=streamed --test_strategy=exclusive --test_timeout=9999 --nocache_test_results
|
||||||
@ -51,6 +53,22 @@ build --incompatible_strict_action_env
|
|||||||
run --incompatible_strict_action_env
|
run --incompatible_strict_action_env
|
||||||
test --incompatible_strict_action_env
|
test --incompatible_strict_action_env
|
||||||
|
|
||||||
|
###############################
|
||||||
|
# Saucelabs support #
|
||||||
|
# Turn on these settings with #
|
||||||
|
# --config=saucelabs #
|
||||||
|
###############################
|
||||||
|
|
||||||
|
# Expose SauceLabs environment to actions
|
||||||
|
# These environment variables are needed by
|
||||||
|
# web_test_karma to run on Saucelabs
|
||||||
|
test:saucelabs --action_env=SAUCE_USERNAME
|
||||||
|
test:saucelabs --action_env=SAUCE_ACCESS_KEY
|
||||||
|
test:saucelabs --action_env=SAUCE_READY_FILE
|
||||||
|
test:saucelabs --action_env=SAUCE_PID_FILE
|
||||||
|
test:saucelabs --action_env=SAUCE_TUNNEL_IDENTIFIER
|
||||||
|
test:saucelabs --define=KARMA_WEB_TEST_MODE=SL_REQUIRED
|
||||||
|
|
||||||
###############################
|
###############################
|
||||||
# Release support #
|
# Release support #
|
||||||
# Turn on these settings with #
|
# Turn on these settings with #
|
||||||
@ -98,16 +116,21 @@ build --define=compile=legacy
|
|||||||
# --config=remote
|
# --config=remote
|
||||||
###############################
|
###############################
|
||||||
|
|
||||||
# Load default settings for Remote Build Execution
|
# Load default settings for Remote Build Execution.
|
||||||
# When updating, the URLs of bazel_toolchains in packages/bazel/package.bzl
|
import %workspace%/third_party/github.com/bazelbuild/bazel-toolchains/bazelrc/.bazelrc.notoolchain
|
||||||
# may also need to be updated (see https://github.com/angular/angular/pull/27935)
|
|
||||||
import %workspace%/third_party/github.com/bazelbuild/bazel-toolchains/bazelrc/bazel-0.21.0.bazelrc
|
|
||||||
|
|
||||||
# Increase the default number of jobs by 50% because our build has lots of
|
# Increase the default number of jobs by 50% because our build has lots of
|
||||||
# parallelism
|
# parallelism
|
||||||
build:remote --jobs=150
|
build:remote --jobs=150
|
||||||
|
|
||||||
# Point to our custom execution platform; see tools/BUILD.bazel
|
# Toolchain and platform related flags
|
||||||
|
build:remote --host_javabase=@rbe_ubuntu1604_angular//java:jdk
|
||||||
|
build:remote --javabase=@rbe_ubuntu1604_angular//java:jdk
|
||||||
|
build:remote --host_java_toolchain=@bazel_tools//tools/jdk:toolchain_hostjdk8
|
||||||
|
build:remote --java_toolchain=@bazel_tools//tools/jdk:toolchain_hostjdk8
|
||||||
|
build:remote --crosstool_top=@rbe_ubuntu1604_angular//cc:toolchain
|
||||||
|
build:remote --action_env=BAZEL_DO_NOT_DETECT_CPP_TOOLCHAIN=1
|
||||||
|
build:remote --extra_toolchains=@rbe_ubuntu1604_angular//config:cc-toolchain
|
||||||
build:remote --extra_execution_platforms=//tools:rbe_ubuntu1604-angular
|
build:remote --extra_execution_platforms=//tools:rbe_ubuntu1604-angular
|
||||||
build:remote --host_platform=//tools:rbe_ubuntu1604-angular
|
build:remote --host_platform=//tools:rbe_ubuntu1604-angular
|
||||||
build:remote --platforms=//tools:rbe_ubuntu1604-angular
|
build:remote --platforms=//tools:rbe_ubuntu1604-angular
|
||||||
@ -119,6 +142,20 @@ build:remote --remote_instance_name=projects/internal-200822/instances/default_i
|
|||||||
# We need to understand the security risks of using prior build artifacts.
|
# We need to understand the security risks of using prior build artifacts.
|
||||||
build:remote --remote_accept_cached=false
|
build:remote --remote_accept_cached=false
|
||||||
|
|
||||||
# Load any settings specific to the current user. Needs to be last statement in this
|
###############################
|
||||||
# config, as the user configuration should be able to overwrite flags from this file.
|
# NodeJS rules settings
|
||||||
|
# These settings are required for rules_nodejs
|
||||||
|
###############################
|
||||||
|
|
||||||
|
# Turn on managed directories feature in Bazel
|
||||||
|
# This allows us to avoid installing a second copy of node_modules
|
||||||
|
common --experimental_allow_incremental_repository_updates
|
||||||
|
|
||||||
|
####################################################
|
||||||
|
# User bazel configuration
|
||||||
|
# NOTE: This needs to be the *last* entry in the config.
|
||||||
|
####################################################
|
||||||
|
|
||||||
|
# Load any settings which are specific to the current user. Needs to be *last* statement
|
||||||
|
# in this config, as the user configuration should be able to overwrite flags from this file.
|
||||||
try-import .bazelrc.user
|
try-import .bazelrc.user
|
||||||
|
@ -1,42 +0,0 @@
|
|||||||
# Heavily based on https://github.com/StefanScherer/dockerfiles-windows/ images.
|
|
||||||
# Combines the node windowsservercore image with the Bazel Prerequisites (https://docs.bazel.build/versions/master/install-windows.html).
|
|
||||||
# msys install taken from https://github.com/StefanScherer/dockerfiles-windows/issues/30
|
|
||||||
# VS redist install taken from https://github.com/StefanScherer/dockerfiles-windows/blob/master/apache/Dockerfile
|
|
||||||
# The nanoserver image won't work because MSYS2 does not run in it https://github.com/Alexpux/MSYS2-packages/issues/1493
|
|
||||||
|
|
||||||
# Before building this image, you must locally build node-windows:10.13.0-windowsservercore-1803.
|
|
||||||
# Clone https://github.com/StefanScherer/dockerfiles-windows/commit/4ce7101a766b9b880ac262479dd9126b64d656cf and build using
|
|
||||||
# docker build -t node-windows:10.13.0-windowsservercore-1803 --build-arg core=microsoft/windowsservercore:1803 --build-arg target=microsoft/windowsservercore:1803 .
|
|
||||||
FROM node-windows:10.13.0-windowsservercore-1803
|
|
||||||
|
|
||||||
SHELL ["powershell", "-Command", "$ErrorActionPreference = 'Stop'; $ProgressPreference = 'SilentlyContinue';"]
|
|
||||||
|
|
||||||
# Install 7zip to extract msys2
|
|
||||||
RUN Invoke-WebRequest -UseBasicParsing 'https://www.7-zip.org/a/7z1805-x64.exe' -OutFile 7z.exe
|
|
||||||
# For some reason the last letter in the destination directory is lost. So '/D=C:\\7zip0' will extract to '/D=C:\\7zip'.
|
|
||||||
RUN Start-Process -FilePath 'C:\\7z.exe' -ArgumentList '/S', '/D=C:\\7zip0' -NoNewWindow -Wait
|
|
||||||
|
|
||||||
# Extract msys2
|
|
||||||
RUN Invoke-WebRequest -UseBasicParsing 'http://repo.msys2.org/distrib/x86_64/msys2-base-x86_64-20180531.tar.xz' -OutFile msys2.tar.xz
|
|
||||||
RUN Start-Process -FilePath 'C:\\7zip\\7z' -ArgumentList 'e', 'msys2.tar.xz' -Wait
|
|
||||||
RUN Start-Process -FilePath 'C:\\7zip\\7z' -ArgumentList 'x', 'msys2.tar', '-oC:\\' -Wait
|
|
||||||
RUN Remove-Item msys2.tar.xz
|
|
||||||
RUN Remove-Item msys2.tar
|
|
||||||
RUN Remove-Item 7z.exe
|
|
||||||
RUN Remove-Item -Recurse 7zip
|
|
||||||
|
|
||||||
# Add MSYS2 to PATH, and set BAZEL_SH
|
|
||||||
RUN [Environment]::SetEnvironmentVariable('Path', $env:Path + ';C:\msys64\usr\bin', [System.EnvironmentVariableTarget]::Machine)
|
|
||||||
RUN [Environment]::SetEnvironmentVariable('BAZEL_SH', 'C:\msys64\usr\bin\bash.exe', [System.EnvironmentVariableTarget]::Machine)
|
|
||||||
|
|
||||||
# Install Microsoft Visual C++ Redistributable for Visual Studio 2015
|
|
||||||
RUN Invoke-WebRequest -UseBasicParsing 'https://download.microsoft.com/download/9/3/F/93FCF1E7-E6A4-478B-96E7-D4B285925B00/vc_redist.x64.exe' -OutFile vc_redist.x64.exe
|
|
||||||
RUN Start-Process 'c:\\vc_redist.x64.exe' -ArgumentList '/Install', '/Passive', '/NoRestart' -NoNewWindow -Wait
|
|
||||||
RUN Remove-Item vc_redist.x64.exe
|
|
||||||
|
|
||||||
# Add a fix for https://github.com/docker/for-win/issues/2920 as entry point to the container.
|
|
||||||
SHELL ["cmd", "/c"]
|
|
||||||
COPY "fix-msys64.cmd" "C:\\fix-msys64.cmd"
|
|
||||||
ENTRYPOINT cmd /C C:\\fix-msys64.cmd && cmd /c
|
|
||||||
|
|
||||||
CMD ["cmd.exe"]
|
|
@ -1,96 +0,0 @@
|
|||||||
# BuildKite configuration
|
|
||||||
|
|
||||||
This folder contains configuration for the [BuildKite](https://buildkite.com) based CI checks for
|
|
||||||
this repository.
|
|
||||||
|
|
||||||
BuildKite is a CI provider that provides build coordination and reports while we provide the
|
|
||||||
infrastructure.
|
|
||||||
|
|
||||||
CI runs are triggered by new PRs and will show up on the GitHub checks interface, along with the
|
|
||||||
other current CI solutions.
|
|
||||||
|
|
||||||
Currently it is only used for tests on Windows platforms.
|
|
||||||
|
|
||||||
|
|
||||||
## The build pipeline
|
|
||||||
|
|
||||||
BuildKite uses a pipeline for each repository. The `pipeline.yml` file defines pipeline
|
|
||||||
[build steps](https://buildkite.com/docs/pipelines/defining-steps) for this repository.
|
|
||||||
|
|
||||||
Run results can be seen in the GitHub checks interface and in the
|
|
||||||
[pipeline dashboard](https://buildkite.com/angular/angular).
|
|
||||||
|
|
||||||
Although most configuration is done via `pipeline.yml`, some options are only available
|
|
||||||
in the online [pipeline settings](https://buildkite.com/angular/angular/settings).
|
|
||||||
|
|
||||||
|
|
||||||
## Infrastructure
|
|
||||||
|
|
||||||
BuildKite does not provide the host machines where the builds runs, providing instead the
|
|
||||||
[BuildKite Agent](https://buildkite.com/docs/agent/v3) that should be run our own infrastructure.
|
|
||||||
|
|
||||||
|
|
||||||
### Agents
|
|
||||||
|
|
||||||
This agent polls the BuildKite API for builds, runs them, and reports back the results.
|
|
||||||
Agents are the unit of concurrency: each agent can run one build at any given time.
|
|
||||||
Adding agents allows more builds to be ran at the same time.
|
|
||||||
|
|
||||||
Individual agents can have tags, and pipeline steps can target only agents with certain tags via the
|
|
||||||
`agents` field in `pipeline.yml`.
|
|
||||||
For example: agents on Windows machines are tagged as `windows`, and the Windows specific build
|
|
||||||
steps list `windows: true` in their `agents` field.
|
|
||||||
|
|
||||||
You can see the current agent pool, along with their tags, in the
|
|
||||||
[agents list](https://buildkite.com/organizations/angular/agents).
|
|
||||||
|
|
||||||
|
|
||||||
### Our host machines
|
|
||||||
|
|
||||||
We use [Google Cloud](https://cloud.google.com/) as our cloud provider, under the
|
|
||||||
[Angular project](https://console.cloud.google.com/home/dashboard?project=internal-200822).
|
|
||||||
To access this project you need need to be logged in with a Google account that's a member of
|
|
||||||
team@angular.io.
|
|
||||||
For googlers this may be your google.com account, for others it is an angular.io account.
|
|
||||||
|
|
||||||
In this project we have a number of Windows VMs running, each of them with several agents.
|
|
||||||
The `provision-windows-buildkite.ps1` file contains instructions on how to create new host VMs that
|
|
||||||
are fully configured to run the BuildKite agents as services.
|
|
||||||
|
|
||||||
Our pipeline uses [docker-buildkite-plugin](https://github.com/buildkite-plugins/docker-buildkite-plugin)
|
|
||||||
to run build steps inside docker containers.
|
|
||||||
This way we achieve isolation and hermeticity.
|
|
||||||
|
|
||||||
The `Dockerfile` file describes a custom Docker image that includes NodeJs, Yarn, and the Bazel
|
|
||||||
pre-requisites on Windows.
|
|
||||||
|
|
||||||
To upload a new version of the docker image, follow any build instructions in `Dockerfile` and then
|
|
||||||
run `docker build -t angular/node-bazel-windows:NEW_VERSION`, followed by
|
|
||||||
`docker push angular/node-bazel-windows:NEW_VERSION`.
|
|
||||||
After being pushed it should be available online, and you can use the new version in `pipeline.yml`.
|
|
||||||
|
|
||||||
|
|
||||||
## Caretaker
|
|
||||||
|
|
||||||
BuildKite status can be found at https://www.buildkitestatus.com/.
|
|
||||||
|
|
||||||
Issues related to the BuildKite setup should be escalated to the Tools Team via the current
|
|
||||||
caretaker, followed by Alex Eagle and Filipe Silva.
|
|
||||||
|
|
||||||
Support requests should be submitted via email to support@buildkite.com and cc Igor, Misko, Alex,
|
|
||||||
Jeremy and Manu
|
|
||||||
|
|
||||||
|
|
||||||
## Rollout strategy
|
|
||||||
|
|
||||||
At the moment our BuildKite CI uses 1 host VM running 4 agents, thus being capable of 4 concurrent
|
|
||||||
builds.
|
|
||||||
The only test running is `bazel test //tools/ts-api-guardian:all`, and the PR check is not
|
|
||||||
mandatory.
|
|
||||||
|
|
||||||
In the future we should add cache support to speed up the initial `yarn` install, and also Bazel
|
|
||||||
remote caching to speed up Bazel builds.
|
|
||||||
|
|
||||||
After the current setup is verified as stable and reliable the GitHub PR check can become mandatory.
|
|
||||||
|
|
||||||
The tests ran should also be expanded to cover most, if not all, of the Bazel tests.
|
|
@ -1,6 +0,0 @@
|
|||||||
@echo off
|
|
||||||
REM Fix for https://github.com/docker/for-win/issues/2920
|
|
||||||
REM echo "Fixing msys64 folder..."
|
|
||||||
REM Touch all .dll files inside C:\msys64\
|
|
||||||
forfiles /p C:\msys64\ /s /m *.dll /c "cmd /c Copy /B @path+,, >NUL"
|
|
||||||
REM echo "Fixed msys64 folder."
|
|
@ -1,10 +0,0 @@
|
|||||||
steps:
|
|
||||||
- label: windows-test
|
|
||||||
commands:
|
|
||||||
- "yarn install --frozen-lockfile --non-interactive --network-timeout 100000"
|
|
||||||
- "yarn bazel test //tools/ts-api-guardian:all --noshow_progress"
|
|
||||||
plugins:
|
|
||||||
- docker#v2.1.0:
|
|
||||||
image: "filipesilva/node-bazel-windows:0.0.2"
|
|
||||||
agents:
|
|
||||||
windows: true
|
|
@ -1,92 +0,0 @@
|
|||||||
# PowerShell script to provision a Windows Server with BuildKite
|
|
||||||
# This script follows https://buildkite.com/docs/agent/v3/windows.
|
|
||||||
|
|
||||||
# Instructions
|
|
||||||
|
|
||||||
# VM creation:
|
|
||||||
# In Google Cloud Platform, create a Compute Engine instance.
|
|
||||||
# We recommend machine type n1-highcpu-16 (16 vCPUs, 14.4 GB memory).
|
|
||||||
# Use a windows boot disk with container support such as
|
|
||||||
# "Windows Server version 1803 Datacenter Core for Containers".
|
|
||||||
# Give it a name, then click "Create".
|
|
||||||
|
|
||||||
# VM setup:
|
|
||||||
# In the Compute Engine menu, select "VM Instances". Click on the VM name you chose before.
|
|
||||||
# Click "Set Windows Password" to choose a username and password.
|
|
||||||
# Click RDP to open a remote desktop via browser, using the username and password.
|
|
||||||
# In the Windows command prompt start an elevated powershell by inputing
|
|
||||||
# "powershell -Command "Start-Process PowerShell -Verb RunAs" followed by Enter.
|
|
||||||
# Download and execute this script from GitHub, passing the token (mandatory), tags (optional)
|
|
||||||
# and number of agents (optional) as args:
|
|
||||||
# ```
|
|
||||||
# Invoke-WebRequest -Uri https://raw.githubusercontent.com/angular/angular/master/.buildkite/provision-windows-buildkite.ps1 -OutFile provision.ps1
|
|
||||||
# .\provision.ps1 -token "MY_TOKEN" -tags "windows=true,another_tag=true" -agents 4
|
|
||||||
# ```
|
|
||||||
# The VM should restart and be fully configured.
|
|
||||||
|
|
||||||
# Creating extra VMs
|
|
||||||
# You can create an image of the current VM by following the instructions below.
|
|
||||||
# https://cloud.google.com/compute/docs/instances/windows/creating-windows-os-image
|
|
||||||
# Then create a new VM and choose "Custom images".
|
|
||||||
|
|
||||||
|
|
||||||
# Script proper.
|
|
||||||
|
|
||||||
# Get the token and tags from arguments.
|
|
||||||
param (
|
|
||||||
[Parameter(Mandatory=$true)][string]$token,
|
|
||||||
[string]$tags = ""
|
|
||||||
[Int]$agents = 1
|
|
||||||
)
|
|
||||||
|
|
||||||
# Allow HTTPS
|
|
||||||
[Net.ServicePointManager]::SecurityProtocol = "tls12, tls11, tls"
|
|
||||||
|
|
||||||
# Helper to add to PATH.
|
|
||||||
# Will take current PATH so avoid running it after anything to modifies only the powershell session path.
|
|
||||||
function Add-Path ([string]$newPathItem) {
|
|
||||||
$Env:Path+= ";" + $newPathItem + ";"
|
|
||||||
[Environment]::SetEnvironmentVariable("Path",$env:Path, [System.EnvironmentVariableTarget]::Machine)
|
|
||||||
}
|
|
||||||
|
|
||||||
# Install Git for Windows
|
|
||||||
Write-Host "Installing Git for Windows."
|
|
||||||
Invoke-WebRequest -Uri https://github.com/git-for-windows/git/releases/download/v2.19.1.windows.1/Git-2.19.1-64-bit.exe -OutFile git.exe
|
|
||||||
.\git.exe /VERYSILENT /NORESTART /NOCANCEL /SP- /CLOSEAPPLICATIONS /RESTARTAPPLICATIONS /COMPONENTS="icons,ext\reg\shellhere,assoc,assoc_sh" /DIR="C:\git"
|
|
||||||
Add-Path "C:\git\bin"
|
|
||||||
Remove-Item git.exe
|
|
||||||
|
|
||||||
# Download NSSM (https://nssm.cc/) to run the BuildKite agent as a service.
|
|
||||||
Write-Host "Downloading NSSM."
|
|
||||||
Invoke-WebRequest -Uri https://nssm.cc/ci/nssm-2.24-101-g897c7ad.zip -OutFile nssm.zip
|
|
||||||
Expand-Archive -Path nssm.zip -DestinationPath C:\nssm
|
|
||||||
Add-Path "C:\nssm\nssm-2.24-101-g897c7ad\win64"
|
|
||||||
Remove-Item nssm.zip
|
|
||||||
|
|
||||||
# Run the BuildKite agent install script
|
|
||||||
Write-Host "Installing BuildKite agent."
|
|
||||||
$env:buildkiteAgentToken = $token
|
|
||||||
$env:buildkiteAgentTags = $tags
|
|
||||||
Set-ExecutionPolicy Bypass -Scope Process -Force
|
|
||||||
iex ((New-Object System.Net.WebClient).DownloadString('https://raw.githubusercontent.com/buildkite/agent/master/install.ps1'))
|
|
||||||
|
|
||||||
# Configure the BuildKite agent clone and timestamp behavior
|
|
||||||
Add-Content C:\buildkite-agent\buildkite-agent.cfg "`ngit-clone-flags=--config core.autocrlf=input --config core.eol=lf --config core.longpaths=true --config core.symlinks=true`n"
|
|
||||||
Add-Content C:\buildkite-agent\buildkite-agent.cfg "`ntimestamp-lines=true`n"
|
|
||||||
|
|
||||||
# Register the BuildKite agent service using NSSM, so that it persists through restarts and is
|
|
||||||
# restarted if the process dies.
|
|
||||||
for ($i=1; $i -le $agents; $i++)
|
|
||||||
{
|
|
||||||
$agentName = "buildkite-agent-$i"
|
|
||||||
Write-Host "Registering $agentName as a service."
|
|
||||||
nssm.exe install $agentName "C:\buildkite-agent\bin\buildkite-agent.exe" "start"
|
|
||||||
nssm.exe set $agentName AppStdout "C:\buildkite-agent\$agentName.log"
|
|
||||||
nssm.exe set $agentName AppStderr "C:\buildkite-agent\$agentName.log"
|
|
||||||
nssm.exe status $agentName
|
|
||||||
nssm.exe start $agentName
|
|
||||||
nssm.exe status $agentName
|
|
||||||
}
|
|
||||||
|
|
||||||
# Restart the machine.
|
|
||||||
Restart-Computer
|
|
@ -15,8 +15,8 @@
|
|||||||
# `CI_CHROMEDRIVER_VERSION_ARG` env var (in `.circleci/env.sh`) points to a ChromeDriver
|
# `CI_CHROMEDRIVER_VERSION_ARG` env var (in `.circleci/env.sh`) points to a ChromeDriver
|
||||||
# version that is compatible with the Chrome version in the image.
|
# version that is compatible with the Chrome version in the image.
|
||||||
# **NOTE 2**: If you change the version of the docker images, also change the `cache_key` suffix.
|
# **NOTE 2**: If you change the version of the docker images, also change the `cache_key` suffix.
|
||||||
var_1: &default_docker_image circleci/node:10.12
|
var_1: &default_docker_image circleci/node:10.16
|
||||||
var_2: &browsers_docker_image circleci/node:10.12-browsers
|
var_2: &browsers_docker_image circleci/node:10.16-browsers
|
||||||
# We don't want to include the current branch name in the cache key because that would prevent
|
# We don't want to include the current branch name in the cache key because that would prevent
|
||||||
# PRs from being able to restore the cache since the branch names are always different for PRs.
|
# PRs from being able to restore the cache since the branch names are always different for PRs.
|
||||||
# The cache key should only consist of dynamic values that change whenever something in the
|
# The cache key should only consist of dynamic values that change whenever something in the
|
||||||
@ -26,7 +26,7 @@ var_2: &browsers_docker_image circleci/node:10.12-browsers
|
|||||||
# **NOTE 1 **: If you change the cache key prefix, also sync the restore_cache fallback to match.
|
# **NOTE 1 **: If you change the cache key prefix, also sync the restore_cache fallback to match.
|
||||||
# **NOTE 2 **: Keep the static part of the cache key as prefix to enable correct fallbacks.
|
# **NOTE 2 **: Keep the static part of the cache key as prefix to enable correct fallbacks.
|
||||||
# See https://circleci.com/docs/2.0/caching/#restoring-cache for how prefixes work in CircleCI.
|
# See https://circleci.com/docs/2.0/caching/#restoring-cache for how prefixes work in CircleCI.
|
||||||
var_3: &cache_key v3-angular-node-10.12-{{ checksum "yarn.lock" }}-{{ checksum "WORKSPACE" }}-{{ checksum "packages/bazel/package.bzl" }}-{{ checksum "aio/yarn.lock" }}
|
var_3: &cache_key v3-angular-node-10.16-{{ checksum "yarn.lock" }}-{{ checksum "WORKSPACE" }}-{{ checksum "packages/bazel/package.bzl" }}-{{ checksum "aio/yarn.lock" }}
|
||||||
|
|
||||||
# Initializes the CI environment by setting up common environment variables.
|
# Initializes the CI environment by setting up common environment variables.
|
||||||
var_4: &init_environment
|
var_4: &init_environment
|
||||||
@ -53,7 +53,10 @@ var_5: &setup_bazel_remote_execution
|
|||||||
run:
|
run:
|
||||||
name: "Setup bazel RBE remote execution"
|
name: "Setup bazel RBE remote execution"
|
||||||
command: |
|
command: |
|
||||||
openssl aes-256-cbc -d -in .circleci/gcp_token -k "$CI_REPO_NAME" -out /home/circleci/.gcp_credentials
|
# We need ensure that the same default digest is used for encoding and decoding
|
||||||
|
# with openssl. Openssl versions might have different default digests which can
|
||||||
|
# cause decryption failures based on the openssl version. https://stackoverflow.com/a/39641378/4317734
|
||||||
|
openssl aes-256-cbc -d -in .circleci/gcp_token -md md5 -k "$CI_REPO_NAME" -out /home/circleci/.gcp_credentials
|
||||||
echo "export GOOGLE_APPLICATION_CREDENTIALS=/home/circleci/.gcp_credentials" >> $BASH_ENV
|
echo "export GOOGLE_APPLICATION_CREDENTIALS=/home/circleci/.gcp_credentials" >> $BASH_ENV
|
||||||
sudo bash -c "echo 'build --config=remote' >> /etc/bazel.bazelrc"
|
sudo bash -c "echo 'build --config=remote' >> /etc/bazel.bazelrc"
|
||||||
|
|
||||||
@ -99,7 +102,7 @@ var_10: &restore_cache
|
|||||||
keys:
|
keys:
|
||||||
- *cache_key
|
- *cache_key
|
||||||
# This fallback should be the cache_key without variables.
|
# This fallback should be the cache_key without variables.
|
||||||
- v3-angular-node-10.12-
|
- v3-angular-node-10.16-
|
||||||
|
|
||||||
# Branch filter that can be specified for jobs that should only run on publish branches
|
# Branch filter that can be specified for jobs that should only run on publish branches
|
||||||
# (e.g. master or the patch branch)
|
# (e.g. master or the patch branch)
|
||||||
@ -167,10 +170,18 @@ jobs:
|
|||||||
- *attach_workspace
|
- *attach_workspace
|
||||||
- *init_environment
|
- *init_environment
|
||||||
- *setup_circleci_bazel_config
|
- *setup_circleci_bazel_config
|
||||||
|
# Enable remote/sibling docker which is needed by auto-selection of toolchain configs for RBE.
|
||||||
|
- setup_remote_docker
|
||||||
# Setup remote execution and run RBE-compatible tests.
|
# Setup remote execution and run RBE-compatible tests.
|
||||||
- *setup_bazel_remote_execution
|
- *setup_bazel_remote_execution
|
||||||
- run: yarn bazel test //... --build_tag_filters=-ivy-only --test_tag_filters=-ivy-only
|
- run: yarn bazel test //... --build_tag_filters=-ivy-only --test_tag_filters=-ivy-only
|
||||||
|
- run: mkdir ~/testlogs
|
||||||
|
- run: cp -Lr dist/testlogs/* ~/testlogs
|
||||||
|
- store_test_results:
|
||||||
|
# Bazel always writes test.xml files under this directory
|
||||||
|
path: ~/testlogs
|
||||||
|
- store_artifacts:
|
||||||
|
path: ~/testlogs
|
||||||
|
|
||||||
# Temporary job to test what will happen when we flip the Ivy flag to true
|
# Temporary job to test what will happen when we flip the Ivy flag to true
|
||||||
test_ivy_aot:
|
test_ivy_aot:
|
||||||
@ -180,6 +191,8 @@ jobs:
|
|||||||
- *attach_workspace
|
- *attach_workspace
|
||||||
- *init_environment
|
- *init_environment
|
||||||
- *setup_circleci_bazel_config
|
- *setup_circleci_bazel_config
|
||||||
|
# Enable remote/sibling docker which is needed by auto-selection of toolchain configs for RBE.
|
||||||
|
- setup_remote_docker
|
||||||
- *setup_bazel_remote_execution
|
- *setup_bazel_remote_execution
|
||||||
|
|
||||||
# We need to explicitly specify the --symlink_prefix option because otherwise we would
|
# We need to explicitly specify the --symlink_prefix option because otherwise we would
|
||||||
@ -206,6 +219,35 @@ jobs:
|
|||||||
path: dist/bin/packages/core/test/bundling/todo/bundle.min.js.br
|
path: dist/bin/packages/core/test/bundling/todo/bundle.min.js.br
|
||||||
destination: core/todo/bundle.br
|
destination: core/todo/bundle.br
|
||||||
|
|
||||||
|
test_saucelabs_bazel:
|
||||||
|
<<: *job_defaults
|
||||||
|
# In order to avoid the bottleneck of having a slow host machine, we acquire a better
|
||||||
|
# container for this job. This is necessary because we launch a lot of browsers concurrently
|
||||||
|
# and therefore the tunnel and Karma need to process a lot of file requests and tests.
|
||||||
|
resource_class: xlarge
|
||||||
|
steps:
|
||||||
|
- *attach_workspace
|
||||||
|
- *init_environment
|
||||||
|
- *setup_circleci_bazel_config
|
||||||
|
- run:
|
||||||
|
name: Preparing environment for running tests on Saucelabs.
|
||||||
|
command: setSecretVar SAUCE_ACCESS_KEY $(echo $SAUCE_ACCESS_KEY | rev)
|
||||||
|
- run:
|
||||||
|
name: Starting Saucelabs tunnel
|
||||||
|
command: ./scripts/saucelabs/start-tunnel.sh
|
||||||
|
background: true
|
||||||
|
# Waits for the Saucelabs tunnel to be ready. This ensures that we don't run tests
|
||||||
|
# too early without Saucelabs not being ready.
|
||||||
|
- run: ./scripts/saucelabs/wait-for-tunnel.sh
|
||||||
|
# All web tests are contained within a single //:test_web_all target for Saucelabs
|
||||||
|
# as running each set of tests as a separate target will attempt to acquire too
|
||||||
|
# many browsers on Saucelabs (7 per target currently) and some tests will always
|
||||||
|
# fail to acquire browsers. For example:
|
||||||
|
# 14 02 2019 19:52:33.170:WARN [launcher]: chrome beta on SauceLabs have not captured in 180000 ms, killing.
|
||||||
|
# //packages/forms/test:web_test_sauce TIMEOUT in 315.0s
|
||||||
|
- run: yarn bazel test --config=saucelabs //:test_web_all
|
||||||
|
- run: ./scripts/saucelabs/stop-tunnel.sh
|
||||||
|
|
||||||
test_aio:
|
test_aio:
|
||||||
<<: *job_defaults
|
<<: *job_defaults
|
||||||
docker:
|
docker:
|
||||||
@ -218,16 +260,14 @@ jobs:
|
|||||||
- run: yarn --cwd aio build --progress=false
|
- run: yarn --cwd aio build --progress=false
|
||||||
# Lint the code
|
# Lint the code
|
||||||
- run: yarn --cwd aio lint
|
- run: yarn --cwd aio lint
|
||||||
# Run PWA-score tests
|
|
||||||
# (Run before unit and e2e tests, which destroy the `dist/` directory.)
|
|
||||||
- run: yarn --cwd aio test-pwa-score-localhost $CI_AIO_MIN_PWA_SCORE
|
|
||||||
# Check the bundle sizes.
|
|
||||||
# (Run before unit and e2e tests, which destroy the `dist/` directory.)
|
|
||||||
- run: yarn --cwd aio payload-size
|
|
||||||
# Run unit tests
|
# Run unit tests
|
||||||
- run: yarn --cwd aio test --progress=false --watch=false
|
- run: yarn --cwd aio test --progress=false --watch=false
|
||||||
# Run e2e tests
|
# Run e2e tests
|
||||||
- run: yarn --cwd aio e2e --configuration=ci
|
- run: yarn --cwd aio e2e --configuration=ci
|
||||||
|
# Run PWA-score tests
|
||||||
|
- run: yarn --cwd aio test-pwa-score-localhost $CI_AIO_MIN_PWA_SCORE
|
||||||
|
# Check the bundle sizes.
|
||||||
|
- run: yarn --cwd aio payload-size
|
||||||
# Run unit tests for Firebase redirects
|
# Run unit tests for Firebase redirects
|
||||||
- run: yarn --cwd aio redirects-test
|
- run: yarn --cwd aio redirects-test
|
||||||
|
|
||||||
@ -240,7 +280,7 @@ jobs:
|
|||||||
- *attach_workspace
|
- *attach_workspace
|
||||||
- *init_environment
|
- *init_environment
|
||||||
# Deploy angular.io to production (if necessary)
|
# Deploy angular.io to production (if necessary)
|
||||||
- run: setPublicVar CI_STABLE_BRANCH "$(npm info @angular/core dist-tags.latest | sed -r 's/^\s*([0-9]+\.[0-9]+)\.[0-9]+.*$/\1.x/')"
|
- run: setPublicVar_CI_STABLE_BRANCH
|
||||||
- run: yarn --cwd aio deploy-production
|
- run: yarn --cwd aio deploy-production
|
||||||
|
|
||||||
test_aio_local:
|
test_aio_local:
|
||||||
@ -253,21 +293,33 @@ jobs:
|
|||||||
- *init_environment
|
- *init_environment
|
||||||
# Build aio (with local Angular packages)
|
# Build aio (with local Angular packages)
|
||||||
- run: yarn --cwd aio build-local --progress=false
|
- run: yarn --cwd aio build-local --progress=false
|
||||||
# Run PWA-score tests
|
|
||||||
# (Run before unit and e2e tests, which destroy the `dist/` directory.)
|
|
||||||
- run: yarn --cwd aio test-pwa-score-localhost $CI_AIO_MIN_PWA_SCORE
|
|
||||||
# Run unit tests
|
# Run unit tests
|
||||||
- run: yarn --cwd aio test --progress=false --watch=false
|
- run: yarn --cwd aio test --progress=false --watch=false
|
||||||
# Run e2e tests
|
# Run e2e tests
|
||||||
- run: yarn --cwd aio e2e --configuration=ci
|
- run: yarn --cwd aio e2e --configuration=ci
|
||||||
|
# Run PWA-score tests
|
||||||
|
- run: yarn --cwd aio test-pwa-score-localhost $CI_AIO_MIN_PWA_SCORE
|
||||||
|
# Check the bundle sizes.
|
||||||
|
- run: yarn --cwd aio payload-size aio-local
|
||||||
|
|
||||||
test_aio_local_ivy:
|
test_aio_local_ivy:
|
||||||
<<: *job_defaults
|
<<: *job_defaults
|
||||||
|
docker:
|
||||||
|
# Needed because the AIO tests and the PWA score test depend on Chrome being available.
|
||||||
|
- image: *browsers_docker_image
|
||||||
steps:
|
steps:
|
||||||
- *attach_workspace
|
- *attach_workspace
|
||||||
- *init_environment
|
- *init_environment
|
||||||
# Build aio with Ivy (using local Angular packages)
|
# Build aio with Ivy (using local Angular packages)
|
||||||
- run: yarn --cwd aio build-with-ivy --progress=false
|
- run: yarn --cwd aio build-with-ivy --progress=false
|
||||||
|
# Run unit tests
|
||||||
|
- run: yarn --cwd aio test --progress=false --watch=false
|
||||||
|
# Run e2e tests
|
||||||
|
- run: yarn --cwd aio e2e --configuration=ci
|
||||||
|
# Run PWA-score tests
|
||||||
|
- run: yarn --cwd aio test-pwa-score-localhost $CI_AIO_MIN_PWA_SCORE
|
||||||
|
# Check the bundle sizes.
|
||||||
|
- run: yarn --cwd aio payload-size aio-local-ivy
|
||||||
|
|
||||||
test_aio_tools:
|
test_aio_tools:
|
||||||
<<: *job_defaults
|
<<: *job_defaults
|
||||||
@ -370,6 +422,8 @@ jobs:
|
|||||||
- *attach_workspace
|
- *attach_workspace
|
||||||
- *init_environment
|
- *init_environment
|
||||||
- *setup_circleci_bazel_config
|
- *setup_circleci_bazel_config
|
||||||
|
# Enable remote/sibling docker which is needed by auto-selection of toolchain configs for RBE.
|
||||||
|
- setup_remote_docker
|
||||||
- *setup_bazel_remote_execution
|
- *setup_bazel_remote_execution
|
||||||
|
|
||||||
- run: scripts/build-packages-dist.sh
|
- run: scripts/build-packages-dist.sh
|
||||||
@ -396,6 +450,8 @@ jobs:
|
|||||||
- *attach_workspace
|
- *attach_workspace
|
||||||
- *init_environment
|
- *init_environment
|
||||||
- *setup_circleci_bazel_config
|
- *setup_circleci_bazel_config
|
||||||
|
# Enable remote/sibling docker which is needed by auto-selection of toolchain configs for RBE.
|
||||||
|
- setup_remote_docker
|
||||||
- *setup_bazel_remote_execution
|
- *setup_bazel_remote_execution
|
||||||
|
|
||||||
- run: scripts/build-ivy-npm-packages.sh
|
- run: scripts/build-ivy-npm-packages.sh
|
||||||
@ -454,10 +510,38 @@ jobs:
|
|||||||
- run: git config --global --unset "url.ssh://git@github.com.insteadof"
|
- run: git config --global --unset "url.ssh://git@github.com.insteadof"
|
||||||
- run:
|
- run:
|
||||||
name: Decrypt github credentials
|
name: Decrypt github credentials
|
||||||
command: 'openssl aes-256-cbc -d -in .circleci/github_token -k "${KEY}" -out ~/.git_credentials'
|
# We need ensure that the same default digest is used for encoding and decoding with
|
||||||
|
# openssl. Openssl versions might have different default digests which can cause
|
||||||
|
# decryption failures based on the installed openssl version. https://stackoverflow.com/a/39641378/4317734
|
||||||
|
command: 'openssl aes-256-cbc -d -in .circleci/github_token -md md5 -k "${KEY}" -out ~/.git_credentials'
|
||||||
- run: ./scripts/ci/publish-build-artifacts.sh
|
- run: ./scripts/ci/publish-build-artifacts.sh
|
||||||
|
|
||||||
aio_monitoring:
|
aio_monitoring_stable:
|
||||||
|
<<: *job_defaults
|
||||||
|
docker:
|
||||||
|
# This job needs Chrome to be globally installed because the tests run with Protractor
|
||||||
|
# which does not load the browser through the Bazel webtesting rules.
|
||||||
|
- image: *browsers_docker_image
|
||||||
|
steps:
|
||||||
|
- *attach_workspace
|
||||||
|
- *init_environment
|
||||||
|
- run: setPublicVar_CI_STABLE_BRANCH
|
||||||
|
- run:
|
||||||
|
name: Check out `aio/` from the stable branch
|
||||||
|
command: |
|
||||||
|
git fetch origin $CI_STABLE_BRANCH
|
||||||
|
git checkout --force origin/$CI_STABLE_BRANCH -- aio/
|
||||||
|
- run:
|
||||||
|
name: Run tests against https://angular.io/
|
||||||
|
command: ./aio/scripts/test-production.sh https://angular.io/ $CI_AIO_MIN_PWA_SCORE
|
||||||
|
- run:
|
||||||
|
name: Notify caretaker about failure
|
||||||
|
# `$SLACK_CARETAKER_WEBHOOK_URL` is a secret env var defined in CircleCI project settings.
|
||||||
|
# The URL comes from https://angular-team.slack.com/apps/A0F7VRE7N-circleci.
|
||||||
|
command: 'curl --request POST --header "Content-Type: application/json" --data "{\"text\":\":x: \`$CIRCLE_JOB\` job failed on build $CIRCLE_BUILD_NUM: $CIRCLE_BUILD_URL :scream:\"}" $SLACK_CARETAKER_WEBHOOK_URL'
|
||||||
|
when: on_fail
|
||||||
|
|
||||||
|
aio_monitoring_next:
|
||||||
<<: *job_defaults
|
<<: *job_defaults
|
||||||
docker:
|
docker:
|
||||||
# This job needs Chrome to be globally installed because the tests run with Protractor
|
# This job needs Chrome to be globally installed because the tests run with Protractor
|
||||||
@ -467,8 +551,8 @@ jobs:
|
|||||||
- *attach_workspace
|
- *attach_workspace
|
||||||
- *init_environment
|
- *init_environment
|
||||||
- run:
|
- run:
|
||||||
name: Run tests against the deployed apps
|
name: Run tests against https://next.angular.io/
|
||||||
command: ./aio/scripts/test-production.sh $CI_AIO_MIN_PWA_SCORE
|
command: ./aio/scripts/test-production.sh https://next.angular.io/ $CI_AIO_MIN_PWA_SCORE
|
||||||
- run:
|
- run:
|
||||||
name: Notify caretaker about failure
|
name: Notify caretaker about failure
|
||||||
# `$SLACK_CARETAKER_WEBHOOK_URL` is a secret env var defined in CircleCI project settings.
|
# `$SLACK_CARETAKER_WEBHOOK_URL` is a secret env var defined in CircleCI project settings.
|
||||||
@ -512,6 +596,62 @@ jobs:
|
|||||||
# the ESM5/ES2015 output. See: https://github.com/angular/angular/issues/27966
|
# the ESM5/ES2015 output. See: https://github.com/angular/angular/issues/27966
|
||||||
# - run: yarn gulp source-map-test
|
# - run: yarn gulp source-map-test
|
||||||
|
|
||||||
|
# Job to run unit tests from angular/material2. Needs a browser since all
|
||||||
|
# component unit tests assume they're running in the browser environment.
|
||||||
|
material-unit-tests:
|
||||||
|
<<: *job_defaults
|
||||||
|
resource_class: xlarge
|
||||||
|
docker:
|
||||||
|
- image: *browsers_docker_image
|
||||||
|
# The Material unit tests support splitting the browsers across multiple CircleCI
|
||||||
|
# instances. Since by default this job launches two browsers, we run each browser
|
||||||
|
# in its own container instance.
|
||||||
|
# https://github.com/angular/material2/blob/7baeaa797b19da2d2998f0d26f6fede3c8a13714/test/karma.conf.js#L107-L110
|
||||||
|
parallelism: 2
|
||||||
|
environment:
|
||||||
|
# The Material unit tests also support launching the same browser multiple times by
|
||||||
|
# sharding individual specs across the defined multiple instances.
|
||||||
|
# See: https://github.com/angular/material2/blob/7baeaa797b19da2d2998f0d26f6fede3c8a13714/test/karma.conf.js#L113-L116
|
||||||
|
KARMA_PARALLEL_BROWSERS: 3
|
||||||
|
steps:
|
||||||
|
- *attach_workspace
|
||||||
|
- *init_environment
|
||||||
|
- run:
|
||||||
|
name: "Cloning Material repository"
|
||||||
|
command: ./scripts/ci/clone_angular_material_repo.sh
|
||||||
|
- restore_cache:
|
||||||
|
# Material directory must be kept in sync with the `$MATERIAL_REPO_TMP_DIR` env variable.
|
||||||
|
# It needs to be hardcoded here, because env variables interpolation is not supported.
|
||||||
|
keys:
|
||||||
|
- v2-angular-material-{{ checksum "/tmp/material2/yarn.lock" }}
|
||||||
|
- v2-angular-material-
|
||||||
|
- run:
|
||||||
|
name: Installing Material dependencies.
|
||||||
|
command: yarn --cwd ${MATERIAL_REPO_TMP_DIR} install --frozen-lockfile --non-interactive
|
||||||
|
# Save the cache before we run the Material unit tests script. This is necessary
|
||||||
|
# because we don't want to cache the node modules which have been modified to contain
|
||||||
|
# the attached Ivy package output.
|
||||||
|
- save_cache:
|
||||||
|
# Material directory must be kept in sync with the `$MATERIAL_REPO_TMP_DIR` env variable.
|
||||||
|
# It needs to be hardcoded here, because env variables interpolation is not supported.
|
||||||
|
key: v2-angular-material-{{ checksum "/tmp/material2/yarn.lock" }}
|
||||||
|
paths:
|
||||||
|
- "/tmp/material2/node_modules"
|
||||||
|
- run:
|
||||||
|
name: "Running Material unit tests"
|
||||||
|
command: ./scripts/ci/run_angular_material_unit_tests.sh
|
||||||
|
|
||||||
|
test_zonejs:
|
||||||
|
<<: *job_defaults
|
||||||
|
steps:
|
||||||
|
- *attach_workspace
|
||||||
|
- *init_environment
|
||||||
|
# Install
|
||||||
|
- run: yarn --cwd packages/zone.js install --frozen-lockfile --non-interactive
|
||||||
|
# Run zone.js tools tests
|
||||||
|
- run: yarn --cwd packages/zone.js promisetest
|
||||||
|
- run: yarn --cwd packages/zone.js promisefinallytest
|
||||||
|
|
||||||
workflows:
|
workflows:
|
||||||
version: 2
|
version: 2
|
||||||
default_workflow:
|
default_workflow:
|
||||||
@ -529,6 +669,9 @@ workflows:
|
|||||||
- build-npm-packages:
|
- build-npm-packages:
|
||||||
requires:
|
requires:
|
||||||
- setup
|
- setup
|
||||||
|
- build-ivy-npm-packages:
|
||||||
|
requires:
|
||||||
|
- setup
|
||||||
- test_aio:
|
- test_aio:
|
||||||
requires:
|
requires:
|
||||||
- setup
|
- setup
|
||||||
@ -544,18 +687,18 @@ workflows:
|
|||||||
- test_aio_local:
|
- test_aio_local:
|
||||||
requires:
|
requires:
|
||||||
- build-npm-packages
|
- build-npm-packages
|
||||||
# - test_aio_local_ivy:
|
- test_aio_local_ivy:
|
||||||
# requires:
|
requires:
|
||||||
# - build-npm-packages
|
- build-npm-packages
|
||||||
- test_aio_tools:
|
- test_aio_tools:
|
||||||
requires:
|
requires:
|
||||||
- build-npm-packages
|
- build-npm-packages
|
||||||
- test_docs_examples:
|
- test_docs_examples:
|
||||||
requires:
|
requires:
|
||||||
- build-npm-packages
|
- build-npm-packages
|
||||||
# - test_docs_examples_ivy:
|
- test_docs_examples_ivy:
|
||||||
# requires:
|
requires:
|
||||||
# - build-ivy-npm-packages
|
- build-ivy-npm-packages
|
||||||
- aio_preview:
|
- aio_preview:
|
||||||
requires:
|
requires:
|
||||||
- setup
|
- setup
|
||||||
@ -581,22 +724,51 @@ workflows:
|
|||||||
- integration_test
|
- integration_test
|
||||||
# Only publish if `aio`/`docs` tests using the locally built Angular packages pass
|
# Only publish if `aio`/`docs` tests using the locally built Angular packages pass
|
||||||
- test_aio_local
|
- test_aio_local
|
||||||
# - test_aio_local_ivy
|
- test_aio_local_ivy
|
||||||
- test_docs_examples
|
- test_docs_examples
|
||||||
# - test_docs_examples_ivy
|
- test_docs_examples_ivy
|
||||||
# Get the artifacts to publish from the build-packages-dist job
|
# Get the artifacts to publish from the build-packages-dist job
|
||||||
# since the publishing script expects the legacy outputs layout.
|
# since the publishing script expects the legacy outputs layout.
|
||||||
- build-npm-packages
|
- build-npm-packages
|
||||||
|
- build-ivy-npm-packages
|
||||||
- legacy-unit-tests-saucelabs
|
- legacy-unit-tests-saucelabs
|
||||||
- legacy-misc-tests
|
- legacy-misc-tests
|
||||||
|
- material-unit-tests:
|
||||||
|
requires:
|
||||||
|
- build-ivy-npm-packages
|
||||||
|
- test_zonejs:
|
||||||
|
requires:
|
||||||
|
- setup
|
||||||
|
|
||||||
|
saucelabs_tests:
|
||||||
|
jobs:
|
||||||
|
- setup
|
||||||
|
- test_saucelabs_bazel:
|
||||||
|
requires:
|
||||||
|
- setup
|
||||||
|
triggers:
|
||||||
|
- schedule:
|
||||||
|
# Runs the Saucelabs legacy tests every hour. We still want to run Saucelabs
|
||||||
|
# frequently as the caretaker needs up-to-date results when merging PRs or creating
|
||||||
|
# a new release. Also we primarily moved the Saucelabs job into a cronjob that doesn't
|
||||||
|
# run for PRs, in order to ensure that PRs are not affected by Saucelabs flakiness or
|
||||||
|
# incidents. This is still guaranteed (even if we run the job every hour).
|
||||||
|
cron: "0 * * * *"
|
||||||
|
filters: *publish_branches_filter
|
||||||
|
|
||||||
aio_monitoring:
|
aio_monitoring:
|
||||||
jobs:
|
jobs:
|
||||||
- aio_monitoring
|
- setup
|
||||||
|
- aio_monitoring_stable:
|
||||||
|
requires:
|
||||||
|
- setup
|
||||||
|
- aio_monitoring_next:
|
||||||
|
requires:
|
||||||
|
- setup
|
||||||
triggers:
|
triggers:
|
||||||
- schedule:
|
- schedule:
|
||||||
# Runs AIO monitoring job at 00:00AM every day.
|
# Runs AIO monitoring jobs at 10:00AM every day.
|
||||||
cron: "0 0 * * *"
|
cron: "0 10 * * *"
|
||||||
filters:
|
filters:
|
||||||
branches:
|
branches:
|
||||||
only:
|
only:
|
||||||
|
@ -36,3 +36,38 @@ function setSecretVar() {
|
|||||||
# Restore original shell options.
|
# Restore original shell options.
|
||||||
eval "$originalShellOptions";
|
eval "$originalShellOptions";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
# Create a function to set an environment variable, when called.
|
||||||
|
#
|
||||||
|
# Use this function for creating setter for public environment variables that require expensive or
|
||||||
|
# time-consuming computaions and may not be needed. When needed, you can call this function to set
|
||||||
|
# the environment variable (which will be available through `$BASH_ENV` from that point onwards).
|
||||||
|
#
|
||||||
|
# Arguments:
|
||||||
|
# - `<name>`: The name of the environment variable. The generated setter function will be
|
||||||
|
# `setPublicVar_<name>`.
|
||||||
|
# - `<code>`: The code to run to compute the value for the variable. Since this code should be
|
||||||
|
# executed lazily, it must be properly escaped. For example:
|
||||||
|
# ```sh
|
||||||
|
# # DO NOT do this:
|
||||||
|
# createPublicVarSetter MY_VAR "$(whoami)"; # `whoami` will be evaluated eagerly
|
||||||
|
#
|
||||||
|
# # DO this isntead:
|
||||||
|
# createPublicVarSetter MY_VAR "\$(whoami)"; # `whoami` will NOT be evaluated eagerly
|
||||||
|
# ```
|
||||||
|
#
|
||||||
|
# Usage: `createPublicVarSetter <name> <code>`
|
||||||
|
#
|
||||||
|
# Example:
|
||||||
|
# ```sh
|
||||||
|
# createPublicVarSetter MY_VAR 'echo "FOO"';
|
||||||
|
# echo $MY_VAR; # Not defined
|
||||||
|
#
|
||||||
|
# setPublicVar_MY_VAR;
|
||||||
|
# source $BASH_ENV;
|
||||||
|
# echo $MY_VAR; # FOO
|
||||||
|
# ```
|
||||||
|
function createPublicVarSetter() {
|
||||||
|
echo "setPublicVar_$1() { setPublicVar $1 \"$2\"; }" >> $BASH_ENV;
|
||||||
|
}
|
||||||
|
@ -23,7 +23,7 @@ setPublicVar CI_BRANCH "$CIRCLE_BRANCH";
|
|||||||
# `.circleci/config.yml`. See http://chromedriver.chromium.org/downloads for a list of versions.
|
# `.circleci/config.yml`. See http://chromedriver.chromium.org/downloads for a list of versions.
|
||||||
# This variable is intended to be passed as an arg to the `webdriver-manager update` command (e.g.
|
# This variable is intended to be passed as an arg to the `webdriver-manager update` command (e.g.
|
||||||
# `"postinstall": "webdriver-manager update $CI_CHROMEDRIVER_VERSION_ARG"`).
|
# `"postinstall": "webdriver-manager update $CI_CHROMEDRIVER_VERSION_ARG"`).
|
||||||
setPublicVar CI_CHROMEDRIVER_VERSION_ARG "--versions.chrome 2.45";
|
setPublicVar CI_CHROMEDRIVER_VERSION_ARG "--versions.chrome 75.0.3770.90";
|
||||||
setPublicVar CI_COMMIT "$CIRCLE_SHA1";
|
setPublicVar CI_COMMIT "$CIRCLE_SHA1";
|
||||||
# `CI_COMMIT_RANGE` will only be available when `CIRCLE_COMPARE_URL` is also available (or can be
|
# `CI_COMMIT_RANGE` will only be available when `CIRCLE_COMPARE_URL` is also available (or can be
|
||||||
# retrieved via `get-compare-url.js`), i.e. on push builds (a.k.a. non-PR, non-scheduled builds and
|
# retrieved via `get-compare-url.js`), i.e. on push builds (a.k.a. non-PR, non-scheduled builds and
|
||||||
@ -34,6 +34,13 @@ setPublicVar CI_REPO_NAME "$CIRCLE_PROJECT_REPONAME";
|
|||||||
setPublicVar CI_REPO_OWNER "$CIRCLE_PROJECT_USERNAME";
|
setPublicVar CI_REPO_OWNER "$CIRCLE_PROJECT_USERNAME";
|
||||||
|
|
||||||
|
|
||||||
|
####################################################################################################
|
||||||
|
# Define "lazy" PUBLIC environment variables for CircleCI.
|
||||||
|
# (I.e. functions to set an environment variable when called.)
|
||||||
|
####################################################################################################
|
||||||
|
createPublicVarSetter CI_STABLE_BRANCH "\$(npm info @angular/core dist-tags.latest | sed -r 's/^\\s*([0-9]+\\.[0-9]+)\\.[0-9]+.*$/\\1.x/')";
|
||||||
|
|
||||||
|
|
||||||
####################################################################################################
|
####################################################################################################
|
||||||
# Define SECRET environment variables for CircleCI.
|
# Define SECRET environment variables for CircleCI.
|
||||||
####################################################################################################
|
####################################################################################################
|
||||||
@ -62,6 +69,15 @@ setPublicVar SAUCE_TUNNEL_IDENTIFIER "angular-${CIRCLE_BUILD_NUM}-${CIRCLE_NODE_
|
|||||||
# acquire CircleCI instances for too long if sauceconnect failed, we need a connect timeout.
|
# acquire CircleCI instances for too long if sauceconnect failed, we need a connect timeout.
|
||||||
setPublicVar SAUCE_READY_FILE_TIMEOUT 120
|
setPublicVar SAUCE_READY_FILE_TIMEOUT 120
|
||||||
|
|
||||||
|
####################################################################################################
|
||||||
|
# Define environment variables for the Angular Material unit tests job.
|
||||||
|
####################################################################################################
|
||||||
|
# We specifically use a directory within "/tmp" here because we want the cloned repo to be
|
||||||
|
# completely isolated from angular/angular in order to avoid any bad interactions between
|
||||||
|
# their separate build setups.
|
||||||
|
setPublicVar MATERIAL_REPO_TMP_DIR "/tmp/material2"
|
||||||
|
setPublicVar MATERIAL_REPO_URL "https://github.com/angular/material2.git"
|
||||||
|
setPublicVar MATERIAL_REPO_BRANCH "ivy-2019"
|
||||||
|
|
||||||
# Source `$BASH_ENV` to make the variables available immediately.
|
# Source `$BASH_ENV` to make the variables available immediately.
|
||||||
source $BASH_ENV;
|
source $BASH_ENV;
|
||||||
|
@ -6,9 +6,9 @@
|
|||||||
* node get-commit-range <build-number> [<compare-url> [<circle-token>]]
|
* node get-commit-range <build-number> [<compare-url> [<circle-token>]]
|
||||||
* ```
|
* ```
|
||||||
*
|
*
|
||||||
* Returns the value of the `CIRCLE_COMPARE_URL` environment variable (if defined) or, if this is
|
* Returns the commit range, either extracting it from `compare-url` (if defined), which is of the
|
||||||
* not a PR build (i.e. `CIRCLE_PR_NUMBER` is not defined), retrieves the equivalent of
|
* format of the `CIRCLE_COMPARE_URL` environment variable, or by retrieving the equivalent of
|
||||||
* `CIRCLE_COMPARE_URL` for jobs that are part of a rerun workflow.
|
* `CIRCLE_COMPARE_URL` for jobs that are part of a rerun workflow and extracting it from there.
|
||||||
*
|
*
|
||||||
* **Context:**
|
* **Context:**
|
||||||
* CircleCI sets the `CIRCLE_COMPARE_URL` environment variable (from which we can extract the commit
|
* CircleCI sets the `CIRCLE_COMPARE_URL` environment variable (from which we can extract the commit
|
||||||
|
120
.codefresh/Dockerfile.win-1809
Normal file
120
.codefresh/Dockerfile.win-1809
Normal file
@ -0,0 +1,120 @@
|
|||||||
|
# escape=`
|
||||||
|
|
||||||
|
ARG core=mcr.microsoft.com/windows/servercore:1809
|
||||||
|
ARG target=mcr.microsoft.com/powershell:windowsservercore-1809
|
||||||
|
|
||||||
|
FROM $core as download
|
||||||
|
|
||||||
|
ARG node_version=10.13.0
|
||||||
|
ARG yarn_version=1.13.0
|
||||||
|
|
||||||
|
SHELL ["powershell", "-Command", "$ErrorActionPreference = 'Stop'; $ProgressPreference = 'SilentlyContinue';"]
|
||||||
|
|
||||||
|
ENV GPG_VERSION 2.3.4
|
||||||
|
|
||||||
|
RUN Invoke-WebRequest $('https://files.gpg4win.org/gpg4win-vanilla-{0}.exe' -f $env:GPG_VERSION) -OutFile 'gpg4win.exe' -UseBasicParsing ; `
|
||||||
|
Start-Process .\gpg4win.exe -ArgumentList '/S' -NoNewWindow -Wait
|
||||||
|
|
||||||
|
RUN @( `
|
||||||
|
'94AE36675C464D64BAFA68DD7434390BDBE9B9C5', `
|
||||||
|
'FD3A5288F042B6850C66B31F09FE44734EB7990E', `
|
||||||
|
'71DCFD284A79C3B38668286BC97EC7A07EDE3FC1', `
|
||||||
|
'DD8F2338BAE7501E3DD5AC78C273792F7D83545D', `
|
||||||
|
'C4F0DFFF4E8C1A8236409D08E73BC641CC11F4C8', `
|
||||||
|
'B9AE9905FFD7803F25714661B63B535A4C206CA9', `
|
||||||
|
'77984A986EBC2AA786BC0F66B01FBB92821C587A', `
|
||||||
|
'8FCCA13FEF1D0C2E91008E09770F7A9A5AE15600', `
|
||||||
|
'4ED778F539E3634C779C87C6D7062848A1AB005C', `
|
||||||
|
'A48C2BEE680E841632CD4E44F07496B3EB3C1762', `
|
||||||
|
'B9E2F5981AA6E0CD28160D9FF13993A75599653C' `
|
||||||
|
) | foreach { `
|
||||||
|
gpg --keyserver ha.pool.sks-keyservers.net --recv-keys $_ ; `
|
||||||
|
}
|
||||||
|
|
||||||
|
ENV NODE_VERSION=$node_version
|
||||||
|
|
||||||
|
RUN Invoke-WebRequest $('https://nodejs.org/dist/v{0}/SHASUMS256.txt.asc' -f $env:NODE_VERSION) -OutFile 'SHASUMS256.txt.asc' -UseBasicParsing ; `
|
||||||
|
gpg --batch --decrypt --output SHASUMS256.txt SHASUMS256.txt.asc
|
||||||
|
|
||||||
|
RUN Invoke-WebRequest $('https://nodejs.org/dist/v{0}/node-v{0}-win-x64.zip' -f $env:NODE_VERSION) -OutFile 'node.zip' -UseBasicParsing ; `
|
||||||
|
$sum = $(cat SHASUMS256.txt.asc | sls $(' node-v{0}-win-x64.zip' -f $env:NODE_VERSION)) -Split ' ' ; `
|
||||||
|
if ((Get-FileHash node.zip -Algorithm sha256).Hash -ne $sum[0]) { Write-Error 'SHA256 mismatch' } ; `
|
||||||
|
Expand-Archive node.zip -DestinationPath C:\ ; `
|
||||||
|
Rename-Item -Path $('C:\node-v{0}-win-x64' -f $env:NODE_VERSION) -NewName 'C:\nodejs'
|
||||||
|
|
||||||
|
ENV YARN_VERSION=$yarn_version
|
||||||
|
|
||||||
|
RUN [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12 ; `
|
||||||
|
Invoke-WebRequest $('https://yarnpkg.com/downloads/{0}/yarn-{0}.msi' -f $env:YARN_VERSION) -OutFile yarn.msi -UseBasicParsing ; `
|
||||||
|
$sig = Get-AuthenticodeSignature yarn.msi ; `
|
||||||
|
if ($sig.Status -ne 'Valid') { Write-Error 'Authenticode signature is not valid' } ; `
|
||||||
|
Write-Output $sig.SignerCertificate.Thumbprint ; `
|
||||||
|
if (@( `
|
||||||
|
'7E253367F8A102A91D04829E37F3410F14B68A5F', `
|
||||||
|
'AF764E1EA56C762617BDC757C8B0F3780A0CF5F9' `
|
||||||
|
) -notcontains $sig.SignerCertificate.Thumbprint) { Write-Error 'Unknown signer certificate' } ; `
|
||||||
|
Start-Process msiexec.exe -ArgumentList '/i', 'yarn.msi', '/quiet', '/norestart' -NoNewWindow -Wait
|
||||||
|
|
||||||
|
ENV GIT_VERSION 2.20.1
|
||||||
|
ENV GIT_DOWNLOAD_URL https://github.com/git-for-windows/git/releases/download/v${GIT_VERSION}.windows.1/MinGit-${GIT_VERSION}-busybox-64-bit.zip
|
||||||
|
ENV GIT_SHA256 9817ab455d9cbd0b09d8664b4afbe4bbf78d18b556b3541d09238501a749486c
|
||||||
|
|
||||||
|
RUN [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12 ; `
|
||||||
|
Invoke-WebRequest -UseBasicParsing $env:GIT_DOWNLOAD_URL -OutFile git.zip; `
|
||||||
|
if ((Get-FileHash git.zip -Algorithm sha256).Hash -ne $env:GIT_SHA256) {exit 1} ; `
|
||||||
|
Expand-Archive git.zip -DestinationPath C:\git; `
|
||||||
|
Remove-Item git.zip
|
||||||
|
|
||||||
|
FROM $target as baseimage
|
||||||
|
|
||||||
|
ENV NPM_CONFIG_LOGLEVEL info
|
||||||
|
|
||||||
|
COPY --from=download /nodejs /nodejs
|
||||||
|
COPY --from=download [ "/Program Files (x86)/yarn", "/yarn" ]
|
||||||
|
COPY --from=download /git /git
|
||||||
|
|
||||||
|
ARG SETX=/M
|
||||||
|
RUN setx %SETX% PATH "%PATH%;C:\nodejs;C:\yarn\bin;C:\git\cmd;C:\git\mingw64\bin;C:\git\usr\bin"
|
||||||
|
|
||||||
|
CMD [ "node.exe" ]
|
||||||
|
|
||||||
|
FROM baseimage
|
||||||
|
|
||||||
|
SHELL ["powershell", "-Command", "$ErrorActionPreference = 'Stop'; $ProgressPreference = 'SilentlyContinue';"]
|
||||||
|
|
||||||
|
RUN Invoke-WebRequest -UseBasicParsing 'https://www.7-zip.org/a/7z1805-x64.exe' -OutFile 7z.exe; `
|
||||||
|
Start-Process -FilePath 'C:\\7z.exe' -ArgumentList '/S', '/D=C:\\7zip0' -NoNewWindow -Wait; `
|
||||||
|
Invoke-WebRequest -UseBasicParsing 'http://repo.msys2.org/distrib/x86_64/msys2-base-x86_64-20180531.tar.xz' -OutFile msys2.tar.xz; `
|
||||||
|
Start-Process -FilePath 'C:\\7zip\\7z' -ArgumentList 'e', 'msys2.tar.xz' -Wait; `
|
||||||
|
Start-Process -FilePath 'C:\\7zip\\7z' -ArgumentList 'x', 'msys2.tar', '-oC:\\' -Wait; `
|
||||||
|
Remove-Item msys2.tar.xz; `
|
||||||
|
Remove-Item msys2.tar; `
|
||||||
|
Remove-Item 7z.exe; `
|
||||||
|
Remove-Item -Recurse 7zip; `
|
||||||
|
[Environment]::SetEnvironmentVariable('Path', $env:Path + ';C:\msys64\usr\bin', [System.EnvironmentVariableTarget]::Machine); `
|
||||||
|
[Environment]::SetEnvironmentVariable('BAZEL_SH', 'C:\msys64\usr\bin\bash.exe', [System.EnvironmentVariableTarget]::Machine)
|
||||||
|
|
||||||
|
# Install VS Build Tools
|
||||||
|
RUN Invoke-WebRequest -UseBasicParsing https://download.visualstudio.microsoft.com/download/pr/df649173-11e9-4af2-8eb7-0eb02ba8958a/cadb5bdac41e55bb8f6a6b7c45273370/vs_buildtools.exe -OutFile vs_BuildTools.exe; `
|
||||||
|
# Installer won't detect DOTNET_SKIP_FIRST_TIME_EXPERIENCE if ENV is used, must use setx /M
|
||||||
|
setx /M DOTNET_SKIP_FIRST_TIME_EXPERIENCE 1; `
|
||||||
|
Start-Process vs_BuildTools.exe `
|
||||||
|
-ArgumentList `
|
||||||
|
'--add', 'Microsoft.VisualStudio.Workload.VCTools', `
|
||||||
|
'--add', 'Microsoft.VisualStudio.Component.VC.Tools.x86.x64', `
|
||||||
|
'--add', 'Microsoft.Component.VC.Runtime.UCRTSDK', `
|
||||||
|
'--add', 'Microsoft.VisualStudio.Component.Windows10SDK.17763', `
|
||||||
|
'--quiet', '--norestart', '--nocache' `
|
||||||
|
-NoNewWindow -Wait; `
|
||||||
|
Remove-Item -Force vs_buildtools.exe; `
|
||||||
|
Remove-Item -Force -Recurse \"${Env:ProgramFiles(x86)}\Microsoft Visual Studio\Installer\"; `
|
||||||
|
Remove-Item -Force -Recurse ${Env:TEMP}\*; `
|
||||||
|
Remove-Item -Force -Recurse \"${Env:ProgramData}\Package Cache\"; `
|
||||||
|
[Environment]::SetEnvironmentVariable('BAZEL_VC', \"${Env:ProgramFiles(x86)}\Microsoft Visual Studio\2019\BuildTools\VC\", [System.EnvironmentVariableTarget]::Machine)
|
||||||
|
|
||||||
|
# Install Python
|
||||||
|
RUN Invoke-WebRequest -UseBasicParsing https://www.python.org/ftp/python/3.5.1/python-3.5.1.exe -OutFile python-3.5.1.exe; `
|
||||||
|
Start-Process python-3.5.1.exe -ArgumentList '/quiet InstallAllUsers=1 PrependPath=1' -Wait; `
|
||||||
|
Remove-Item -Force python-3.5.1.exe
|
||||||
|
|
||||||
|
CMD ["cmd.exe"]
|
33
.codefresh/README.md
Normal file
33
.codefresh/README.md
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
# CodeFresh configuration
|
||||||
|
|
||||||
|
[](https://g.codefresh.io/public/accounts/angular/pipelines/angular/angular/angular)
|
||||||
|
|
||||||
|
This folder contains configuration for the [CodeFresh](<https://codefresh.io/>) based CI checks for this repository.
|
||||||
|
|
||||||
|
## The build pipeline
|
||||||
|
|
||||||
|
CodeFresh uses a several pipeline for each repository. The `codefresh.yml` file defines pipeline [build steps](https://codefresh.io/docs/docs/configure-ci-cd-pipeline/introduction-to-codefresh-pipelines/) for this repository.
|
||||||
|
|
||||||
|
Run results can be seen in the GitHub checks interface and in the [public pipeline](https://g.codefresh.io/public/accounts/angular/pipelines/angular/angular/angular)
|
||||||
|
|
||||||
|
Although most configuration is done via `pipeline.yml`, some options are only available in the online [pipeline settings](https://g.codefresh.io/pipelines/angular/services?repoOwner=angular&repoName=angular&project=angular%2Fangular&context=github&serviceName=angular%2Fangular), which needs a login to access.
|
||||||
|
|
||||||
|
|
||||||
|
## Caretaker
|
||||||
|
|
||||||
|
CodeFresh status can be found at <http://status.codefresh.io/>.
|
||||||
|
|
||||||
|
Issues related to the CodeFresh setup should be escalated to the Tools Team via the current caretaker, followed by Alex Eagle and Filipe Silva.
|
||||||
|
|
||||||
|
## Rollout strategy
|
||||||
|
|
||||||
|
Currently it is only used for tests on Windows platforms, on the master branch, and without pushing user-facing reports. It's only possible to see current builds in the [public pipeline dashboard](https://g.codefresh.io/public/accounts/angular/pipelines/angular/angular/angular).
|
||||||
|
|
||||||
|
After a week or two of running like this, we should reassess how stable and reliable it is.
|
||||||
|
|
||||||
|
Next steps include:
|
||||||
|
- building PRs
|
||||||
|
- showing build status publicly
|
||||||
|
- blocking PRs that break the build
|
||||||
|
- expanding the test suite
|
||||||
|
|
38
.codefresh/bazel.rc
Normal file
38
.codefresh/bazel.rc
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
# These options are enabled when running on CI
|
||||||
|
# We do this by copying this file to /etc/bazel.bazelrc at the start of the build.
|
||||||
|
# See documentation in /docs/BAZEL.md
|
||||||
|
|
||||||
|
# Save built files and downloaded repositories in a location that can be cached by CodeFresh and
|
||||||
|
# shared between builds. This helps speed up the analysis time significantly with Bazel managed node
|
||||||
|
# dependencies on the CI.
|
||||||
|
# https://codefresh.io/docs/docs/configure-ci-cd-pipeline/introduction-to-codefresh-pipelines/#caching-the-artifacts-of-your-build-system
|
||||||
|
build --repository_cache=C:/codefresh/volume/bazel_repository_cache
|
||||||
|
# Setting the output_base to a Docker volume is currently broken because of a Docker bug on Windows:
|
||||||
|
# https://github.com/moby/moby/issues/37024
|
||||||
|
# This affects Bazel because bazel_output_base\external\bazel_tools is an absolute path junction.
|
||||||
|
# When its fixed we can uncomment this line, and use a different output_base for Ivy tests (they
|
||||||
|
# use a separate compiler and destructively replace the cache).
|
||||||
|
# startup --output_base=C:/codefresh/volume/bazel_output_base
|
||||||
|
|
||||||
|
# Don't be spammy in the logs
|
||||||
|
# TODO(gmagolan): Hide progress again once build performance improves
|
||||||
|
# Presently, CircleCI can timeout during bazel test ... with the following
|
||||||
|
# error: Too long with no output (exceeded 10m0s)
|
||||||
|
build --noshow_progress
|
||||||
|
|
||||||
|
# Print all the options that apply to the build.
|
||||||
|
# This helps us diagnose which options override others
|
||||||
|
# (e.g. /etc/bazel.bazelrc vs. tools/bazel.rc)
|
||||||
|
build --announce_rc
|
||||||
|
|
||||||
|
# Workaround https://github.com/bazelbuild/bazel/issues/3645
|
||||||
|
# Bazel doesn't calculate the memory ceiling correctly when running under Docker.
|
||||||
|
# Limit Bazel to consuming resources that fit in CodeFresh VMs
|
||||||
|
# TODO(filipesilva): determine the correct memory limit
|
||||||
|
build --local_resources=10240,8.0,1.0
|
||||||
|
|
||||||
|
# Retry in the event of flakes, eg. https://circleci.com/gh/angular/angular/31309
|
||||||
|
test --flaky_test_attempts=2
|
||||||
|
|
||||||
|
# More details on failures
|
||||||
|
build --verbose_failures=true
|
28
.codefresh/codefresh.yml
Normal file
28
.codefresh/codefresh.yml
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
version: '1.0'
|
||||||
|
|
||||||
|
steps:
|
||||||
|
BuildImage:
|
||||||
|
title: Build Docker image
|
||||||
|
type: build
|
||||||
|
image_name: node-bazel-windows
|
||||||
|
working_directory: ./.codefresh
|
||||||
|
no_cf_cache: true
|
||||||
|
build_arguments:
|
||||||
|
- node_version=10.13.0
|
||||||
|
- yarn_version=1.13.0
|
||||||
|
dockerfile: ./Dockerfile.win-1809
|
||||||
|
|
||||||
|
RunTests:
|
||||||
|
title: Run Bazel tests
|
||||||
|
image: ${{BuildImage}}
|
||||||
|
commands:
|
||||||
|
# Install dependencies
|
||||||
|
- yarn install --frozen-lockfile --non-interactive --network-timeout 100000 --no-progress
|
||||||
|
# Add Bazel CI config
|
||||||
|
- copy .codefresh\bazel.rc %ProgramData%\bazel.bazelrc
|
||||||
|
# Run tests
|
||||||
|
# At the moment 'browser:chromium-local' are broken in CI while locally they work
|
||||||
|
# VE
|
||||||
|
- yarn bazel test --build_tag_filters=-ivy-only --test_tag_filters=-ivy-only,-browser:chromium-local //...
|
||||||
|
# Ivy
|
||||||
|
- yarn bazel test --define=compile=aot --build_tag_filters=-no-ivy-aot,-fixme-ivy-aot --test_tag_filters=-no-ivy-aot,-fixme-ivy-aot,-browser:chromium-local //...
|
22
.devcontainer/recommended-Dockerfile
Normal file
22
.devcontainer/recommended-Dockerfile
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
# Image metadata and config.
|
||||||
|
FROM circleci/node:10-browsers
|
||||||
|
|
||||||
|
LABEL name="Angular dev environment" \
|
||||||
|
description="This image can be used to create a dev environment for building Angular." \
|
||||||
|
vendor="angular" \
|
||||||
|
version="1.0"
|
||||||
|
|
||||||
|
EXPOSE 4000 4200 4433 5000 8080 9876
|
||||||
|
|
||||||
|
|
||||||
|
# Switch to `root` (CircleCI images use `circleci` as the user).
|
||||||
|
USER root
|
||||||
|
|
||||||
|
|
||||||
|
# Configure `Node.js`/`npm` and install utilities.
|
||||||
|
RUN npm config --global set user root
|
||||||
|
RUN npm install --global yarn@1.13.0 # This needs to be in sync with what we use on CI.
|
||||||
|
|
||||||
|
|
||||||
|
# Go! (And keep going.)
|
||||||
|
CMD ["tail", "--follow", "/dev/null"]
|
16
.devcontainer/recommended-devcontainer.json
Normal file
16
.devcontainer/recommended-devcontainer.json
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
// Reference: https://code.visualstudio.com/docs/remote/containers#_devcontainerjson-reference
|
||||||
|
{
|
||||||
|
"name": "Angular dev container",
|
||||||
|
"dockerFile": "Dockerfile",
|
||||||
|
"appPort": [4000, 4200, 4433, 5000, 8080, 9876],
|
||||||
|
"postCreateCommand": "yarn install",
|
||||||
|
"extensions": [
|
||||||
|
"devondcarew.bazel-code",
|
||||||
|
"gkalpak.aio-docs-utils",
|
||||||
|
"ms-vscode.vscode-typescript-tslint-plugin",
|
||||||
|
"xaver.clang-format",
|
||||||
|
// The following extensions are useful when working on angular.io (i.e. inside the `aio/` directory).
|
||||||
|
//"angular.ng-template",
|
||||||
|
//"dbaeumer.vscode-eslint",
|
||||||
|
],
|
||||||
|
}
|
3
.gitattributes
vendored
3
.gitattributes
vendored
@ -5,5 +5,8 @@
|
|||||||
*.js eol=lf
|
*.js eol=lf
|
||||||
*.ts eol=lf
|
*.ts eol=lf
|
||||||
|
|
||||||
|
# API guardian patch must always use LF for tests to work
|
||||||
|
*.patch eol=lf
|
||||||
|
|
||||||
# Must keep Windows line ending to be parsed correctly
|
# Must keep Windows line ending to be parsed correctly
|
||||||
scripts/windows/packages.txt eol=crlf
|
scripts/windows/packages.txt eol=crlf
|
||||||
|
75
.github/CODEOWNERS
vendored
75
.github/CODEOWNERS
vendored
@ -179,6 +179,7 @@
|
|||||||
# ===========================================================
|
# ===========================================================
|
||||||
#
|
#
|
||||||
# - kara
|
# - kara
|
||||||
|
# - jasonaden
|
||||||
|
|
||||||
|
|
||||||
# ===========================================================
|
# ===========================================================
|
||||||
@ -218,6 +219,7 @@
|
|||||||
#
|
#
|
||||||
# - gkalpak
|
# - gkalpak
|
||||||
# - petebacondarwin
|
# - petebacondarwin
|
||||||
|
# - jasonaden
|
||||||
|
|
||||||
|
|
||||||
# ===========================================================
|
# ===========================================================
|
||||||
@ -275,6 +277,7 @@
|
|||||||
# @angular/fw-docs-intro
|
# @angular/fw-docs-intro
|
||||||
# ===========================================================
|
# ===========================================================
|
||||||
#
|
#
|
||||||
|
# - jenniferfell
|
||||||
# - brandonroberts
|
# - brandonroberts
|
||||||
# - IgorMinar
|
# - IgorMinar
|
||||||
# - stephenfluin
|
# - stephenfluin
|
||||||
@ -307,6 +310,18 @@
|
|||||||
# - mgechev
|
# - mgechev
|
||||||
|
|
||||||
|
|
||||||
|
# ===========================================================
|
||||||
|
# @angular/tools-docs-schematics
|
||||||
|
# ===========================================================
|
||||||
|
#
|
||||||
|
# - alan-agius4
|
||||||
|
# - alexeagle
|
||||||
|
# - hansl
|
||||||
|
# - IgorMinar
|
||||||
|
# - mgechev
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# ===========================================================
|
# ===========================================================
|
||||||
# @angular/fw-docs-marketing
|
# @angular/fw-docs-marketing
|
||||||
# ===========================================================
|
# ===========================================================
|
||||||
@ -399,10 +414,10 @@
|
|||||||
|
|
||||||
|
|
||||||
# ================================================
|
# ================================================
|
||||||
# packages/compiler-cli/src/ngcc/
|
# packages/compiler-cli/ngcc/
|
||||||
# ================================================
|
# ================================================
|
||||||
|
|
||||||
/packages/compiler-cli/src/ngcc/** @angular/fw-ngcc @angular/framework-global-approvers
|
/packages/compiler-cli/ngcc/** @angular/fw-ngcc @angular/framework-global-approvers
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -414,6 +429,7 @@
|
|||||||
|
|
||||||
/packages/compiler-cli/src/ngtools/** @angular/tools-cli @angular/framework-global-approvers
|
/packages/compiler-cli/src/ngtools/** @angular/tools-cli @angular/framework-global-approvers
|
||||||
/aio/content/guide/ivy.md @angular/tools-cli @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes
|
/aio/content/guide/ivy.md @angular/tools-cli @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes
|
||||||
|
/aio/content/guide/web-worker.md @angular/tools-cli @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -518,6 +534,15 @@
|
|||||||
/aio/content/examples/interpolation/** @angular/fw-core @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes
|
/aio/content/examples/interpolation/** @angular/fw-core @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes
|
||||||
/aio/content/examples/template-syntax/** @angular/fw-core @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes
|
/aio/content/examples/template-syntax/** @angular/fw-core @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes
|
||||||
/aio/content/images/guide/template-syntax/** @angular/fw-core @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes
|
/aio/content/images/guide/template-syntax/** @angular/fw-core @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes
|
||||||
|
/aio/content/examples/binding-syntax/** @angular/fw-core @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes
|
||||||
|
/aio/content/examples/property-binding/** @angular/fw-core @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes
|
||||||
|
/aio/content/examples/attribute-binding/** @angular/fw-core @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes
|
||||||
|
/aio/content/examples/two-way-binding/** @angular/fw-core @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes
|
||||||
|
/aio/content/examples/built-in-directives/** @angular/fw-core @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes
|
||||||
|
/aio/content/examples/template-reference-variables/** @angular/fw-core @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes
|
||||||
|
/aio/content/examples/inputs-outputs/** @angular/fw-core @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes
|
||||||
|
/aio/content/examples/template-expression-operators/** @angular/fw-core @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes
|
||||||
|
|
||||||
|
|
||||||
/aio/content/guide/pipes.md @angular/fw-core @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes
|
/aio/content/guide/pipes.md @angular/fw-core @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes
|
||||||
/aio/content/examples/pipes/** @angular/fw-core @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes
|
/aio/content/examples/pipes/** @angular/fw-core @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes
|
||||||
@ -643,8 +668,10 @@
|
|||||||
# ================================================
|
# ================================================
|
||||||
|
|
||||||
/packages/upgrade/** @angular/fw-upgrade @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes
|
/packages/upgrade/** @angular/fw-upgrade @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes
|
||||||
|
/packages/common/upgrade/** @angular/fw-upgrade @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes
|
||||||
/packages/examples/upgrade/** @angular/fw-upgrade @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes
|
/packages/examples/upgrade/** @angular/fw-upgrade @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes
|
||||||
/aio/content/guide/upgrade.md @angular/fw-upgrade @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes
|
/aio/content/guide/upgrade.md @angular/fw-upgrade @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes
|
||||||
|
/aio/content/examples/upgrade-lazy-load-ajs/** @angular/fw-upgrade @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes
|
||||||
/aio/content/examples/upgrade-module/** @angular/fw-upgrade @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes
|
/aio/content/examples/upgrade-module/** @angular/fw-upgrade @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes
|
||||||
/aio/content/images/guide/upgrade/** @angular/fw-upgrade @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes
|
/aio/content/images/guide/upgrade/** @angular/fw-upgrade @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes
|
||||||
/aio/content/examples/upgrade-phonecat-1-typescript/** @angular/fw-upgrade @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes
|
/aio/content/examples/upgrade-phonecat-1-typescript/** @angular/fw-upgrade @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes
|
||||||
@ -725,6 +752,7 @@ testing/** @angular/fw-test
|
|||||||
|
|
||||||
/aio/* @angular/docs-infra @angular/framework-global-approvers
|
/aio/* @angular/docs-infra @angular/framework-global-approvers
|
||||||
/aio/aio-builds-setup/** @angular/docs-infra @angular/framework-global-approvers
|
/aio/aio-builds-setup/** @angular/docs-infra @angular/framework-global-approvers
|
||||||
|
/aio/content/examples/* @angular/docs-infra @angular/framework-global-approvers
|
||||||
/aio/scripts/** @angular/docs-infra @angular/framework-global-approvers
|
/aio/scripts/** @angular/docs-infra @angular/framework-global-approvers
|
||||||
/aio/src/** @angular/docs-infra @angular/framework-global-approvers
|
/aio/src/** @angular/docs-infra @angular/framework-global-approvers
|
||||||
/aio/tests/** @angular/docs-infra @angular/framework-global-approvers
|
/aio/tests/** @angular/docs-infra @angular/framework-global-approvers
|
||||||
@ -756,7 +784,10 @@ testing/** @angular/fw-test
|
|||||||
/aio/content/examples/toh-pt4/** @angular/fw-docs-intro @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes
|
/aio/content/examples/toh-pt4/** @angular/fw-docs-intro @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes
|
||||||
/aio/content/examples/toh-pt5/** @angular/fw-docs-intro @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes
|
/aio/content/examples/toh-pt5/** @angular/fw-docs-intro @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes
|
||||||
/aio/content/examples/toh-pt6/** @angular/fw-docs-intro @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes
|
/aio/content/examples/toh-pt6/** @angular/fw-docs-intro @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes
|
||||||
|
/aio/content/examples/getting-started-v0/** @angular/fw-docs-intro @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes
|
||||||
|
/aio/content/examples/getting-started/** @angular/fw-docs-intro @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes
|
||||||
|
/aio/content/getting-started/** @angular/fw-docs-intro @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes
|
||||||
|
/aio/content/images/guide/getting-started/** @angular/fw-docs-intro @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes
|
||||||
|
|
||||||
|
|
||||||
# ================================================
|
# ================================================
|
||||||
@ -791,6 +822,7 @@ testing/** @angular/fw-test
|
|||||||
/aio/content/guide/releases.md @angular/fw-docs-packaging @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes
|
/aio/content/guide/releases.md @angular/fw-docs-packaging @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes
|
||||||
/aio/content/guide/updating.md @angular/fw-docs-packaging @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes
|
/aio/content/guide/updating.md @angular/fw-docs-packaging @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes
|
||||||
/aio/content/guide/workspace-config.md @angular/fw-docs-packaging @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes
|
/aio/content/guide/workspace-config.md @angular/fw-docs-packaging @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes
|
||||||
|
/aio/content/guide/deprecations.md @angular/fw-docs-packaging @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -803,6 +835,17 @@ testing/** @angular/fw-test
|
|||||||
/aio/content/guide/using-libraries.md @angular/tools-docs-libraries @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes
|
/aio/content/guide/using-libraries.md @angular/tools-docs-libraries @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes
|
||||||
|
|
||||||
|
|
||||||
|
# ================================================
|
||||||
|
# Docs: schematics
|
||||||
|
# ================================================
|
||||||
|
|
||||||
|
/aio/content/guide/schematics.md @angular/tools-docs-schematics @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes
|
||||||
|
/aio/content/guide/schematics-authoring.md @angular/tools-docs-schematics @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes
|
||||||
|
/aio/content/guide/schematics-for-libraries.md @angular/tools-docs-schematics @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes
|
||||||
|
/aio/content/images/guide/schematics/** @angular/tools-docs-schematics @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes
|
||||||
|
/aio/content/examples/schematics-for-libraries/** @angular/tools-docs-schematics @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# ================================================
|
# ================================================
|
||||||
# Docs: marketing
|
# Docs: marketing
|
||||||
@ -824,17 +867,41 @@ testing/** @angular/fw-test
|
|||||||
/.buildkite/** @angular/fw-dev-infra
|
/.buildkite/** @angular/fw-dev-infra
|
||||||
/.circleci/** @angular/fw-dev-infra
|
/.circleci/** @angular/fw-dev-infra
|
||||||
/.codefresh/** @angular/fw-dev-infra
|
/.codefresh/** @angular/fw-dev-infra
|
||||||
|
/.devcontainer/** @angular/fw-dev-infra
|
||||||
/.github/** @angular/fw-dev-infra
|
/.github/** @angular/fw-dev-infra
|
||||||
/.vscode/** @angular/fw-dev-infra
|
/.vscode/** @angular/fw-dev-infra
|
||||||
/docs/BAZEL.md @angular/fw-dev-infra
|
/docs/BAZEL.md @angular/fw-dev-infra
|
||||||
/packages/* @angular/fw-dev-infra
|
/packages/* @angular/fw-dev-infra
|
||||||
/scripts/** @angular/fw-dev-infra
|
/scripts/** @angular/fw-dev-infra
|
||||||
/third_party/** @angular/fw-dev-infra
|
/third_party/** @angular/fw-dev-infra
|
||||||
/tools/** @angular/fw-dev-infra
|
/tools/build/** @angular/fw-dev-infra
|
||||||
|
/tools/cjs-jasmine/** @angular/fw-dev-infra
|
||||||
|
/tools/gulp-tasks/** @angular/fw-dev-infra
|
||||||
|
/tools/ngcontainer/** @angular/fw-dev-infra
|
||||||
|
/tools/npm/** @angular/fw-dev-infra
|
||||||
|
/tools/npm_workspace/** @angular/fw-dev-infra
|
||||||
|
/tools/public_api_guard/** @angular/fw-dev-infra
|
||||||
|
/tools/rxjs/** @angular/fw-dev-infra
|
||||||
|
/tools/source-map-test/** @angular/fw-dev-infra
|
||||||
|
/tools/symbol-extractor/** @angular/fw-dev-infra
|
||||||
|
/tools/testing/** @angular/fw-dev-infra
|
||||||
|
/tools/ts-api-guardian/** @angular/fw-dev-infra
|
||||||
|
/tools/tslint/** @angular/fw-dev-infra
|
||||||
|
/tools/validate-commit-message/** @angular/fw-dev-infra
|
||||||
|
/tools/yarn/** @angular/fw-dev-infra
|
||||||
|
/tools/*
|
||||||
*.bzl @angular/fw-dev-infra
|
*.bzl @angular/fw-dev-infra
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# ================================================
|
||||||
|
# Material CI
|
||||||
|
# ================================================
|
||||||
|
|
||||||
|
/tools/material-ci/** @angular/fw-core @angular/framework-global-approvers
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# ================================================
|
# ================================================
|
||||||
# Public API
|
# Public API
|
||||||
# ================================================
|
# ================================================
|
||||||
|
13
.github/angular-robot.yml
vendored
13
.github/angular-robot.yml
vendored
@ -35,17 +35,19 @@ merge:
|
|||||||
# this list must be manually kept in sync with google3/third_party/javascript/angular2/copy.bara.sky
|
# this list must be manually kept in sync with google3/third_party/javascript/angular2/copy.bara.sky
|
||||||
include:
|
include:
|
||||||
- "LICENSE"
|
- "LICENSE"
|
||||||
- "modules/**"
|
- "modules/benchmarks/**"
|
||||||
|
- "modules/system.d.ts"
|
||||||
- "packages/**"
|
- "packages/**"
|
||||||
# list of patterns to ignore for the files changed by the PR
|
# list of patterns to ignore for the files changed by the PR
|
||||||
exclude:
|
exclude:
|
||||||
- "packages/*"
|
- "packages/*"
|
||||||
- "packages/bazel/*"
|
- "packages/bazel/*"
|
||||||
|
- "packages/bazel/src/api-extractor/**"
|
||||||
- "packages/bazel/src/builders/**"
|
- "packages/bazel/src/builders/**"
|
||||||
- "packages/bazel/src/ng_package/**"
|
- "packages/bazel/src/ng_package/**"
|
||||||
- "packages/bazel/src/protractor/**"
|
- "packages/bazel/src/protractor/**"
|
||||||
- "packages/bazel/src/schematics/**"
|
- "packages/bazel/src/schematics/**"
|
||||||
- "packages/compiler-cli/src/ngcc/**"
|
- "packages/compiler-cli/ngcc/**"
|
||||||
- "packages/docs/**"
|
- "packages/docs/**"
|
||||||
- "packages/elements/schematics/**"
|
- "packages/elements/schematics/**"
|
||||||
- "packages/examples/**"
|
- "packages/examples/**"
|
||||||
@ -165,3 +167,10 @@ triagePR:
|
|||||||
- "effort*"
|
- "effort*"
|
||||||
- "risk*"
|
- "risk*"
|
||||||
- "comp: *"
|
- "comp: *"
|
||||||
|
|
||||||
|
# options for rerunning CI
|
||||||
|
rerunCircleCI:
|
||||||
|
# set to true to disable
|
||||||
|
disabled: false
|
||||||
|
# the label which when added triggers a rerun of the default CircleCI workflow
|
||||||
|
triggerRerunLabel: "PR action: rerun CI at HEAD"
|
||||||
|
6
.gitignore
vendored
6
.gitignore
vendored
@ -1,17 +1,19 @@
|
|||||||
.DS_STORE
|
.DS_STORE
|
||||||
|
|
||||||
/dist/
|
/dist/
|
||||||
/bazel-out/
|
/bazel-out
|
||||||
/integration/bazel/bazel-*
|
/integration/bazel/bazel-*
|
||||||
e2e_test.*
|
e2e_test.*
|
||||||
node_modules
|
node_modules
|
||||||
bower_components
|
|
||||||
tools/gulp-tasks/cldr/cldr-data/
|
tools/gulp-tasks/cldr/cldr-data/
|
||||||
|
|
||||||
# Include when developing application packages.
|
# Include when developing application packages.
|
||||||
pubspec.lock
|
pubspec.lock
|
||||||
.c9
|
.c9
|
||||||
.idea/
|
.idea/
|
||||||
|
.devcontainer/*
|
||||||
|
!.devcontainer/recommended-devcontainer.json
|
||||||
|
!.devcontainer/recommended-Dockerfile
|
||||||
.settings/
|
.settings/
|
||||||
.vscode/launch.json
|
.vscode/launch.json
|
||||||
.vscode/settings.json
|
.vscode/settings.json
|
||||||
|
3
.vscode/extensions.json
vendored
3
.vscode/extensions.json
vendored
@ -8,5 +8,8 @@
|
|||||||
"gkalpak.aio-docs-utils",
|
"gkalpak.aio-docs-utils",
|
||||||
"ms-vscode.vscode-typescript-tslint-plugin",
|
"ms-vscode.vscode-typescript-tslint-plugin",
|
||||||
"xaver.clang-format",
|
"xaver.clang-format",
|
||||||
|
// The following extensions are useful when working on angular.io (i.e. inside the `aio/` directory).
|
||||||
|
//"angular.ng-template",
|
||||||
|
//"dbaeumer.vscode-eslint",
|
||||||
],
|
],
|
||||||
}
|
}
|
||||||
|
55
BUILD.bazel
55
BUILD.bazel
@ -1,8 +1,12 @@
|
|||||||
package(default_visibility = ["//visibility:public"])
|
package(default_visibility = ["//visibility:public"])
|
||||||
|
|
||||||
|
load("//tools:defaults.bzl", "karma_web_test")
|
||||||
|
|
||||||
exports_files([
|
exports_files([
|
||||||
"LICENSE",
|
"LICENSE",
|
||||||
"protractor-perf.conf.js",
|
"protractor-perf.conf.js",
|
||||||
|
"karma-js.conf.js",
|
||||||
|
"browser-providers.conf.js",
|
||||||
])
|
])
|
||||||
|
|
||||||
alias(
|
alias(
|
||||||
@ -14,11 +18,15 @@ filegroup(
|
|||||||
name = "web_test_bootstrap_scripts",
|
name = "web_test_bootstrap_scripts",
|
||||||
# do not sort
|
# do not sort
|
||||||
srcs = [
|
srcs = [
|
||||||
"@npm//node_modules/reflect-metadata:Reflect.js",
|
"@npm//node_modules/core-js:client/core.js",
|
||||||
"@npm//node_modules/zone.js:dist/zone.js",
|
"@npm//node_modules/zone.js:dist/zone.js",
|
||||||
"@npm//node_modules/zone.js:dist/zone-testing.js",
|
"@npm//node_modules/zone.js:dist/zone-testing.js",
|
||||||
"@npm//node_modules/zone.js:dist/task-tracking.js",
|
"@npm//node_modules/zone.js:dist/task-tracking.js",
|
||||||
"//:test-events.js",
|
"//:test-events.js",
|
||||||
|
"//:shims_for_IE.js",
|
||||||
|
# Including systemjs because it defines `__eval`, which produces correct stack traces.
|
||||||
|
"@npm//node_modules/systemjs:dist/system.src.js",
|
||||||
|
"@npm//node_modules/reflect-metadata:Reflect.js",
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -38,3 +46,48 @@ filegroup(
|
|||||||
"@npm//node_modules/angular-mocks-1.6:angular-mocks.js",
|
"@npm//node_modules/angular-mocks-1.6:angular-mocks.js",
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# To run a karma_web_test target locally on SauceLabs:
|
||||||
|
# 1) have SAUCE_USERNAME, SAUCE_ACCESS_KEY (and optionally a SAUCE_TUNNEL_IDENTIFIER) set in your environment
|
||||||
|
# 2) open a sauce connection with `./scripts/saucelabs/start-tunnel.sh`
|
||||||
|
# NOTE: start-tunnel.sh uses `node_modules/sauce-connect` which is current linux specific:
|
||||||
|
# "sauce-connect": "https://saucelabs.com/downloads/sc-4.5.3-linux.tar.gz".
|
||||||
|
# On OSX or Windows you'll need to use the appropriate sauce-connect binary.
|
||||||
|
# 3) run target with `yarn bazel test --config=saucelabs <target>`
|
||||||
|
# NOTE: --config=saucelabs is required as it makes the SAUCE_XXX environment variables available to
|
||||||
|
# the action. See /.bazelrc.
|
||||||
|
karma_web_test(
|
||||||
|
name = "test_web_all",
|
||||||
|
tags = [
|
||||||
|
"local",
|
||||||
|
"manual",
|
||||||
|
"saucelabs",
|
||||||
|
],
|
||||||
|
deps = [
|
||||||
|
# We combine all tests into a single karma_web_test target
|
||||||
|
# as running them as seperate targets in parallel leads to too many
|
||||||
|
# browsers being acquired at once in SauceLabs and the tests flake out
|
||||||
|
# TODO: this is an example subset of tests below, add all remaining angular tests
|
||||||
|
"//packages/common/http/test:test_lib",
|
||||||
|
"//packages/common/http/testing/test:test_lib",
|
||||||
|
"//packages/common/test:test_lib",
|
||||||
|
"//packages/core/test:test_lib",
|
||||||
|
"//packages/forms/test:test_lib",
|
||||||
|
"//packages/http/test:test_lib",
|
||||||
|
"//packages/zone.js/test:karma_jasmine_test_ci",
|
||||||
|
# "//packages/router/test:test_lib",
|
||||||
|
# //packages/router/test:test_lib fails with:
|
||||||
|
# IE 11.0.0 (Windows 8.1.0.0) bootstrap should restore the scrolling position FAILED
|
||||||
|
# Expected undefined to equal 5000.
|
||||||
|
# at stack (eval code:2338:11)
|
||||||
|
# at buildExpectationResult (eval code:2305:5)
|
||||||
|
# at expectationResultFactory (eval code:858:11)
|
||||||
|
# at Spec.prototype.addExpectationResult (eval code:487:5)
|
||||||
|
# at addExpectationResult (eval code:802:9)
|
||||||
|
# at Anonymous function (eval code:2252:7)
|
||||||
|
# at Anonymous function (eval code:339:25)
|
||||||
|
# at step (eval code:133:17)
|
||||||
|
# at Anonymous function (eval code:114:50)
|
||||||
|
# at fulfilled (eval code:104:47)
|
||||||
|
],
|
||||||
|
)
|
||||||
|
914
CHANGELOG.md
914
CHANGELOG.md
File diff suppressed because it is too large
Load Diff
@ -1,4 +1,4 @@
|
|||||||
[](https://circleci.com/gh/angular/angular/tree/master)
|
[](https://circleci.com/gh/angular/workflows/angular/tree/master)
|
||||||
[](https://www.browserstack.com/automate/public-build/LzF3RzBVVGt6VWE2S0hHaC9uYllOZz09LS1BVjNTclBKV0x4eVRlcjA4QVY1M0N3PT0=--eb4ce8c8dc2c1c5b2b5352d473ee12a73ac20e06)
|
[](https://www.browserstack.com/automate/public-build/LzF3RzBVVGt6VWE2S0hHaC9uYllOZz09LS1BVjNTclBKV0x4eVRlcjA4QVY1M0N3PT0=--eb4ce8c8dc2c1c5b2b5352d473ee12a73ac20e06)
|
||||||
[](https://gitter.im/angular/angular?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
|
[](https://gitter.im/angular/angular?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
|
||||||
[](https://www.npmjs.com/@angular/core)
|
[](https://www.npmjs.com/@angular/core)
|
||||||
@ -23,6 +23,6 @@ guidelines for [contributing][contributing] and then check out one of our issues
|
|||||||
|
|
||||||
[browserstack]: https://www.browserstack.com/automate/public-build/LzF3RzBVVGt6VWE2S0hHaC9uYllOZz09LS1BVjNTclBKV0x4eVRlcjA4QVY1M0N3PT0=--eb4ce8c8dc2c1c5b2b5352d473ee12a73ac20e06
|
[browserstack]: https://www.browserstack.com/automate/public-build/LzF3RzBVVGt6VWE2S0hHaC9uYllOZz09LS1BVjNTclBKV0x4eVRlcjA4QVY1M0N3PT0=--eb4ce8c8dc2c1c5b2b5352d473ee12a73ac20e06
|
||||||
[contributing]: https://github.com/angular/angular/blob/master/CONTRIBUTING.md
|
[contributing]: https://github.com/angular/angular/blob/master/CONTRIBUTING.md
|
||||||
[quickstart]: https://angular.io/guide/quickstart
|
[quickstart]: https://angular.io/start
|
||||||
[changelog]: https://github.com/angular/angular/blob/master/CHANGELOG.md
|
[changelog]: https://github.com/angular/angular/blob/master/CHANGELOG.md
|
||||||
[ng]: https://angular.io
|
[ng]: https://angular.io
|
||||||
|
74
WORKSPACE
74
WORKSPACE
@ -1,4 +1,7 @@
|
|||||||
workspace(name = "angular")
|
workspace(
|
||||||
|
name = "angular",
|
||||||
|
managed_directories = {"@npm": ["node_modules"]},
|
||||||
|
)
|
||||||
|
|
||||||
load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive")
|
load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive")
|
||||||
|
|
||||||
@ -15,17 +18,15 @@ load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive")
|
|||||||
# Fetch rules_nodejs so we can install our npm dependencies
|
# Fetch rules_nodejs so we can install our npm dependencies
|
||||||
http_archive(
|
http_archive(
|
||||||
name = "build_bazel_rules_nodejs",
|
name = "build_bazel_rules_nodejs",
|
||||||
sha256 = "5c86b055c57e15bf32d9009a15bcd6d8e190c41b1ff2fb18037b75e0012e4e7c",
|
sha256 = "e04a82a72146bfbca2d0575947daa60fda1878c8d3a3afe868a8ec39a6b968bb",
|
||||||
urls = ["https://github.com/bazelbuild/rules_nodejs/releases/download/0.26.0/rules_nodejs-0.26.0.tar.gz"],
|
urls = ["https://github.com/bazelbuild/rules_nodejs/releases/download/0.31.1/rules_nodejs-0.31.1.tar.gz"],
|
||||||
)
|
)
|
||||||
|
|
||||||
# Check the bazel version and download npm dependencies
|
# Check the bazel version and download npm dependencies
|
||||||
load("@build_bazel_rules_nodejs//:defs.bzl", "check_bazel_version", "node_repositories", "yarn_install")
|
load("@build_bazel_rules_nodejs//:defs.bzl", "check_bazel_version", "check_rules_nodejs_version", "node_repositories", "yarn_install")
|
||||||
load("@build_bazel_rules_nodejs//:package.bzl", "check_rules_nodejs_version")
|
|
||||||
|
|
||||||
# Bazel version must be at least v0.21.0 because:
|
# Bazel version must be at least the following version because:
|
||||||
# - 0.21.0 Using --incompatible_strict_action_env flag fixes cache when running `yarn bazel`
|
# - 0.26.0 managed_directories feature added which is required for nodejs rules 0.30.0
|
||||||
# (see https://github.com/angular/angular/issues/27514#issuecomment-451438271)
|
|
||||||
check_bazel_version(
|
check_bazel_version(
|
||||||
message = """
|
message = """
|
||||||
You no longer need to install Bazel on your machine.
|
You no longer need to install Bazel on your machine.
|
||||||
@ -34,21 +35,36 @@ Try running `yarn bazel` instead.
|
|||||||
(If you did run that, check that you've got a fresh `yarn install`)
|
(If you did run that, check that you've got a fresh `yarn install`)
|
||||||
|
|
||||||
""",
|
""",
|
||||||
minimum_bazel_version = "0.21.0",
|
minimum_bazel_version = "0.26.0",
|
||||||
)
|
)
|
||||||
|
|
||||||
# The NodeJS rules version must be at least v0.15.3 because:
|
# The NodeJS rules version must be at least the following version because:
|
||||||
# - 0.15.2 Re-introduced the prod_only attribute on yarn_install
|
# - 0.15.2 Re-introduced the prod_only attribute on yarn_install
|
||||||
# - 0.15.3 Includes a fix for the `jasmine_node_test` rule ignoring target tags
|
# - 0.15.3 Includes a fix for the `jasmine_node_test` rule ignoring target tags
|
||||||
# - 0.16.8 Supports npm installed bazel workspaces
|
# - 0.16.8 Supports npm installed bazel workspaces
|
||||||
# - 0.26.0 Fix for data files in yarn_install and npm_install
|
# - 0.26.0 Fix for data files in yarn_install and npm_install
|
||||||
check_rules_nodejs_version("0.26.0")
|
# - 0.27.12 Adds NodeModuleSources provider for transtive npm deps support
|
||||||
|
# - 0.30.0 yarn_install now uses symlinked node_modules with new managed directories Bazel 0.26.0 feature
|
||||||
|
# - 0.31.1 entry_point attribute of nodejs_binary & rollup_bundle is now a label
|
||||||
|
check_rules_nodejs_version(minimum_version_string = "0.31.1")
|
||||||
|
|
||||||
# Setup the Node.js toolchain
|
# Setup the Node.js toolchain
|
||||||
node_repositories(
|
node_repositories(
|
||||||
node_version = "10.9.0",
|
node_repositories = {
|
||||||
|
"10.16.0-darwin_amd64": ("node-v10.16.0-darwin-x64.tar.gz", "node-v10.16.0-darwin-x64", "6c009df1b724026d84ae9a838c5b382662e30f6c5563a0995532f2bece39fa9c"),
|
||||||
|
"10.16.0-linux_amd64": ("node-v10.16.0-linux-x64.tar.xz", "node-v10.16.0-linux-x64", "1827f5b99084740234de0c506f4dd2202a696ed60f76059696747c34339b9d48"),
|
||||||
|
"10.16.0-windows_amd64": ("node-v10.16.0-win-x64.zip", "node-v10.16.0-win-x64", "aa22cb357f0fb54ccbc06b19b60e37eefea5d7dd9940912675d3ed988bf9a059"),
|
||||||
|
},
|
||||||
|
node_version = "10.16.0",
|
||||||
package_json = ["//:package.json"],
|
package_json = ["//:package.json"],
|
||||||
preserve_symlinks = True,
|
# yarn 1.13.0 under Bazel has a regression on Windows that causes build errors on rebuilds:
|
||||||
|
# ```
|
||||||
|
# ERROR: Source forest creation failed: C:/.../fyuc5c3n/execroot/angular/external (Directory not empty)
|
||||||
|
# ```
|
||||||
|
# See https://github.com/angular/angular/pull/29431 for more information.
|
||||||
|
# It possible that versions of yarn past 1.13.0 do not have this issue, however, before
|
||||||
|
# advancing this version we need to test manually on Windows that the above error does not
|
||||||
|
# happen as the issue is not caught by CI.
|
||||||
yarn_version = "1.12.1",
|
yarn_version = "1.12.1",
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -63,15 +79,13 @@ yarn_install(
|
|||||||
package_json = "//:package.json",
|
package_json = "//:package.json",
|
||||||
# Don't install devDependencies, they are large and not used under Bazel
|
# Don't install devDependencies, they are large and not used under Bazel
|
||||||
prod_only = True,
|
prod_only = True,
|
||||||
|
# Temporarily disable node_modules symlinking until the fix for
|
||||||
|
# https://github.com/bazelbuild/bazel/issues/8487 makes it into a
|
||||||
|
# future Bazel release
|
||||||
|
symlink_node_modules = False,
|
||||||
yarn_lock = "//:yarn.lock",
|
yarn_lock = "//:yarn.lock",
|
||||||
)
|
)
|
||||||
|
|
||||||
yarn_install(
|
|
||||||
name = "ts-api-guardian_deps",
|
|
||||||
package_json = "@angular//tools/ts-api-guardian:package.json",
|
|
||||||
yarn_lock = "@angular//tools/ts-api-guardian:yarn.lock",
|
|
||||||
)
|
|
||||||
|
|
||||||
# Install all bazel dependencies of the @npm npm packages
|
# Install all bazel dependencies of the @npm npm packages
|
||||||
load("@npm//:install_bazel_dependencies.bzl", "install_bazel_dependencies")
|
load("@npm//:install_bazel_dependencies.bzl", "install_bazel_dependencies")
|
||||||
|
|
||||||
@ -94,7 +108,7 @@ web_test_repositories()
|
|||||||
|
|
||||||
# Temporary work-around for https://github.com/angular/angular/issues/28681
|
# Temporary work-around for https://github.com/angular/angular/issues/28681
|
||||||
# TODO(gregmagolan): go back to @io_bazel_rules_webtesting browser_repositories
|
# TODO(gregmagolan): go back to @io_bazel_rules_webtesting browser_repositories
|
||||||
load("@npm_bazel_karma//:browser_repositories.bzl", "browser_repositories")
|
load("//:browser_repositories.bzl", "browser_repositories")
|
||||||
|
|
||||||
browser_repositories()
|
browser_repositories()
|
||||||
|
|
||||||
@ -112,3 +126,23 @@ sass_repositories()
|
|||||||
load("@io_bazel_skydoc//skylark:skylark.bzl", "skydoc_repositories")
|
load("@io_bazel_skydoc//skylark:skylark.bzl", "skydoc_repositories")
|
||||||
|
|
||||||
skydoc_repositories()
|
skydoc_repositories()
|
||||||
|
|
||||||
|
load("@bazel_toolchains//rules:environments.bzl", "clang_env")
|
||||||
|
load("@bazel_toolchains//rules:rbe_repo.bzl", "rbe_autoconfig")
|
||||||
|
|
||||||
|
rbe_autoconfig(
|
||||||
|
name = "rbe_ubuntu1604_angular",
|
||||||
|
# The sha256 of marketplace.gcr.io/google/rbe-ubuntu16-04 container that is
|
||||||
|
# used by rbe_autoconfig() to pair toolchain configs in the @bazel_toolchains repo.
|
||||||
|
base_container_digest = "sha256:677c1317f14c6fd5eba2fd8ec645bfdc5119f64b3e5e944e13c89e0525cc8ad1",
|
||||||
|
# Note that if you change the `digest`, you might also need to update the
|
||||||
|
# `base_container_digest` to make sure marketplace.gcr.io/google/rbe-ubuntu16-04-webtest:<digest>
|
||||||
|
# and marketplace.gcr.io/google/rbe-ubuntu16-04:<base_container_digest> have
|
||||||
|
# the same Clang and JDK installed.
|
||||||
|
# Clang is needed because of the dependency on @com_google_protobuf.
|
||||||
|
# Java is needed for the Bazel's test executor Java tool.
|
||||||
|
digest = "sha256:74a8e9dca4781d5f277a7bd8e7ea7ed0f5906c79c9cd996205b6d32f090c62f3",
|
||||||
|
env = clang_env(),
|
||||||
|
registry = "marketplace.gcr.io",
|
||||||
|
repository = "google/rbe-ubuntu16-04-webtest",
|
||||||
|
)
|
||||||
|
@ -13,6 +13,13 @@
|
|||||||
"root": "",
|
"root": "",
|
||||||
"sourceRoot": "src",
|
"sourceRoot": "src",
|
||||||
"projectType": "application",
|
"projectType": "application",
|
||||||
|
"prefix": "aio",
|
||||||
|
"schematics": {
|
||||||
|
"@schematics/angular:component": {
|
||||||
|
"inlineStyle": true,
|
||||||
|
"style": "scss"
|
||||||
|
}
|
||||||
|
},
|
||||||
"architect": {
|
"architect": {
|
||||||
"build": {
|
"build": {
|
||||||
"builder": "@angular-devkit/build-angular:browser",
|
"builder": "@angular-devkit/build-angular:browser",
|
||||||
@ -20,8 +27,9 @@
|
|||||||
"outputPath": "dist",
|
"outputPath": "dist",
|
||||||
"index": "src/index.html",
|
"index": "src/index.html",
|
||||||
"main": "src/main.ts",
|
"main": "src/main.ts",
|
||||||
"tsConfig": "src/tsconfig.app.json",
|
"polyfills": "src/polyfills.ts",
|
||||||
"webWorkerTsConfig": "src/tsconfig.worker.json",
|
"tsConfig": "tsconfig.app.json",
|
||||||
|
"webWorkerTsConfig": "tsconfig.worker.json",
|
||||||
"aot": true,
|
"aot": true,
|
||||||
"optimization": true,
|
"optimization": true,
|
||||||
"buildOptimizer": true,
|
"buildOptimizer": true,
|
||||||
@ -32,7 +40,6 @@
|
|||||||
"extractLicenses": true,
|
"extractLicenses": true,
|
||||||
"namedChunks": true,
|
"namedChunks": true,
|
||||||
"vendorChunk": false,
|
"vendorChunk": false,
|
||||||
"polyfills": "src/polyfills.ts",
|
|
||||||
"assets": [
|
"assets": [
|
||||||
"src/assets",
|
"src/assets",
|
||||||
"src/generated",
|
"src/generated",
|
||||||
@ -61,8 +68,8 @@
|
|||||||
"next": {
|
"next": {
|
||||||
"fileReplacements": [
|
"fileReplacements": [
|
||||||
{
|
{
|
||||||
"src": "src/environments/environment.ts",
|
"replace": "src/environments/environment.ts",
|
||||||
"replaceWith": "src/environments/environment.next.ts"
|
"with": "src/environments/environment.next.ts"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"serviceWorker": true
|
"serviceWorker": true
|
||||||
@ -70,8 +77,8 @@
|
|||||||
"stable": {
|
"stable": {
|
||||||
"fileReplacements": [
|
"fileReplacements": [
|
||||||
{
|
{
|
||||||
"src": "src/environments/environment.ts",
|
"replace": "src/environments/environment.ts",
|
||||||
"replaceWith": "src/environments/environment.stable.ts"
|
"with": "src/environments/environment.stable.ts"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"serviceWorker": true
|
"serviceWorker": true
|
||||||
@ -79,8 +86,8 @@
|
|||||||
"archive": {
|
"archive": {
|
||||||
"fileReplacements": [
|
"fileReplacements": [
|
||||||
{
|
{
|
||||||
"src": "src/environments/environment.ts",
|
"replace": "src/environments/environment.ts",
|
||||||
"replaceWith": "src/environments/environment.archive.ts"
|
"with": "src/environments/environment.archive.ts"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"serviceWorker": true
|
"serviceWorker": true
|
||||||
@ -120,14 +127,10 @@
|
|||||||
"builder": "@angular-devkit/build-angular:karma",
|
"builder": "@angular-devkit/build-angular:karma",
|
||||||
"options": {
|
"options": {
|
||||||
"main": "src/test.ts",
|
"main": "src/test.ts",
|
||||||
"karmaConfig": "src/karma.conf.js",
|
|
||||||
"polyfills": "src/polyfills.ts",
|
"polyfills": "src/polyfills.ts",
|
||||||
"tsConfig": "src/tsconfig.spec.json",
|
"tsConfig": "tsconfig.spec.json",
|
||||||
"webWorkerTsConfig": "src/tsconfig.worker.json",
|
"webWorkerTsConfig": "tsconfig.worker.json",
|
||||||
"scripts": [],
|
"karmaConfig": "karma.conf.js",
|
||||||
"styles": [
|
|
||||||
"src/styles.scss"
|
|
||||||
],
|
|
||||||
"assets": [
|
"assets": [
|
||||||
"src/assets",
|
"src/assets",
|
||||||
"src/generated",
|
"src/generated",
|
||||||
@ -143,27 +146,27 @@
|
|||||||
"input": "node_modules/@webcomponents/custom-elements/src",
|
"input": "node_modules/@webcomponents/custom-elements/src",
|
||||||
"output": "/assets/js"
|
"output": "/assets/js"
|
||||||
}
|
}
|
||||||
]
|
],
|
||||||
|
"styles": [
|
||||||
|
"src/styles.scss"
|
||||||
|
],
|
||||||
|
"scripts": []
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"lint": {
|
"lint": {
|
||||||
"builder": "@angular-devkit/build-angular:tslint",
|
"builder": "@angular-devkit/build-angular:tslint",
|
||||||
"options": {
|
"options": {
|
||||||
"tsConfig": [
|
"tsConfig": [
|
||||||
"src/tsconfig.app.json",
|
"tsconfig.app.json",
|
||||||
"src/tsconfig.spec.json"
|
"tsconfig.spec.json",
|
||||||
|
"tsconfig.worker.json",
|
||||||
|
"tests/e2e/tsconfig.json"
|
||||||
],
|
],
|
||||||
"exclude": []
|
"exclude": [
|
||||||
|
"**/node_modules/**"
|
||||||
|
]
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
}
|
|
||||||
},
|
|
||||||
"site-e2e": {
|
|
||||||
"root": "",
|
|
||||||
"projectType": "application",
|
|
||||||
"cli": {},
|
|
||||||
"schematics": {},
|
|
||||||
"architect": {
|
|
||||||
"e2e": {
|
"e2e": {
|
||||||
"builder": "@angular-devkit/build-angular:protractor",
|
"builder": "@angular-devkit/build-angular:protractor",
|
||||||
"options": {
|
"options": {
|
||||||
@ -175,27 +178,9 @@
|
|||||||
"devServerTarget": "site:serve:ci"
|
"devServerTarget": "site:serve:ci"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
|
||||||
"lint": {
|
|
||||||
"builder": "@angular-devkit/build-angular:tslint",
|
|
||||||
"options": {
|
|
||||||
"tsConfig": [
|
|
||||||
"tests/e2e/tsconfig.e2e.json"
|
|
||||||
],
|
|
||||||
"exclude": []
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"schematics": {
|
"defaultProject": "site"
|
||||||
"@schematics/angular:component": {
|
|
||||||
"inlineStyle": true,
|
|
||||||
"prefix": "aio",
|
|
||||||
"styleext": "scss"
|
|
||||||
},
|
|
||||||
"@schematics/angular:directive": {
|
|
||||||
"prefix": "aio"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
12
aio/browserslist
Normal file
12
aio/browserslist
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
# This file is used by the build system to adjust CSS and JS output to support the specified browsers below.
|
||||||
|
# For additional information regarding the format and rule options, please see:
|
||||||
|
# https://github.com/browserslist/browserslist#queries
|
||||||
|
|
||||||
|
# Googlebot uses an older version of Chrome
|
||||||
|
# For additional information see: https://developers.google.com/search/docs/guides/rendering
|
||||||
|
|
||||||
|
> 0.5%
|
||||||
|
last 2 major versions
|
||||||
|
Firefox ESR
|
||||||
|
not dead
|
||||||
|
IE 11
|
@ -1,4 +1,4 @@
|
|||||||
<h1 class="no-toc">CLI Command Reference</h1>
|
# CLI Overview and Command Reference
|
||||||
|
|
||||||
The Angular CLI is a command-line interface tool that you use to initialize, develop, scaffold, and maintain Angular applications. You can use the tool directly in a command shell, or indirectly through an interactive UI such as [Angular Console](https://angularconsole.com).
|
The Angular CLI is a command-line interface tool that you use to initialize, develop, scaffold, and maintain Angular applications. You can use the tool directly in a command shell, or indirectly through an interactive UI such as [Angular Console](https://angularconsole.com).
|
||||||
|
|
||||||
@ -101,3 +101,9 @@ Options that specify files can be given as absolute paths, or as paths relative
|
|||||||
The [ng generate](cli/generate) and [ng add](cli/add) commands take as an argument the artifact or library to be generated or added to the current project.
|
The [ng generate](cli/generate) and [ng add](cli/add) commands take as an argument the artifact or library to be generated or added to the current project.
|
||||||
In addition to any general options, each artifact or library defines its own options in a *schematic*.
|
In addition to any general options, each artifact or library defines its own options in a *schematic*.
|
||||||
Schematic options are supplied to the command in the same format as immediate command options.
|
Schematic options are supplied to the command in the same format as immediate command options.
|
||||||
|
|
||||||
|
|
||||||
|
### Building with Bazel
|
||||||
|
|
||||||
|
Optionally, you can configure the Angular CLI to use [Bazel](https://docs.bazel.build) as the build tool. For more information, see [Building with Bazel](guide/bazel).
|
||||||
|
|
||||||
|
48
aio/content/cli/usage-analytics-gathering.md
Normal file
48
aio/content/cli/usage-analytics-gathering.md
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
# Gathering and Viewing Usage Analytics
|
||||||
|
|
||||||
|
Users can opt in to share their Angular CLI usage data with [Google Analytics](https://support.google.com/analytics/answer/1008015?hl=en), using the [`ng analytics` CLI command](analytics).
|
||||||
|
The data is also shared with the Angular team, and used to improve the CLI.
|
||||||
|
|
||||||
|
The gathering of CLI analytics data is disabled by default, and must be enabled at the project level by individual users.
|
||||||
|
It cannot be enabled at the project level for all users.
|
||||||
|
|
||||||
|
Data gathered in this way can be viewed on the Google Analytics site, but is not automatically visible on your own organization's Analytics site.
|
||||||
|
As an administrator for an Angular development group, you can configure your instance of Angular CLI to be able to see analytics data for your own team's usage of the Angular CLI.
|
||||||
|
This configuration option is separate from and in addition to other usage analytics that your users may be sharing with Google.
|
||||||
|
|
||||||
|
## Enable access to CLI usage data
|
||||||
|
|
||||||
|
To configure access to your own users' CLI usage data, use the `ng config` command to add a key to your global [`angular.json` workspace configuration file](guide/workspace-config).
|
||||||
|
The key goes under `cli.analyticsSharing` at the top level of the file, outside the `projects` sections.
|
||||||
|
The value of the key is your organization's tracking ID, as assigned by Google Analytics.
|
||||||
|
This ID is a string that looks like `UA-123456-12`.
|
||||||
|
|
||||||
|
You can choose to use a descriptive string as the key value, or be assigned a random key when you run the CLI command.
|
||||||
|
For example, the following command adds a configuration key named "tracking".
|
||||||
|
|
||||||
|
<code-example language="sh" class="code-shell">
|
||||||
|
ng config --global cli.analyticsSharing.tracking UA-123456-12
|
||||||
|
</code-example>
|
||||||
|
|
||||||
|
To turn off this feature, run the following command:
|
||||||
|
|
||||||
|
<code-example language="sh" class="code-shell">
|
||||||
|
ng config --global --remove cli.analyticsSharing
|
||||||
|
</code-example>
|
||||||
|
|
||||||
|
|
||||||
|
## Per user tracking
|
||||||
|
|
||||||
|
You can add a custom user ID to the global configuration, in order to identify unique usage of commands and flags.
|
||||||
|
If that user enables CLI analytics for their own project, your analytics display tracks and labels their individual usage.
|
||||||
|
|
||||||
|
|
||||||
|
<code-example language="sh" class="code-shell">
|
||||||
|
ng config --global cli.analyticsSharing.user SOME_USER_NAME
|
||||||
|
</code-example>
|
||||||
|
|
||||||
|
To generate a new random user ID, run the following command:
|
||||||
|
|
||||||
|
<code-example language="sh" class="code-shell">
|
||||||
|
ng config --global cli.analyticsSharing.user ""
|
||||||
|
</code-example>
|
3
aio/content/examples/.gitignore
vendored
3
aio/content/examples/.gitignore
vendored
@ -23,6 +23,9 @@
|
|||||||
**/bs-config.e2e.json
|
**/bs-config.e2e.json
|
||||||
**/bs-config.json
|
**/bs-config.json
|
||||||
**/package.json
|
**/package.json
|
||||||
|
**/tsconfig.json
|
||||||
|
**/tsconfig.app.json
|
||||||
|
**/tsconfig.spec.json
|
||||||
**/tslint.json
|
**/tslint.json
|
||||||
**/karma-test-shim.js
|
**/karma-test-shim.js
|
||||||
**/browser-test-shim.js
|
**/browser-test-shim.js
|
||||||
|
@ -67,8 +67,8 @@ describe('AngularJS to Angular Quick Reference Tests', function () {
|
|||||||
testFavoriteHero('Magneta', 'No movie, sorry!');
|
testFavoriteHero('Magneta', 'No movie, sorry!');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should display a movie for Mr. Nice', function () {
|
it('should display a movie for Dr Nice', function () {
|
||||||
testFavoriteHero('Mr. Nice', 'Excellent choice!');
|
testFavoriteHero('Dr Nice', 'Excellent choice!');
|
||||||
});
|
});
|
||||||
|
|
||||||
function testImagesAreDisplayed(isDisplayed: boolean) {
|
function testImagesAreDisplayed(isDisplayed: boolean) {
|
||||||
|
@ -18,12 +18,12 @@ export class MovieService {
|
|||||||
approvalRating: .97
|
approvalRating: .97
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
hero: 'Mr. Nice',
|
hero: 'Dr Nice',
|
||||||
imageurl: 'assets/images/villain.png',
|
imageurl: 'assets/images/villain.png',
|
||||||
movieId: 2,
|
movieId: 2,
|
||||||
mpaa: 'pg-13',
|
mpaa: 'pg-13',
|
||||||
releaseDate: '2015-12-18T00:00:00',
|
releaseDate: '2015-12-18T00:00:00',
|
||||||
title: 'No More Mr. Nice Guy',
|
title: 'No More Dr Nice',
|
||||||
price: 14.95,
|
price: 14.95,
|
||||||
starRating: 4.6,
|
starRating: 4.6,
|
||||||
approvalRating: .94
|
approvalRating: .94
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
import { Hero } from './hero';
|
import { Hero } from './hero';
|
||||||
|
|
||||||
export const HEROES: Hero[] = [
|
export const HEROES: Hero[] = [
|
||||||
{ id: 11, name: 'Mr. Nice' },
|
{ id: 11, name: 'Dr Nice' },
|
||||||
{ id: 12, name: 'Narco' },
|
{ id: 12, name: 'Narco' },
|
||||||
{ id: 13, name: 'Bombasto' },
|
{ id: 13, name: 'Bombasto' },
|
||||||
{ id: 14, name: 'Celeritas' },
|
{ id: 14, name: 'Celeritas' },
|
||||||
|
@ -31,7 +31,7 @@ describe('Architecture', () => {
|
|||||||
|
|
||||||
function heroTests() {
|
function heroTests() {
|
||||||
|
|
||||||
const targetHero: Hero = { id: 2, name: 'Mr. Nice' };
|
const targetHero: Hero = { id: 2, name: 'Dr Nice' };
|
||||||
|
|
||||||
it('has the right number of heroes', () => {
|
it('has the right number of heroes', () => {
|
||||||
let page = getPageElts();
|
let page = getPageElts();
|
||||||
|
@ -5,7 +5,7 @@ import { Hero } from './hero';
|
|||||||
|
|
||||||
const HEROES = [
|
const HEROES = [
|
||||||
new Hero('Windstorm', 'Weather mastery'),
|
new Hero('Windstorm', 'Weather mastery'),
|
||||||
new Hero('Mr. Nice', 'Killing them with kindness'),
|
new Hero('Dr Nice', 'Killing them with kindness'),
|
||||||
new Hero('Magneta', 'Manipulates metallic objects')
|
new Hero('Magneta', 'Manipulates metallic objects')
|
||||||
];
|
];
|
||||||
|
|
||||||
|
@ -12,7 +12,7 @@ import { Component } from '@angular/core';
|
|||||||
// #enddocregion import-core-component
|
// #enddocregion import-core-component
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'my-app',
|
selector: 'app-root',
|
||||||
template: 'Welcome to Angular'
|
template: 'Welcome to Angular'
|
||||||
})
|
})
|
||||||
export class AppComponent {
|
export class AppComponent {
|
||||||
|
@ -0,0 +1,47 @@
|
|||||||
|
'use strict'; // necessary for es6 output in node
|
||||||
|
|
||||||
|
import { browser, element, by } from 'protractor';
|
||||||
|
|
||||||
|
describe('Attribute binding example', function () {
|
||||||
|
|
||||||
|
beforeEach(function () {
|
||||||
|
browser.get('');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should display Property Binding with Angular', function () {
|
||||||
|
expect(element(by.css('h1')).getText()).toEqual('Attribute, class, and style bindings');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should display a table', function() {
|
||||||
|
expect(element.all(by.css('table')).isPresent()).toBe(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should display an Aria button', function () {
|
||||||
|
expect(element.all(by.css('button')).get(0).getText()).toBe('Go for it with Aria');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should display a blue background on div', function () {
|
||||||
|
expect(element.all(by.css('div')).get(1).getCssValue('background-color')).toEqual('rgba(25, 118, 210, 1)');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should display a blue div with a red border', function () {
|
||||||
|
expect(element.all(by.css('div')).get(4).getCssValue('border')).toEqual('2px solid rgb(212, 30, 46)');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should display a div with replaced classes', function () {
|
||||||
|
expect(element.all(by.css('div')).get(5).getAttribute('class')).toEqual('new-class');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should display four buttons', function() {
|
||||||
|
let redButton = element.all(by.css('button')).get(1);
|
||||||
|
let saveButton = element.all(by.css('button')).get(2);
|
||||||
|
let bigButton = element.all(by.css('button')).get(3);
|
||||||
|
let smallButton = element.all(by.css('button')).get(4);
|
||||||
|
|
||||||
|
expect(redButton.getCssValue('color')).toEqual('rgba(255, 0, 0, 1)');
|
||||||
|
expect(saveButton.getCssValue('background-color')).toEqual('rgba(0, 255, 255, 1)');
|
||||||
|
expect(bigButton.getText()).toBe('Big');
|
||||||
|
expect(smallButton.getText()).toBe('Small');
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
@ -0,0 +1,22 @@
|
|||||||
|
.special {
|
||||||
|
background-color: #1976d2;
|
||||||
|
color: #ffffff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.item {
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
.clearance {
|
||||||
|
border: 2px solid #d41e2e;
|
||||||
|
|
||||||
|
}
|
||||||
|
.item-clearance {
|
||||||
|
font-style: italic;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
.new-class {
|
||||||
|
background-color: #ed1b2f;
|
||||||
|
font-style: italic;
|
||||||
|
color: #fff;
|
||||||
|
}
|
@ -0,0 +1,65 @@
|
|||||||
|
|
||||||
|
<h1>Attribute, class, and style bindings</h1>
|
||||||
|
<h2>Attribute binding</h2>
|
||||||
|
<!-- #docregion attrib-binding-colspan -->
|
||||||
|
<table border=1>
|
||||||
|
<!-- expression calculates colspan=2 -->
|
||||||
|
<tr><td [attr.colspan]="1 + 1">One-Two</td></tr>
|
||||||
|
|
||||||
|
<!-- ERROR: There is no `colspan` property to set!
|
||||||
|
<tr><td colspan="{{1 + 1}}">Three-Four</td></tr>
|
||||||
|
-->
|
||||||
|
<!-- #docregion colSpan -->
|
||||||
|
<!-- Notice the colSpan property is camel case -->
|
||||||
|
<tr><td [colSpan]="1 + 1">Three-Four</td></tr>
|
||||||
|
<!-- #enddocregion colSpan -->
|
||||||
|
|
||||||
|
<tr><td>Five</td><td>Six</td></tr>
|
||||||
|
</table>
|
||||||
|
<!-- #enddocregion attrib-binding-colspan -->
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<!-- #docregion attrib-binding-aria -->
|
||||||
|
<!-- create and set an aria attribute for assistive technology -->
|
||||||
|
<button [attr.aria-label]="actionName">{{actionName}} with Aria</button>
|
||||||
|
<!-- #enddocregion attrib-binding-aria -->
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<hr />
|
||||||
|
|
||||||
|
<h2>Class binding</h2>
|
||||||
|
|
||||||
|
<!-- #docregion is-special -->
|
||||||
|
<h3>toggle the "special" class on/off with a property:</h3>
|
||||||
|
<div [class.special]="isSpecial">The class binding is special.</div>
|
||||||
|
|
||||||
|
<h3>binding to class.special overrides the class attribute:</h3>
|
||||||
|
<div class="special" [class.special]="!isSpecial">This one is not so special.</div>
|
||||||
|
|
||||||
|
<h3>Using the bind- syntax:</h3>
|
||||||
|
<div bind-class.special="isSpecial">This class binding is special too.</div>
|
||||||
|
<!-- #enddocregion is-special -->
|
||||||
|
|
||||||
|
<!-- #docregion add-class -->
|
||||||
|
<h3>Add a class:</h3>
|
||||||
|
<div class="item clearance special" [class.item-clearance]="itemClearance">Add another class</div>
|
||||||
|
<!-- #enddocregion add-class -->
|
||||||
|
|
||||||
|
<!-- #docregion class-override -->
|
||||||
|
<h3>Overwrite all existing classes with a new class:</h3>
|
||||||
|
<div class="item clearance special" [attr.class]="resetClasses">Reset all classes at once</div>
|
||||||
|
<!-- #enddocregion class-override -->
|
||||||
|
|
||||||
|
<hr />
|
||||||
|
|
||||||
|
<h2>Style binding</h2>
|
||||||
|
|
||||||
|
<!-- #docregion style-binding-->
|
||||||
|
<button [style.color]="isSpecial ? 'red': 'green'">Red</button>
|
||||||
|
<button [style.background-color]="canSave ? 'cyan': 'grey'" >Save</button>
|
||||||
|
<!-- #enddocregion style-binding -->
|
||||||
|
|
||||||
|
<!-- #docregion style-binding-condition-->
|
||||||
|
<button [style.font-size.em]="isSpecial ? 3 : 1" >Big</button>
|
||||||
|
<button [style.font-size.%]="!isSpecial ? 150 : 50" >Small</button>
|
||||||
|
<!-- #enddocregion style-binding-condition-->
|
@ -8,23 +8,20 @@ describe('AppComponent', () => {
|
|||||||
],
|
],
|
||||||
}).compileComponents();
|
}).compileComponents();
|
||||||
}));
|
}));
|
||||||
|
|
||||||
it('should create the app', async(() => {
|
it('should create the app', async(() => {
|
||||||
const fixture = TestBed.createComponent(AppComponent);
|
const fixture = TestBed.createComponent(AppComponent);
|
||||||
const app = fixture.debugElement.componentInstance;
|
const app = fixture.debugElement.componentInstance;
|
||||||
expect(app).toBeTruthy();
|
expect(app).toBeTruthy();
|
||||||
}));
|
}));
|
||||||
|
|
||||||
it(`should have as title 'app'`, async(() => {
|
it(`should have as title 'app'`, async(() => {
|
||||||
const fixture = TestBed.createComponent(AppComponent);
|
const fixture = TestBed.createComponent(AppComponent);
|
||||||
const app = fixture.debugElement.componentInstance;
|
const app = fixture.debugElement.componentInstance;
|
||||||
expect(app.title).toMatch(/app/i);
|
expect(app.title).toEqual('app');
|
||||||
}));
|
}));
|
||||||
|
|
||||||
it('should render title in a h1 tag', async(() => {
|
it('should render title in a h1 tag', async(() => {
|
||||||
const fixture = TestBed.createComponent(AppComponent);
|
const fixture = TestBed.createComponent(AppComponent);
|
||||||
fixture.detectChanges();
|
fixture.detectChanges();
|
||||||
const compiled = fixture.debugElement.nativeElement;
|
const compiled = fixture.debugElement.nativeElement;
|
||||||
expect(compiled.querySelector('h1').textContent).toMatch(/app/i);
|
expect(compiled.querySelector('h1').textContent).toContain('Welcome to app!');
|
||||||
}));
|
}));
|
||||||
});
|
});
|
@ -0,0 +1,15 @@
|
|||||||
|
import { Component } from '@angular/core';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'app-root',
|
||||||
|
templateUrl: './app.component.html',
|
||||||
|
styleUrls: ['./app.component.css']
|
||||||
|
})
|
||||||
|
export class AppComponent {
|
||||||
|
actionName = 'Go for it';
|
||||||
|
isSpecial = true;
|
||||||
|
itemClearance = true;
|
||||||
|
resetClasses = 'new-class';
|
||||||
|
canSave = true;
|
||||||
|
|
||||||
|
}
|
@ -1,8 +1,10 @@
|
|||||||
import { BrowserModule } from '@angular/platform-browser';
|
import { BrowserModule } from '@angular/platform-browser';
|
||||||
import { NgModule } from '@angular/core';
|
import { NgModule } from '@angular/core';
|
||||||
|
|
||||||
|
|
||||||
import { AppComponent } from './app.component';
|
import { AppComponent } from './app.component';
|
||||||
|
|
||||||
|
|
||||||
@NgModule({
|
@NgModule({
|
||||||
declarations: [
|
declarations: [
|
||||||
AppComponent
|
AppComponent
|
@ -2,7 +2,7 @@
|
|||||||
<html lang="en">
|
<html lang="en">
|
||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8">
|
<meta charset="utf-8">
|
||||||
<title>CliHelloWorldIvy</title>
|
<title>AttributeBinding</title>
|
||||||
<base href="/">
|
<base href="/">
|
||||||
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
12
aio/content/examples/attribute-binding/src/main.ts
Normal file
12
aio/content/examples/attribute-binding/src/main.ts
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
import { enableProdMode } from '@angular/core';
|
||||||
|
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
|
||||||
|
|
||||||
|
import { AppModule } from './app/app.module';
|
||||||
|
import { environment } from './environments/environment';
|
||||||
|
|
||||||
|
if (environment.production) {
|
||||||
|
enableProdMode();
|
||||||
|
}
|
||||||
|
|
||||||
|
platformBrowserDynamic().bootstrapModule(AppModule)
|
||||||
|
.catch(err => console.log(err));
|
10
aio/content/examples/attribute-binding/stackblitz.json
Normal file
10
aio/content/examples/attribute-binding/stackblitz.json
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
{
|
||||||
|
"description": "Attribute Binding",
|
||||||
|
"files": [
|
||||||
|
"!**/*.d.ts",
|
||||||
|
"!**/*.js",
|
||||||
|
"!**/*.[1,2].*"
|
||||||
|
],
|
||||||
|
"file": "src/app/app.component.ts",
|
||||||
|
"tags": ["Attribute Binding"]
|
||||||
|
}
|
@ -2,30 +2,31 @@
|
|||||||
|
|
||||||
import { browser, element, by } from 'protractor';
|
import { browser, element, by } from 'protractor';
|
||||||
|
|
||||||
describe('Attribute directives', function () {
|
describe('Attribute directives', () => {
|
||||||
|
|
||||||
let _title = 'My First Attribute Directive';
|
let _title = 'My First Attribute Directive';
|
||||||
|
|
||||||
beforeAll(function () {
|
beforeAll(() => {
|
||||||
browser.get('');
|
browser.get('');
|
||||||
});
|
});
|
||||||
|
|
||||||
it(`should display correct title: ${_title}`, function () {
|
it(`should display correct title: ${_title}`, () => {
|
||||||
expect(element(by.css('h1')).getText()).toEqual(_title);
|
expect(element(by.css('h1')).getText()).toEqual(_title);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should be able to select green highlight', function () {
|
it('should be able to select green highlight', () => {
|
||||||
let highlightedEle = element(by.cssContainingText('p', 'Highlight me!'));
|
const highlightedEle = element(by.cssContainingText('p', 'Highlight me!'));
|
||||||
let lightGreen = 'rgba(144, 238, 144, 1)';
|
const lightGreen = 'rgba(144, 238, 144, 1)';
|
||||||
|
const getBgColor = () => highlightedEle.getCssValue('background-color');
|
||||||
|
|
||||||
expect(highlightedEle.getCssValue('background-color')).not.toEqual(lightGreen);
|
expect(highlightedEle.getCssValue('background-color')).not.toEqual(lightGreen);
|
||||||
// let greenRb = element(by.cssContainingText('input', 'Green'));
|
|
||||||
let greenRb = element.all(by.css('input')).get(0);
|
|
||||||
greenRb.click().then(function() {
|
|
||||||
// TypeScript Todo: find the right type for highlightedEle
|
|
||||||
browser.actions().mouseMove(highlightedEle as any).perform();
|
|
||||||
expect(highlightedEle.getCssValue('background-color')).toEqual(lightGreen);
|
|
||||||
});
|
|
||||||
|
|
||||||
|
const greenRb = element.all(by.css('input')).get(0);
|
||||||
|
greenRb.click();
|
||||||
|
browser.actions().mouseMove(highlightedEle).perform();
|
||||||
|
|
||||||
|
// Wait for up to 2s for the background color to be updated,
|
||||||
|
// to account for slow environments (e.g. CI).
|
||||||
|
browser.wait(() => highlightedEle.getCssValue('background-color').then(c => c === lightGreen), 2000);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
76
aio/content/examples/binding-syntax/e2e/src/app.e2e-spec.ts
Normal file
76
aio/content/examples/binding-syntax/e2e/src/app.e2e-spec.ts
Normal file
@ -0,0 +1,76 @@
|
|||||||
|
import { browser, element, by } from 'protractor';
|
||||||
|
import { logging } from 'selenium-webdriver';
|
||||||
|
|
||||||
|
describe('Binding syntax e2e tests', () => {
|
||||||
|
|
||||||
|
beforeEach(function () {
|
||||||
|
browser.get('');
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
// helper function used to test what's logged to the console
|
||||||
|
async function logChecker(button, contents) {
|
||||||
|
const logs = await browser.manage().logs().get(logging.Type.BROWSER);
|
||||||
|
const message = logs.filter(({ message }) => message.indexOf(contents) !== -1 ? true : false);
|
||||||
|
expect(message.length).toBeGreaterThan(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
it('should display Binding syntax', function () {
|
||||||
|
expect(element(by.css('h1')).getText()).toEqual('Binding syntax');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should display Save button', function () {
|
||||||
|
expect(element.all(by.css('button')).get(0).getText()).toBe('Save');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should display HTML attributes and DOM properties', function () {
|
||||||
|
expect(element.all(by.css('h2')).get(1).getText()).toBe('HTML attributes and DOM properties');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should display 1. Use the inspector...', function () {
|
||||||
|
expect(element.all(by.css('p')).get(0).getText()).toContain('1. Use the inspector');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should display Disabled property vs. attribute', function () {
|
||||||
|
expect(element.all(by.css('h3')).get(0).getText()).toBe('Disabled property vs. attribute');
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
it('should log a message including Sarah', async () => {
|
||||||
|
let attributeButton = element.all(by.css('button')).get(1);
|
||||||
|
await attributeButton.click();
|
||||||
|
const contents = 'Sarah';
|
||||||
|
logChecker(attributeButton, contents);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should log a message including Sarah for DOM property', async () => {
|
||||||
|
let DOMPropertyButton = element.all(by.css('button')).get(2);
|
||||||
|
await DOMPropertyButton.click();
|
||||||
|
const contents = 'Sarah';
|
||||||
|
logChecker(DOMPropertyButton, contents);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should log a message including Sally for DOM property', async () => {
|
||||||
|
let DOMPropertyButton = element.all(by.css('button')).get(2);
|
||||||
|
let input = element(by.css('input'));
|
||||||
|
input.sendKeys('Sally');
|
||||||
|
await DOMPropertyButton.click();
|
||||||
|
const contents = 'Sally';
|
||||||
|
logChecker(DOMPropertyButton, contents);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should log a message that Test Button works', async () => {
|
||||||
|
let testButton = element.all(by.css('button')).get(3);
|
||||||
|
await testButton.click();
|
||||||
|
const contents = 'Test';
|
||||||
|
logChecker(testButton, contents);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should toggle Test Button disabled', async () => {
|
||||||
|
let toggleButton = element.all(by.css('button')).get(4);
|
||||||
|
await toggleButton.click();
|
||||||
|
const contents = 'true';
|
||||||
|
logChecker(toggleButton, contents);
|
||||||
|
});
|
||||||
|
});
|
@ -0,0 +1,3 @@
|
|||||||
|
div {
|
||||||
|
padding: .25rem 0;
|
||||||
|
}
|
@ -0,0 +1,45 @@
|
|||||||
|
|
||||||
|
<div>
|
||||||
|
<h1>Binding syntax</h1>
|
||||||
|
<hr />
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<h2>Button disabled state bound to isUnchanged property</h2>
|
||||||
|
<!-- #docregion disabled-button -->
|
||||||
|
<!-- Bind button disabled state to `isUnchanged` property -->
|
||||||
|
<button [disabled]="isUnchanged">Save</button>
|
||||||
|
<!-- #enddocregion disabled-button -->
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<hr />
|
||||||
|
|
||||||
|
<div (keyup)="0">
|
||||||
|
<h2>HTML attributes and DOM properties</h2>
|
||||||
|
<p>1. Use the inspector to see the HTML attribute and DOM property values. Click the buttons to log values to the console.</p>
|
||||||
|
|
||||||
|
<label>HTML Attribute Initializes to "Sarah":
|
||||||
|
<input type="text" value="Sarah" #bindingInput></label>
|
||||||
|
<div>
|
||||||
|
<button (click)="getHTMLAttributeValue()">Get HTML attribute value</button> Won't change.
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<button (click)="getDOMPropertyValue()">Get DOM property value</button> Changeable. Angular works with these.
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<p>2. Change the name in the input and click the buttons again.</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<hr />
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<h3>Disabled property vs. attribute</h3>
|
||||||
|
<p>Use the inspector to see the Test Button work and its disabled property toggle.</p>
|
||||||
|
<div>
|
||||||
|
<button id="testButton" (click)="working()">Test Button</button>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<button (click)="toggleDisabled()">Toggle disabled property for Test Button</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
@ -0,0 +1,27 @@
|
|||||||
|
import { TestBed, async } from '@angular/core/testing';
|
||||||
|
import { AppComponent } from './app.component';
|
||||||
|
describe('AppComponent', () => {
|
||||||
|
beforeEach(async(() => {
|
||||||
|
TestBed.configureTestingModule({
|
||||||
|
declarations: [
|
||||||
|
AppComponent
|
||||||
|
],
|
||||||
|
}).compileComponents();
|
||||||
|
}));
|
||||||
|
it('should create the app', async(() => {
|
||||||
|
const fixture = TestBed.createComponent(AppComponent);
|
||||||
|
const app = fixture.debugElement.componentInstance;
|
||||||
|
expect(app).toBeTruthy();
|
||||||
|
}));
|
||||||
|
it(`should have as title 'app'`, async(() => {
|
||||||
|
const fixture = TestBed.createComponent(AppComponent);
|
||||||
|
const app = fixture.debugElement.componentInstance;
|
||||||
|
expect(app.title).toEqual('app');
|
||||||
|
}));
|
||||||
|
it('should render title in a h1 tag', async(() => {
|
||||||
|
const fixture = TestBed.createComponent(AppComponent);
|
||||||
|
fixture.detectChanges();
|
||||||
|
const compiled = fixture.debugElement.nativeElement;
|
||||||
|
expect(compiled.querySelector('h1').textContent).toContain('Welcome to app!');
|
||||||
|
}));
|
||||||
|
});
|
33
aio/content/examples/binding-syntax/src/app/app.component.ts
Normal file
33
aio/content/examples/binding-syntax/src/app/app.component.ts
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
import { Component, ViewChild, ElementRef } from '@angular/core';
|
||||||
|
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'app-root',
|
||||||
|
templateUrl: './app.component.html',
|
||||||
|
styleUrls: ['./app.component.css']
|
||||||
|
})
|
||||||
|
export class AppComponent {
|
||||||
|
|
||||||
|
@ViewChild('bindingInput', { static: false }) bindingInput: ElementRef;
|
||||||
|
|
||||||
|
isUnchanged = true;
|
||||||
|
|
||||||
|
getHTMLAttributeValue(): any {
|
||||||
|
console.warn('HTML attribute value: ' + this.bindingInput.nativeElement.getAttribute('value'));
|
||||||
|
}
|
||||||
|
|
||||||
|
getDOMPropertyValue(): any {
|
||||||
|
console.warn('DOM property value: ' + this.bindingInput.nativeElement.value);
|
||||||
|
}
|
||||||
|
|
||||||
|
working(): any {
|
||||||
|
console.warn('Test Button works!');
|
||||||
|
}
|
||||||
|
|
||||||
|
toggleDisabled(): any {
|
||||||
|
|
||||||
|
let testButton = <HTMLInputElement> document.getElementById('testButton');
|
||||||
|
testButton.disabled = !testButton.disabled;
|
||||||
|
console.warn(testButton.disabled);
|
||||||
|
}
|
||||||
|
}
|
18
aio/content/examples/binding-syntax/src/app/app.module.ts
Normal file
18
aio/content/examples/binding-syntax/src/app/app.module.ts
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
import { BrowserModule } from '@angular/platform-browser';
|
||||||
|
import { NgModule } from '@angular/core';
|
||||||
|
|
||||||
|
|
||||||
|
import { AppComponent } from './app.component';
|
||||||
|
|
||||||
|
|
||||||
|
@NgModule({
|
||||||
|
declarations: [
|
||||||
|
AppComponent
|
||||||
|
],
|
||||||
|
imports: [
|
||||||
|
BrowserModule
|
||||||
|
],
|
||||||
|
providers: [],
|
||||||
|
bootstrap: [AppComponent]
|
||||||
|
})
|
||||||
|
export class AppModule { }
|
14
aio/content/examples/binding-syntax/src/index.html
Normal file
14
aio/content/examples/binding-syntax/src/index.html
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
<!-- #docregion -->
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<base href="/">
|
||||||
|
<title>Angular binding syntax example</title>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<app-root>Loading...</app-root>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
<!-- #enddocregion -->
|
12
aio/content/examples/binding-syntax/src/main.ts
Normal file
12
aio/content/examples/binding-syntax/src/main.ts
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
// #docregion
|
||||||
|
import { enableProdMode } from '@angular/core';
|
||||||
|
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
|
||||||
|
|
||||||
|
import { AppModule } from './app/app.module';
|
||||||
|
import { environment } from './environments/environment';
|
||||||
|
|
||||||
|
if (environment.production) {
|
||||||
|
enableProdMode();
|
||||||
|
}
|
||||||
|
|
||||||
|
platformBrowserDynamic().bootstrapModule(AppModule);
|
10
aio/content/examples/binding-syntax/stackblitz.json
Normal file
10
aio/content/examples/binding-syntax/stackblitz.json
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
{
|
||||||
|
"description": "Binding Syntax",
|
||||||
|
"files": [
|
||||||
|
"!**/*.d.ts",
|
||||||
|
"!**/*.js",
|
||||||
|
"!**/*.[1,2].*"
|
||||||
|
],
|
||||||
|
"file": "src/app/app.component.ts",
|
||||||
|
"tags": ["Binding Syntax"]
|
||||||
|
}
|
@ -9,6 +9,6 @@ describe('feature-modules App', () => {
|
|||||||
|
|
||||||
it('should display message saying app works', () => {
|
it('should display message saying app works', () => {
|
||||||
page.navigateTo();
|
page.navigateTo();
|
||||||
expect(page.getParagraphText()).toEqual('app works!');
|
expect(page.getTitleText()).toEqual('app works!');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -0,0 +1,78 @@
|
|||||||
|
'use strict';
|
||||||
|
|
||||||
|
import { browser, element, by } from 'protractor';
|
||||||
|
|
||||||
|
describe('Built-in Directives', function () {
|
||||||
|
|
||||||
|
beforeAll(function () {
|
||||||
|
browser.get('');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should have title Built-in Directives', function () {
|
||||||
|
let title = element.all(by.css('h1')).get(0);
|
||||||
|
expect(title.getText()).toEqual('Built-in Directives');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should change first Teapot header', async () => {
|
||||||
|
let firstLabel = element.all(by.css('p')).get(0);
|
||||||
|
let firstInput = element.all(by.css('input')).get(0);
|
||||||
|
|
||||||
|
expect(firstLabel.getText()).toEqual('Current item name: Teapot');
|
||||||
|
firstInput.sendKeys('abc');
|
||||||
|
expect(firstLabel.getText()).toEqual('Current item name: Teapotabc');
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
it('should modify sentence when modified checkbox checked', function () {
|
||||||
|
let modifiedChkbxLabel = element.all(by.css('input[type="checkbox"]')).get(1);
|
||||||
|
let modifiedSentence = element.all(by.css('div')).get(1);
|
||||||
|
|
||||||
|
modifiedChkbxLabel.click();
|
||||||
|
expect(modifiedSentence.getText()).toContain('modified');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should modify sentence when normal checkbox checked', function () {
|
||||||
|
let normalChkbxLabel = element.all(by.css('input[type="checkbox"]')).get(4);
|
||||||
|
let normalSentence = element.all(by.css('div')).get(7);
|
||||||
|
|
||||||
|
normalChkbxLabel.click();
|
||||||
|
expect(normalSentence.getText()).toContain('normal weight and, extra large');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should toggle app-item-detail', function () {
|
||||||
|
let toggleButton = element.all(by.css('button')).get(3);
|
||||||
|
let toggledDiv = element.all(by.css('app-item-detail')).get(0);
|
||||||
|
|
||||||
|
toggleButton.click();
|
||||||
|
expect(toggledDiv.isDisplayed()).toBe(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should hide app-item-detail', function () {
|
||||||
|
let hiddenMessage = element.all(by.css('p')).get(11);
|
||||||
|
let hiddenDiv = element.all(by.css('app-item-detail')).get(2);
|
||||||
|
|
||||||
|
expect(hiddenMessage.getText()).toContain('in the DOM');
|
||||||
|
expect(hiddenDiv.isDisplayed()).toBe(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should have 10 lists each containing the string Teapot', function () {
|
||||||
|
let listDiv = element.all(by.cssContainingText('.box', 'Teapot'));
|
||||||
|
expect(listDiv.count()).toBe(10);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should switch case', function () {
|
||||||
|
let tvRadioButton = element.all(by.css('input[type="radio"]')).get(3);
|
||||||
|
let tvDiv = element(by.css('app-lost-item'));
|
||||||
|
|
||||||
|
let fishbowlRadioButton = element.all(by.css('input[type="radio"]')).get(4);
|
||||||
|
let fishbowlDiv = element(by.css('app-unknown-item'));
|
||||||
|
|
||||||
|
tvRadioButton.click();
|
||||||
|
expect(tvDiv.getText()).toContain('Television');
|
||||||
|
fishbowlRadioButton.click();
|
||||||
|
expect(fishbowlDiv.getText()).toContain('mysterious');
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
});
|
||||||
|
|
@ -0,0 +1,75 @@
|
|||||||
|
|
||||||
|
button {
|
||||||
|
font-size: 100%;
|
||||||
|
margin: 0 2px;
|
||||||
|
}
|
||||||
|
|
||||||
|
div[ng-reflect-ng-switch], app-unknown-item {
|
||||||
|
margin: .5rem 0;
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
|
#noTrackByCnt,
|
||||||
|
#withTrackByCnt {
|
||||||
|
color: darkred;
|
||||||
|
max-width: 450px;
|
||||||
|
margin: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
img {
|
||||||
|
height: 100px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.box {
|
||||||
|
border: 1px solid black;
|
||||||
|
padding: 6px;
|
||||||
|
max-width: 450px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.child-div {
|
||||||
|
margin-left: 1em;
|
||||||
|
font-weight: normal;
|
||||||
|
}
|
||||||
|
|
||||||
|
.context {
|
||||||
|
margin-left: 1em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hidden {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.parent-div {
|
||||||
|
margin-top: 1em;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
.course {
|
||||||
|
font-weight: bold;
|
||||||
|
font-size: x-large;
|
||||||
|
}
|
||||||
|
|
||||||
|
.helpful {
|
||||||
|
color: red;
|
||||||
|
}
|
||||||
|
|
||||||
|
.saveable {
|
||||||
|
color: limegreen;
|
||||||
|
}
|
||||||
|
|
||||||
|
.study,
|
||||||
|
.modified {
|
||||||
|
font-family: "Brush Script MT";
|
||||||
|
font-size: 2rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.toe {
|
||||||
|
margin-left: 1em;
|
||||||
|
font-style: italic;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
.to-toc {
|
||||||
|
margin-top: 10px;
|
||||||
|
display: block;
|
||||||
|
}
|
@ -0,0 +1,253 @@
|
|||||||
|
<h1>Built-in Directives</h1>
|
||||||
|
|
||||||
|
<h2>Built-in attribute directives</h2>
|
||||||
|
|
||||||
|
<h3 id="ngModel">NgModel (two-way) Binding</h3>
|
||||||
|
|
||||||
|
<fieldset><h4>NgModel examples</h4>
|
||||||
|
<p>Current item name: {{currentItem.name}}</p>
|
||||||
|
<p>
|
||||||
|
<!-- #docregion without-NgModel -->
|
||||||
|
<label for="without">without NgModel:</label>
|
||||||
|
<input [value]="currentItem.name" (input)="currentItem.name=$event.target.value" id="without">
|
||||||
|
<!-- #enddocregion without-NgModel -->
|
||||||
|
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
<!-- #docregion NgModel-1 -->
|
||||||
|
<label for="example-ngModel">[(ngModel)]:</label>
|
||||||
|
<input [(ngModel)]="currentItem.name" id="example-ngModel">
|
||||||
|
<!-- #enddocregion NgModel-1 -->
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
<label for="example-bindon">bindon-ngModel: </label>
|
||||||
|
<input bindon-ngModel="currentItem.name" id="example-bindon">
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
<!-- #docregion NgModelChange -->
|
||||||
|
<label for="example-change">(ngModelChange)="...name=$event":</label>
|
||||||
|
<input [ngModel]="currentItem.name" (ngModelChange)="currentItem.name=$event" id="example-change">
|
||||||
|
<!-- #enddocregion NgModelChange -->
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
<label for="example-uppercase">(ngModelChange)="setUppercaseName($event)"
|
||||||
|
<!-- #docregion uppercase -->
|
||||||
|
<input [ngModel]="currentItem.name" (ngModelChange)="setUppercaseName($event)" id="example-uppercase">
|
||||||
|
<!-- #enddocregion uppercase -->
|
||||||
|
</label>
|
||||||
|
</p>
|
||||||
|
</fieldset>
|
||||||
|
|
||||||
|
<hr><h2 id="ngClass">NgClass Binding</h2>
|
||||||
|
|
||||||
|
<p>currentClasses is {{currentClasses | json}}</p>
|
||||||
|
<!-- #docregion NgClass-1 -->
|
||||||
|
<div [ngClass]="currentClasses">This div is initially saveable, unchanged, and special.</div>
|
||||||
|
<!-- #enddocregion NgClass-1 -->
|
||||||
|
<ul>
|
||||||
|
<li>
|
||||||
|
<label for="saveable">saveable</label>
|
||||||
|
<input type="checkbox" [(ngModel)]="canSave" id="saveable">
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<label for="modified">modified:</label>
|
||||||
|
<input type="checkbox" [value]="!isUnchanged" (change)="isUnchanged=!isUnchanged" id="modified"></li>
|
||||||
|
<li>
|
||||||
|
<label for="special">special: <input type="checkbox" [(ngModel)]="isSpecial" id="special"></label>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
<button (click)="setCurrentClasses()">Refresh currentClasses</button>
|
||||||
|
|
||||||
|
<div [ngClass]="currentClasses">
|
||||||
|
This div should be {{ canSave ? "": "not"}} saveable,
|
||||||
|
{{ isUnchanged ? "unchanged" : "modified" }} and
|
||||||
|
{{ isSpecial ? "": "not"}} special after clicking "Refresh".</div>
|
||||||
|
<br><br>
|
||||||
|
<!-- #docregion special-div -->
|
||||||
|
<!-- toggle the "special" class on/off with a property -->
|
||||||
|
<div [ngClass]="isSpecial ? 'special' : ''">This div is special</div>
|
||||||
|
<!-- #enddocregion special-div -->
|
||||||
|
<div class="helpful study course">Helpful study course</div>
|
||||||
|
<div [ngClass]="{'helpful':false, 'study':true, 'course':true}">Study course</div>
|
||||||
|
|
||||||
|
|
||||||
|
<!-- NgStyle binding -->
|
||||||
|
<hr><h3>NgStyle Binding</h3>
|
||||||
|
<!-- #docregion without-ng-style -->
|
||||||
|
<div [style.font-size]="isSpecial ? 'x-large' : 'smaller'">
|
||||||
|
This div is x-large or smaller.
|
||||||
|
</div>
|
||||||
|
<!-- #enddocregion without-ng-style -->
|
||||||
|
|
||||||
|
|
||||||
|
<h4>[ngStyle] binding to currentStyles - CSS property names</h4>
|
||||||
|
<p>currentStyles is {{currentStyles | json}}</p>
|
||||||
|
|
||||||
|
<!-- #docregion NgStyle-2 -->
|
||||||
|
<div [ngStyle]="currentStyles">
|
||||||
|
This div is initially italic, normal weight, and extra large (24px).
|
||||||
|
</div>
|
||||||
|
<!-- #enddocregion NgStyle-2 -->
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<br>
|
||||||
|
<label>italic: <input type="checkbox" [(ngModel)]="canSave"></label> |
|
||||||
|
<label>normal: <input type="checkbox" [(ngModel)]="isUnchanged"></label> |
|
||||||
|
<label>xlarge: <input type="checkbox" [(ngModel)]="isSpecial"></label>
|
||||||
|
<button (click)="setCurrentStyles()">Refresh currentStyles</button>
|
||||||
|
<br><br>
|
||||||
|
<div [ngStyle]="currentStyles">
|
||||||
|
This div should be {{ canSave ? "italic": "plain"}},
|
||||||
|
{{ isUnchanged ? "normal weight" : "bold" }} and,
|
||||||
|
{{ isSpecial ? "extra large": "normal size"}} after clicking "Refresh".</div>
|
||||||
|
|
||||||
|
<hr>
|
||||||
|
<h2>Built-in structural directives</h2>
|
||||||
|
<h3 id="ngIf">NgIf Binding</h3>
|
||||||
|
<div>
|
||||||
|
<p>If isActive is true, app-item-detail will render: </p>
|
||||||
|
<!-- #docregion NgIf-1 -->
|
||||||
|
<app-item-detail *ngIf="isActive" [item]="item"></app-item-detail>
|
||||||
|
<!-- #enddocregion NgIf-1 -->
|
||||||
|
|
||||||
|
<button (click)="isActiveToggle()">Toggle app-item-detail</button>
|
||||||
|
</div>
|
||||||
|
<p>If currentCustomer isn't null, say hello to Laura:</p>
|
||||||
|
<!-- #docregion NgIf-2 -->
|
||||||
|
<div *ngIf="currentCustomer">Hello, {{currentCustomer.name}}</div>
|
||||||
|
<!-- #enddocregion NgIf-2 -->
|
||||||
|
<p>nullCustomer is null by default. NgIf guards against null. Give it a value to show it:</p>
|
||||||
|
<!-- #docregion NgIf-2b -->
|
||||||
|
<div *ngIf="nullCustomer">Hello, <span>{{nullCustomer}}</span></div>
|
||||||
|
<!-- #enddocregion NgIf-2b -->
|
||||||
|
<button (click)="giveNullCustomerValue()">Give nullCustomer a value</button>
|
||||||
|
|
||||||
|
|
||||||
|
<h4>NgIf binding with template (no *)</h4>
|
||||||
|
|
||||||
|
<ng-template [ngIf]="currentItem">Add {{currentItem.name}} with template</ng-template>
|
||||||
|
<hr>
|
||||||
|
|
||||||
|
<h4>Show/hide vs. NgIf</h4>
|
||||||
|
<!-- #docregion NgIf-3 -->
|
||||||
|
<!-- isSpecial is true -->
|
||||||
|
<div [class.hidden]="!isSpecial">Show with class</div>
|
||||||
|
<div [class.hidden]="isSpecial">Hide with class</div>
|
||||||
|
|
||||||
|
<p>ItemDetail is in the DOM but hidden</p>
|
||||||
|
<app-item-detail [class.hidden]="isSpecial"></app-item-detail>
|
||||||
|
|
||||||
|
<div [style.display]="isSpecial ? 'block' : 'none'">Show with style</div>
|
||||||
|
<div [style.display]="isSpecial ? 'none' : 'block'">Hide with style</div>
|
||||||
|
<!-- #enddocregion NgIf-3 -->
|
||||||
|
|
||||||
|
|
||||||
|
<hr>
|
||||||
|
<h2 id="ngFor">NgFor Binding</h2>
|
||||||
|
|
||||||
|
<div class="box">
|
||||||
|
<!-- #docregion NgFor-1, NgFor-1-2 -->
|
||||||
|
<div *ngFor="let item of items">{{item.name}}</div>
|
||||||
|
<!-- #enddocregion NgFor-1, NgFor-1-2 -->
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<p>*ngFor with ItemDetailComponent element</p>
|
||||||
|
<div class="box">
|
||||||
|
<!-- #docregion NgFor-2, NgFor-1-2 -->
|
||||||
|
<app-item-detail *ngFor="let item of items" [item]="item"></app-item-detail>
|
||||||
|
<!-- #enddocregion NgFor-2, NgFor-1-2 -->
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
<h4 id="ngFor-index">*ngFor with index</h4>
|
||||||
|
<p>with <i>semi-colon</i> separator</p>
|
||||||
|
<div class="box">
|
||||||
|
<!-- #docregion NgFor-3 -->
|
||||||
|
<div *ngFor="let item of items; let i=index">{{i + 1}} - {{item.name}}</div>
|
||||||
|
<!-- #enddocregion NgFor-3 -->
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<p>with <i>comma</i> separator</p>
|
||||||
|
<div class="box">
|
||||||
|
<div *ngFor="let item of items, let i=index">{{i + 1}} - {{item.name}}</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<h4 id="ngFor-trackBy">*ngFor trackBy</h4>
|
||||||
|
<button (click)="resetList()">Reset items</button>
|
||||||
|
<button (click)="changeIds()">Change ids</button>
|
||||||
|
<button (click)="clearTrackByCounts()">Clear counts</button>
|
||||||
|
|
||||||
|
<p><i>without</i> trackBy</p>
|
||||||
|
<div class="box">
|
||||||
|
<div #noTrackBy *ngFor="let item of items">({{item.id}}) {{item.name}}</div>
|
||||||
|
|
||||||
|
<div id="noTrackByCnt" *ngIf="itemsNoTrackByCount" >
|
||||||
|
Item DOM elements change #{{itemsNoTrackByCount}} without trackBy
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<p>with trackBy</p>
|
||||||
|
<div class="box">
|
||||||
|
<div #withTrackBy *ngFor="let item of items; trackBy: trackByItems">({{item.id}}) {{item.name}}</div>
|
||||||
|
|
||||||
|
<div id="withTrackByCnt" *ngIf="itemsWithTrackByCount">
|
||||||
|
Item DOM elements change #{{itemsWithTrackByCount}} with trackBy
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<br><br><br>
|
||||||
|
|
||||||
|
<p>with trackBy and <i>semi-colon</i> separator</p>
|
||||||
|
<div class="box">
|
||||||
|
<!-- #docregion trackBy -->
|
||||||
|
<div *ngFor="let item of items; trackBy: trackByItems">
|
||||||
|
({{item.id}}) {{item.name}}
|
||||||
|
</div>
|
||||||
|
<!-- #enddocregion trackBy -->
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<p>with trackBy and <i>comma</i> separator</p>
|
||||||
|
<div class="box">
|
||||||
|
<div *ngFor="let item of items, trackBy: trackByItems">({{item.id}}) {{item.name}}</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<p>with trackBy and <i>space</i> separator</p>
|
||||||
|
<div class="box">
|
||||||
|
<div *ngFor="let item of items trackBy: trackByItems">({{item.id}}) {{item.name}}</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<p>with <i>generic</i> trackById function</p>
|
||||||
|
<div class="box">
|
||||||
|
<div *ngFor="let item of items, trackBy: trackById">({{item.id}}) {{item.name}}</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<hr><h2>NgSwitch Binding</h2>
|
||||||
|
|
||||||
|
<p>Pick your favorite item</p>
|
||||||
|
<div>
|
||||||
|
<label *ngFor="let i of items">
|
||||||
|
<div><input type="radio" name="items" [(ngModel)]="currentItem" [value]="i">{{i.name}}
|
||||||
|
</div>
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- #docregion NgSwitch -->
|
||||||
|
<div [ngSwitch]="currentItem.feature">
|
||||||
|
<app-stout-item *ngSwitchCase="'stout'" [item]="currentItem"></app-stout-item>
|
||||||
|
<app-device-item *ngSwitchCase="'slim'" [item]="currentItem"></app-device-item>
|
||||||
|
<app-lost-item *ngSwitchCase="'vintage'" [item]="currentItem"></app-lost-item>
|
||||||
|
<app-best-item *ngSwitchCase="'bright'" [item]="currentItem"></app-best-item>
|
||||||
|
<!-- #enddocregion NgSwitch -->
|
||||||
|
<!-- #docregion NgSwitch-div -->
|
||||||
|
<div *ngSwitchCase="'bright'"> Are you as bright as {{currentItem.name}}?</div>
|
||||||
|
<!-- #enddocregion NgSwitch-div -->
|
||||||
|
<!-- #docregion NgSwitch -->
|
||||||
|
<app-unknown-item *ngSwitchDefault [item]="currentItem"></app-unknown-item>
|
||||||
|
</div>
|
||||||
|
<!-- #enddocregion NgSwitch -->
|
||||||
|
|
@ -0,0 +1,115 @@
|
|||||||
|
import { Component, OnInit } from '@angular/core';
|
||||||
|
import { Item } from './item';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'app-root',
|
||||||
|
templateUrl: './app.component.html',
|
||||||
|
styleUrls: ['./app.component.css']
|
||||||
|
})
|
||||||
|
export class AppComponent implements OnInit {
|
||||||
|
|
||||||
|
canSave = true;
|
||||||
|
isSpecial = true;
|
||||||
|
isUnchanged = true;
|
||||||
|
|
||||||
|
isActive = true;
|
||||||
|
nullCustomer = null;
|
||||||
|
currentCustomer = {
|
||||||
|
name: 'Laura'
|
||||||
|
};
|
||||||
|
|
||||||
|
item: Item; // defined to demonstrate template context precedence
|
||||||
|
items: Item[];
|
||||||
|
|
||||||
|
currentItem: Item;
|
||||||
|
|
||||||
|
|
||||||
|
// trackBy change counting
|
||||||
|
itemsNoTrackByCount = 0;
|
||||||
|
itemsWithTrackByCount = 0;
|
||||||
|
itemsWithTrackByCountReset = 0;
|
||||||
|
itemIdIncrement = 1;
|
||||||
|
|
||||||
|
ngOnInit() {
|
||||||
|
this.resetItems();
|
||||||
|
this.setCurrentClasses();
|
||||||
|
this.setCurrentStyles();
|
||||||
|
this.itemsNoTrackByCount = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
setUppercaseName(name: string) {
|
||||||
|
this.currentItem.name = name.toUpperCase();
|
||||||
|
}
|
||||||
|
|
||||||
|
// #docregion setClasses
|
||||||
|
currentClasses: {};
|
||||||
|
setCurrentClasses() {
|
||||||
|
// CSS classes: added/removed per current state of component properties
|
||||||
|
this.currentClasses = {
|
||||||
|
'saveable': this.canSave,
|
||||||
|
'modified': !this.isUnchanged,
|
||||||
|
'special': this.isSpecial
|
||||||
|
};
|
||||||
|
}
|
||||||
|
// #enddocregion setClasses
|
||||||
|
|
||||||
|
// #docregion setStyles
|
||||||
|
currentStyles: {};
|
||||||
|
setCurrentStyles() {
|
||||||
|
// CSS styles: set per current state of component properties
|
||||||
|
this.currentStyles = {
|
||||||
|
'font-style': this.canSave ? 'italic' : 'normal',
|
||||||
|
'font-weight': !this.isUnchanged ? 'bold' : 'normal',
|
||||||
|
'font-size': this.isSpecial ? '24px' : '12px'
|
||||||
|
};
|
||||||
|
}
|
||||||
|
// #enddocregion setStyles
|
||||||
|
|
||||||
|
isActiveToggle() {
|
||||||
|
this.isActive = !this.isActive;
|
||||||
|
}
|
||||||
|
|
||||||
|
giveNullCustomerValue() {
|
||||||
|
!(this.nullCustomer = null) ? (this.nullCustomer = 'Kelly') : (this.nullCustomer = null);
|
||||||
|
}
|
||||||
|
|
||||||
|
resetNullItem() {
|
||||||
|
this.nullCustomer = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
resetItems() {
|
||||||
|
this.items = Item.items.map(item => item.clone());
|
||||||
|
this.currentItem = this.items[0];
|
||||||
|
this.item = this.currentItem;
|
||||||
|
}
|
||||||
|
|
||||||
|
resetList() {
|
||||||
|
this.resetItems()
|
||||||
|
this.itemsWithTrackByCountReset = 0;
|
||||||
|
this.itemsNoTrackByCount = ++this.itemsNoTrackByCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
changeIds() {
|
||||||
|
|
||||||
|
this.items.forEach(i => i.id += 1 * this.itemIdIncrement);
|
||||||
|
this.itemsWithTrackByCountReset = -1;
|
||||||
|
this.itemsNoTrackByCount = ++this.itemsNoTrackByCount;
|
||||||
|
this.itemsWithTrackByCount = ++this.itemsWithTrackByCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
clearTrackByCounts() {
|
||||||
|
this.resetItems();
|
||||||
|
this.itemsNoTrackByCount = 0;
|
||||||
|
this.itemsWithTrackByCount = 0;
|
||||||
|
this.itemIdIncrement = 1;
|
||||||
|
}
|
||||||
|
// #docregion trackByItems
|
||||||
|
trackByItems(index: number, item: Item): number { return item.id; }
|
||||||
|
// #enddocregion trackByItems
|
||||||
|
|
||||||
|
trackById(index: number, item: any): number { return item['id']; }
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -0,0 +1,34 @@
|
|||||||
|
import { BrowserModule } from '@angular/platform-browser';
|
||||||
|
import { NgModule } from '@angular/core';
|
||||||
|
// #docregion import-forms-module
|
||||||
|
import { FormsModule } from '@angular/forms'; // <--- JavaScript import from Angular
|
||||||
|
// #enddocregion import-forms-module
|
||||||
|
|
||||||
|
|
||||||
|
import { AppComponent } from './app.component';
|
||||||
|
import { ItemDetailComponent } from './item-detail/item-detail.component';
|
||||||
|
import { ItemSwitchComponents } from './item-switch.component';
|
||||||
|
|
||||||
|
|
||||||
|
// #docregion import-forms-module
|
||||||
|
@NgModule({
|
||||||
|
// #enddocregion import-forms-module
|
||||||
|
declarations: [
|
||||||
|
AppComponent,
|
||||||
|
ItemDetailComponent,
|
||||||
|
ItemSwitchComponents
|
||||||
|
],
|
||||||
|
// #docregion import-forms-module
|
||||||
|
|
||||||
|
imports: [
|
||||||
|
BrowserModule,
|
||||||
|
FormsModule // <--- import into the NgModule
|
||||||
|
],
|
||||||
|
// #enddocregion import-forms-module
|
||||||
|
providers: [],
|
||||||
|
bootstrap: [AppComponent]
|
||||||
|
// #docregion import-forms-module
|
||||||
|
})
|
||||||
|
export class AppModule { }
|
||||||
|
// #enddocregion import-forms-module
|
||||||
|
|
@ -0,0 +1,3 @@
|
|||||||
|
<div>
|
||||||
|
<span>{{item?.name}}</span>
|
||||||
|
</div>
|
@ -0,0 +1,25 @@
|
|||||||
|
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
|
||||||
|
|
||||||
|
import { ItemDetailComponent } from './item-detail.component';
|
||||||
|
|
||||||
|
describe('ItemDetailComponent', () => {
|
||||||
|
let component: ItemDetailComponent;
|
||||||
|
let fixture: ComponentFixture<ItemDetailComponent>;
|
||||||
|
|
||||||
|
beforeEach(async(() => {
|
||||||
|
TestBed.configureTestingModule({
|
||||||
|
declarations: [ ItemDetailComponent ]
|
||||||
|
})
|
||||||
|
.compileComponents();
|
||||||
|
}));
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
fixture = TestBed.createComponent(ItemDetailComponent);
|
||||||
|
component = fixture.componentInstance;
|
||||||
|
fixture.detectChanges();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should create', () => {
|
||||||
|
expect(component).toBeTruthy();
|
||||||
|
});
|
||||||
|
});
|
@ -0,0 +1,17 @@
|
|||||||
|
import { Component, Input } from '@angular/core';
|
||||||
|
|
||||||
|
import { Item } from '../item';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'app-item-detail',
|
||||||
|
templateUrl: './item-detail.component.html',
|
||||||
|
styleUrls: ['./item-detail.component.css']
|
||||||
|
})
|
||||||
|
export class ItemDetailComponent {
|
||||||
|
|
||||||
|
|
||||||
|
@Input() item: Item;
|
||||||
|
|
||||||
|
constructor() { }
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,50 @@
|
|||||||
|
import { Component, Input } from '@angular/core';
|
||||||
|
import { Item } from './item';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'app-stout-item',
|
||||||
|
template: `I'm a little {{item.name}}, short and stout!`
|
||||||
|
})
|
||||||
|
export class StoutItemComponent {
|
||||||
|
@Input() item: Item;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'app-best-item',
|
||||||
|
template: `This is the brightest {{item.name}} in town.`
|
||||||
|
})
|
||||||
|
export class BestItemComponent {
|
||||||
|
@Input() item: Item;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'app-device-item',
|
||||||
|
template: `Which is the slimmest {{item.name}}?`
|
||||||
|
})
|
||||||
|
export class DeviceItemComponent {
|
||||||
|
@Input() item: Item;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'app-lost-item',
|
||||||
|
template: `Has anyone seen my {{item.name}}?`
|
||||||
|
})
|
||||||
|
export class LostItemComponent {
|
||||||
|
@Input() item: Item;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'app-unknown-item',
|
||||||
|
template: `{{message}}`
|
||||||
|
})
|
||||||
|
export class UnknownItemComponent {
|
||||||
|
@Input() item: Item;
|
||||||
|
get message() {
|
||||||
|
return this.item && this.item.name ?
|
||||||
|
`${this.item.name} is strange and mysterious.` :
|
||||||
|
'A mystery wrapped in a fishbowl.';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export const ItemSwitchComponents =
|
||||||
|
[ StoutItemComponent, BestItemComponent, DeviceItemComponent, LostItemComponent, UnknownItemComponent ];
|
30
aio/content/examples/built-in-directives/src/app/item.ts
Normal file
30
aio/content/examples/built-in-directives/src/app/item.ts
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
export class Item {
|
||||||
|
static nextId = 0;
|
||||||
|
|
||||||
|
static items: Item[] = [
|
||||||
|
new Item(
|
||||||
|
null,
|
||||||
|
'Teapot',
|
||||||
|
'stout'
|
||||||
|
),
|
||||||
|
new Item(1, 'Lamp', 'bright'),
|
||||||
|
new Item(2, 'Phone', 'slim' ),
|
||||||
|
new Item(3, 'Television', 'vintage' ),
|
||||||
|
new Item(4, 'Fishbowl')
|
||||||
|
];
|
||||||
|
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
public id?: number,
|
||||||
|
public name?: string,
|
||||||
|
public feature?: string,
|
||||||
|
public url?: string,
|
||||||
|
public rate = 100,
|
||||||
|
) {
|
||||||
|
this.id = id ? id : Item.nextId++;
|
||||||
|
}
|
||||||
|
|
||||||
|
clone(): Item {
|
||||||
|
return Object.assign(new Item(), this);
|
||||||
|
}
|
||||||
|
}
|
File diff suppressed because one or more lines are too long
After Width: | Height: | Size: 32 KiB |
14
aio/content/examples/built-in-directives/src/index.html
Normal file
14
aio/content/examples/built-in-directives/src/index.html
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
<!doctype html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<title>BuiltInDirectives</title>
|
||||||
|
<base href="/">
|
||||||
|
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
|
<link rel="icon" type="image/x-icon" href="favicon.ico">
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<app-root></app-root>
|
||||||
|
</body>
|
||||||
|
</html>
|
12
aio/content/examples/built-in-directives/src/main.ts
Normal file
12
aio/content/examples/built-in-directives/src/main.ts
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
import { enableProdMode } from '@angular/core';
|
||||||
|
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
|
||||||
|
|
||||||
|
import { AppModule } from './app/app.module';
|
||||||
|
import { environment } from './environments/environment';
|
||||||
|
|
||||||
|
if (environment.production) {
|
||||||
|
enableProdMode();
|
||||||
|
}
|
||||||
|
|
||||||
|
platformBrowserDynamic().bootstrapModule(AppModule)
|
||||||
|
.catch(err => console.log(err));
|
10
aio/content/examples/built-in-directives/stackblitz.json
Normal file
10
aio/content/examples/built-in-directives/stackblitz.json
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
{
|
||||||
|
"description": "Built-in Directives",
|
||||||
|
"files": [
|
||||||
|
"!**/*.d.ts",
|
||||||
|
"!**/*.js",
|
||||||
|
"!**/*.[1,2].*"
|
||||||
|
],
|
||||||
|
"file": "src/app/app.component.ts",
|
||||||
|
"tags": ["Built-in Directives"]
|
||||||
|
}
|
@ -1,11 +0,0 @@
|
|||||||
{
|
|
||||||
"open": false,
|
|
||||||
"logLevel": "silent",
|
|
||||||
"port": 8080,
|
|
||||||
"server": {
|
|
||||||
"baseDir": "dist",
|
|
||||||
"middleware": {
|
|
||||||
"0": null
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,14 +0,0 @@
|
|||||||
'use strict'; // necessary for es6 output in node
|
|
||||||
|
|
||||||
import { browser, element, by } from 'protractor';
|
|
||||||
|
|
||||||
describe('cli-quickstart App', () => {
|
|
||||||
beforeEach(() => {
|
|
||||||
return browser.get('/');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should display message saying app works', () => {
|
|
||||||
let pageTitle = element(by.css('app-root h1')).getText();
|
|
||||||
expect(pageTitle).toEqual('Welcome to My First Angular App!!');
|
|
||||||
});
|
|
||||||
});
|
|
@ -1,4 +0,0 @@
|
|||||||
{
|
|
||||||
"build": "build:cli",
|
|
||||||
"run": "serve:cli"
|
|
||||||
}
|
|
@ -1,6 +0,0 @@
|
|||||||
/* #docregion */
|
|
||||||
h1 {
|
|
||||||
color: #369;
|
|
||||||
font-family: Arial, Helvetica, sans-serif;
|
|
||||||
font-size: 250%;
|
|
||||||
}
|
|
@ -1,19 +0,0 @@
|
|||||||
<!--The content below is only a placeholder and can be replaced.-->
|
|
||||||
<div style="text-align:center">
|
|
||||||
<h1>
|
|
||||||
Welcome to {{ title }}!
|
|
||||||
</h1>
|
|
||||||
<img width="300" alt="Angular Logo" src="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAyNTAgMjUwIj4KICAgIDxwYXRoIGZpbGw9IiNERDAwMzEiIGQ9Ik0xMjUgMzBMMzEuOSA2My4ybDE0LjIgMTIzLjFMMTI1IDIzMGw3OC45LTQzLjcgMTQuMi0xMjMuMXoiIC8+CiAgICA8cGF0aCBmaWxsPSIjQzMwMDJGIiBkPSJNMTI1IDMwdjIyLjItLjFWMjMwbDc4LjktNDMuNyAxNC4yLTEyMy4xTDEyNSAzMHoiIC8+CiAgICA8cGF0aCAgZmlsbD0iI0ZGRkZGRiIgZD0iTTEyNSA1Mi4xTDY2LjggMTgyLjZoMjEuN2wxMS43LTI5LjJoNDkuNGwxMS43IDI5LjJIMTgzTDEyNSA1Mi4xem0xNyA4My4zaC0zNGwxNy00MC45IDE3IDQwLjl6IiAvPgogIDwvc3ZnPg==">
|
|
||||||
</div>
|
|
||||||
<h2>Here are some links to help you start: </h2>
|
|
||||||
<ul>
|
|
||||||
<li>
|
|
||||||
<h2><a target="_blank" rel="noopener" href="https://angular.io/tutorial">Tour of Heroes</a></h2>
|
|
||||||
</li>
|
|
||||||
<li>
|
|
||||||
<h2><a target="_blank" rel="noopener" href="https://github.com/angular/angular-cli/wiki">CLI Documentation</a></h2>
|
|
||||||
</li>
|
|
||||||
<li>
|
|
||||||
<h2><a target="_blank" rel="noopener" href="https://blog.angular.io/">Angular blog</a></h2>
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
@ -1,16 +0,0 @@
|
|||||||
// #docregion import
|
|
||||||
import { Component } from '@angular/core';
|
|
||||||
// #enddocregion import
|
|
||||||
|
|
||||||
// #docregion metadata, component
|
|
||||||
@Component({
|
|
||||||
selector: 'app-root',
|
|
||||||
templateUrl: './app.component.html',
|
|
||||||
styleUrls: ['./app.component.css']
|
|
||||||
})
|
|
||||||
// #enddocregion metadata
|
|
||||||
// #docregion title, class
|
|
||||||
export class AppComponent {
|
|
||||||
title = 'My First Angular App!';
|
|
||||||
}
|
|
||||||
// #enddocregion title, class, component
|
|
@ -1,9 +0,0 @@
|
|||||||
{
|
|
||||||
"files":[
|
|
||||||
"!**/*.d.ts",
|
|
||||||
"!**/*.js",
|
|
||||||
"!**/*.[0-9].*",
|
|
||||||
"angular.json",
|
|
||||||
"protractor.conf.js"
|
|
||||||
]
|
|
||||||
}
|
|
@ -13,7 +13,7 @@ describe('Component Communication Cookbook Tests', function () {
|
|||||||
describe('Parent-to-child communication', function() {
|
describe('Parent-to-child communication', function() {
|
||||||
// #docregion parent-to-child
|
// #docregion parent-to-child
|
||||||
// ...
|
// ...
|
||||||
let _heroNames = ['Mr. IQ', 'Magneta', 'Bombasto'];
|
let _heroNames = ['Dr IQ', 'Magneta', 'Bombasto'];
|
||||||
let _masterName = 'Master';
|
let _masterName = 'Master';
|
||||||
|
|
||||||
it('should pass properties to children properly', function () {
|
it('should pass properties to children properly', function () {
|
||||||
@ -36,7 +36,7 @@ describe('Component Communication Cookbook Tests', function () {
|
|||||||
// ...
|
// ...
|
||||||
it('should display trimmed, non-empty names', function () {
|
it('should display trimmed, non-empty names', function () {
|
||||||
let _nonEmptyNameIndex = 0;
|
let _nonEmptyNameIndex = 0;
|
||||||
let _nonEmptyName = '"Mr. IQ"';
|
let _nonEmptyName = '"Dr IQ"';
|
||||||
let parent = element.all(by.tagName('app-name-parent')).get(0);
|
let parent = element.all(by.tagName('app-name-parent')).get(0);
|
||||||
let hero = parent.all(by.tagName('app-name-child')).get(_nonEmptyNameIndex);
|
let hero = parent.all(by.tagName('app-name-child')).get(_nonEmptyNameIndex);
|
||||||
|
|
||||||
|
@ -39,7 +39,7 @@ export class CountdownLocalVarParentComponent { }
|
|||||||
})
|
})
|
||||||
export class CountdownViewChildParentComponent implements AfterViewInit {
|
export class CountdownViewChildParentComponent implements AfterViewInit {
|
||||||
|
|
||||||
@ViewChild(CountdownTimerComponent)
|
@ViewChild(CountdownTimerComponent, {static: false})
|
||||||
private timerComponent: CountdownTimerComponent;
|
private timerComponent: CountdownTimerComponent;
|
||||||
|
|
||||||
seconds() { return 0; }
|
seconds() { return 0; }
|
||||||
|
@ -3,7 +3,7 @@ export class Hero {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export const HEROES = [
|
export const HEROES = [
|
||||||
{name: 'Mr. IQ'},
|
{name: 'Dr IQ'},
|
||||||
{name: 'Magneta'},
|
{name: 'Magneta'},
|
||||||
{name: 'Bombasto'}
|
{name: 'Bombasto'}
|
||||||
];
|
];
|
||||||
|
@ -9,7 +9,7 @@ import { Component } from '@angular/core';
|
|||||||
`
|
`
|
||||||
})
|
})
|
||||||
export class NameParentComponent {
|
export class NameParentComponent {
|
||||||
// Displays 'Mr. IQ', '<no name set>', 'Bombasto'
|
// Displays 'Dr IQ', '<no name set>', 'Bombasto'
|
||||||
names = ['Mr. IQ', ' ', ' Bombasto '];
|
names = ['Dr IQ', ' ', ' Bombasto '];
|
||||||
}
|
}
|
||||||
// #enddocregion
|
// #enddocregion
|
||||||
|
@ -15,7 +15,7 @@ import { Component } from '@angular/core';
|
|||||||
export class VoteTakerComponent {
|
export class VoteTakerComponent {
|
||||||
agreed = 0;
|
agreed = 0;
|
||||||
disagreed = 0;
|
disagreed = 0;
|
||||||
voters = ['Mr. IQ', 'Ms. Universe', 'Bombasto'];
|
voters = ['Narco', 'Celeritas', 'Bombasto'];
|
||||||
|
|
||||||
onVoted(agreed: boolean) {
|
onVoted(agreed: boolean) {
|
||||||
agreed ? this.agreed++ : this.disagreed++;
|
agreed ? this.agreed++ : this.disagreed++;
|
||||||
|
@ -23,8 +23,8 @@ describe('Dependency Injection Cookbook', function () {
|
|||||||
expect(sortedHeroes).toBeDefined();
|
expect(sortedHeroes).toBeDefined();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('Mr. Nice should be in sorted heroes', function () {
|
it('Dr Nice should be in sorted heroes', function () {
|
||||||
let sortedHero = element.all(by.xpath('//sorted-heroes/[text()="Mr. Nice" and position()=2]')).get(0);
|
let sortedHero = element.all(by.xpath('//sorted-heroes/[text()="Dr Nice" and position()=2]')).get(0);
|
||||||
expect(sortedHero).toBeDefined();
|
expect(sortedHero).toBeDefined();
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -60,7 +60,7 @@ describe('Dependency Injection Cookbook', function () {
|
|||||||
|
|
||||||
it('should render Hero-of-the-Month runner-ups', function () {
|
it('should render Hero-of-the-Month runner-ups', function () {
|
||||||
let runnersUp = element(by.id('rups1')).getText();
|
let runnersUp = element(by.id('rups1')).getText();
|
||||||
expect(runnersUp).toContain('RubberMan, Mr. Nice');
|
expect(runnersUp).toContain('RubberMan, Dr Nice');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should render DateLogger log entry in Hero-of-the-Month', function () {
|
it('should render DateLogger log entry in Hero-of-the-Month', function () {
|
||||||
@ -73,8 +73,12 @@ describe('Dependency Injection Cookbook', function () {
|
|||||||
let yellow = 'rgba(255, 255, 0, 1)';
|
let yellow = 'rgba(255, 255, 0, 1)';
|
||||||
|
|
||||||
expect(target.getCssValue('background-color')).not.toEqual(yellow);
|
expect(target.getCssValue('background-color')).not.toEqual(yellow);
|
||||||
browser.actions().mouseMove(target.getWebElement()).perform();
|
|
||||||
expect(target.getCssValue('background-color')).toEqual(yellow);
|
browser.actions().mouseMove(target).perform();
|
||||||
|
|
||||||
|
// Wait for up to 2s for the background color to be updated,
|
||||||
|
// to account for slow environments (e.g. CI).
|
||||||
|
browser.wait(() => target.getCssValue('background-color').then(c => c === yellow), 2000);
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('in Parent Finder', function () {
|
describe('in Parent Finder', function () {
|
||||||
|
@ -11,7 +11,7 @@ export class HeroService {
|
|||||||
private heroes: Array<Hero> = [
|
private heroes: Array<Hero> = [
|
||||||
new Hero(1, 'RubberMan', 'Hero of many talents', '123-456-7899'),
|
new Hero(1, 'RubberMan', 'Hero of many talents', '123-456-7899'),
|
||||||
new Hero(2, 'Magma', 'Hero of all trades', '555-555-5555'),
|
new Hero(2, 'Magma', 'Hero of all trades', '555-555-5555'),
|
||||||
new Hero(3, 'Mr. Nice', 'The name says it all', '111-222-3333')
|
new Hero(3, 'Dr Nice', 'The name says it all', '111-222-3333')
|
||||||
];
|
];
|
||||||
|
|
||||||
getHeroById(id: number): Hero {
|
getHeroById(id: number): Hero {
|
||||||
|
@ -29,10 +29,10 @@ export class StorageComponent implements OnInit {
|
|||||||
}
|
}
|
||||||
|
|
||||||
setSession() {
|
setSession() {
|
||||||
this.sessionStorageService.set('hero', 'Mr. Nice - Session');
|
this.sessionStorageService.set('hero', 'Dr Nice - Session');
|
||||||
}
|
}
|
||||||
|
|
||||||
setLocal() {
|
setLocal() {
|
||||||
this.localStorageService.set('hero', 'Mr. Nice - Local');
|
this.localStorageService.set('hero', 'Dr Nice - Local');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -56,7 +56,7 @@ describe('Dependency Injection Tests', function () {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('Hero displays as expected', function () {
|
it('Hero displays as expected', function () {
|
||||||
expectedMsg = 'Mr. Nice';
|
expectedMsg = 'Dr Nice';
|
||||||
expect(element(by.css('#hero')).getText()).toEqual(expectedMsg);
|
expect(element(by.css('#hero')).getText()).toEqual(expectedMsg);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
import { Hero } from './hero';
|
import { Hero } from './hero';
|
||||||
|
|
||||||
export const HEROES: Hero[] = [
|
export const HEROES: Hero[] = [
|
||||||
{ id: 11, isSecret: false, name: 'Mr. Nice' },
|
{ id: 11, isSecret: false, name: 'Dr Nice' },
|
||||||
{ id: 12, isSecret: false, name: 'Narco' },
|
{ id: 12, isSecret: false, name: 'Narco' },
|
||||||
{ id: 13, isSecret: false, name: 'Bombasto' },
|
{ id: 13, isSecret: false, name: 'Bombasto' },
|
||||||
{ id: 14, isSecret: false, name: 'Celeritas' },
|
{ id: 14, isSecret: false, name: 'Celeritas' },
|
||||||
|
@ -1,14 +1,14 @@
|
|||||||
import { Component } from '@angular/core';
|
import { Component } from '@angular/core';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-ctor',
|
selector: 'app-root',
|
||||||
template: `
|
template: `
|
||||||
<h1>{{title}} [Ctor version]</h1>
|
<h1>{{title}} [Ctor version]</h1>
|
||||||
<h2>My favorite hero is: {{myHero}}</h2>
|
<h2>My favorite hero is: {{myHero}}</h2>
|
||||||
`
|
`
|
||||||
})
|
})
|
||||||
// #docregion class
|
// #docregion class
|
||||||
export class AppCtorComponent {
|
export class AppComponent {
|
||||||
title: string;
|
title: string;
|
||||||
myHero: string;
|
myHero: string;
|
||||||
|
|
||||||
|
@ -4,7 +4,7 @@ export class Hero {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export const HEROES: Hero[] = [
|
export const HEROES: Hero[] = [
|
||||||
{ id: 11, name: 'Mr. Nice' },
|
{ id: 11, name: 'Dr Nice' },
|
||||||
{ id: 12, name: 'Narco' },
|
{ id: 12, name: 'Narco' },
|
||||||
{ id: 13, name: 'Bombasto' },
|
{ id: 13, name: 'Bombasto' },
|
||||||
{ id: 14, name: 'Celeritas' }
|
{ id: 14, name: 'Celeritas' }
|
||||||
|
@ -20,7 +20,7 @@ import { AdComponent } from './ad.component';
|
|||||||
export class AdBannerComponent implements OnInit, OnDestroy {
|
export class AdBannerComponent implements OnInit, OnDestroy {
|
||||||
@Input() ads: AdItem[];
|
@Input() ads: AdItem[];
|
||||||
currentAdIndex = -1;
|
currentAdIndex = -1;
|
||||||
@ViewChild(AdDirective) adHost: AdDirective;
|
@ViewChild(AdDirective, {static: true}) adHost: AdDirective;
|
||||||
interval: any;
|
interval: any;
|
||||||
|
|
||||||
constructor(private componentFactoryResolver: ComponentFactoryResolver) { }
|
constructor(private componentFactoryResolver: ComponentFactoryResolver) { }
|
||||||
@ -36,14 +36,14 @@ export class AdBannerComponent implements OnInit, OnDestroy {
|
|||||||
|
|
||||||
loadComponent() {
|
loadComponent() {
|
||||||
this.currentAdIndex = (this.currentAdIndex + 1) % this.ads.length;
|
this.currentAdIndex = (this.currentAdIndex + 1) % this.ads.length;
|
||||||
let adItem = this.ads[this.currentAdIndex];
|
const adItem = this.ads[this.currentAdIndex];
|
||||||
|
|
||||||
let componentFactory = this.componentFactoryResolver.resolveComponentFactory(adItem.component);
|
const componentFactory = this.componentFactoryResolver.resolveComponentFactory(adItem.component);
|
||||||
|
|
||||||
let viewContainerRef = this.adHost.viewContainerRef;
|
const viewContainerRef = this.adHost.viewContainerRef;
|
||||||
viewContainerRef.clear();
|
viewContainerRef.clear();
|
||||||
|
|
||||||
let componentRef = viewContainerRef.createComponent(componentFactory);
|
const componentRef = viewContainerRef.createComponent(componentFactory);
|
||||||
(<AdComponent>componentRef.instance).data = adItem.data;
|
(<AdComponent>componentRef.instance).data = adItem.data;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,3 +0,0 @@
|
|||||||
{
|
|
||||||
"projectType": "elements"
|
|
||||||
}
|
|
||||||
|
@ -17,7 +17,7 @@ export class AppComponent {
|
|||||||
if (event) { event.stopPropagation(); }
|
if (event) { event.stopPropagation(); }
|
||||||
}
|
}
|
||||||
|
|
||||||
deleteItem(item?: Item) {
|
deleteItem(item: Item) {
|
||||||
alert(`Delete the ${item}.`);
|
alert(`Delete the ${item}.`);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -21,7 +21,7 @@ export class ItemDetailComponent {
|
|||||||
@Output() deleteRequest = new EventEmitter<Item>();
|
@Output() deleteRequest = new EventEmitter<Item>();
|
||||||
|
|
||||||
delete() {
|
delete() {
|
||||||
this.deleteRequest.emit(this.item.name);
|
this.deleteRequest.emit(this.item);
|
||||||
this.displayNone = this.displayNone ? '' : 'none';
|
this.displayNone = this.displayNone ? '' : 'none';
|
||||||
this.lineThrough = this.lineThrough ? '' : 'line-through';
|
this.lineThrough = this.lineThrough ? '' : 'line-through';
|
||||||
}
|
}
|
||||||
|
@ -9,7 +9,7 @@ describe('feature-modules App', () => {
|
|||||||
|
|
||||||
it('should display message saying app works', () => {
|
it('should display message saying app works', () => {
|
||||||
page.navigateTo();
|
page.navigateTo();
|
||||||
expect(page.getParagraphText()).toEqual('app works!');
|
expect(page.getTitleText()).toEqual('app works!');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -0,0 +1,21 @@
|
|||||||
|
'use strict'; // necessary for es6 output in node
|
||||||
|
|
||||||
|
import { browser, element, by } from 'protractor';
|
||||||
|
|
||||||
|
describe('Getting Started V0', () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
return browser.get('/');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should display "My Store" in the top bar', async() => {
|
||||||
|
const title = await element(by.css('app-root app-top-bar h1')).getText();
|
||||||
|
|
||||||
|
expect(title).toEqual('My Store');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should display "Products" on the homepage', async() => {
|
||||||
|
const title = await element(by.css('app-root app-product-list h2')).getText();
|
||||||
|
|
||||||
|
expect(title).toEqual('Products');
|
||||||
|
});
|
||||||
|
});
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user