From fabbfecfdf3d6de8f5d93e29b0f252f8fb746b73 Mon Sep 17 00:00:00 2001 From: George Kamtziridis Date: Tue, 6 Aug 2019 04:31:09 +0300 Subject: [PATCH 01/18] docs: removed unnecessary 'Effect' decorator in effects example. (#2040) --- projects/ngrx.io/content/guide/effects/index.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/projects/ngrx.io/content/guide/effects/index.md b/projects/ngrx.io/content/guide/effects/index.md index c967449c79..b75117aa45 100644 --- a/projects/ngrx.io/content/guide/effects/index.md +++ b/projects/ngrx.io/content/guide/effects/index.md @@ -104,7 +104,7 @@ To show how you handle loading movies from the example above, let's look at `Mov import { Injectable } from '@angular/core'; -import { Actions, Effect, ofType } from '@ngrx/effects'; +import { Actions, createEffect, ofType } from '@ngrx/effects'; import { EMPTY } from 'rxjs'; import { map, mergeMap, catchError } from 'rxjs/operators'; import { MoviesService } from './movies.service'; @@ -150,7 +150,7 @@ Effects are built on top of observable streams provided by RxJS. Effects are lis import { Injectable } from '@angular/core'; -import { Actions, Effect, ofType } from '@ngrx/effects'; +import { Actions, createEffect, ofType } from '@ngrx/effects'; import { of } from 'rxjs'; import { map, mergeMap, catchError } from 'rxjs/operators'; import { MoviesService } from './movies.service'; From b84ff9d5353bb2d1856771438a20e22c14c26dd8 Mon Sep 17 00:00:00 2001 From: Jordan Date: Fri, 9 Aug 2019 20:15:59 -0400 Subject: [PATCH 02/18] docs(store): adds state management lifecycle diagram to getting started (#2031) Closes #1981 --- projects/ngrx.io/content/guide/store/index.md | 7 +++++++ .../guide/store/state-management-lifecycle.png | Bin 0 -> 89719 bytes 2 files changed, 7 insertions(+) create mode 100644 projects/ngrx.io/content/images/guide/store/state-management-lifecycle.png diff --git a/projects/ngrx.io/content/guide/store/index.md b/projects/ngrx.io/content/guide/store/index.md index 09c03690f8..b2639b7461 100644 --- a/projects/ngrx.io/content/guide/store/index.md +++ b/projects/ngrx.io/content/guide/store/index.md @@ -13,6 +13,13 @@ Store is RxJS powered state management for Angular applications, inspired by Red Detailed installation instructions can be found on the [Installation](guide/store/install) page. +## Diagram + +The following diagram represents the overall general flow of application state in NgRx. +
+ NgRx State Management Lifecycle Diagram +
+ ## Tutorial The following tutorial shows you how to manage the state of a counter, and how to select and display it within an Angular component. Try the . diff --git a/projects/ngrx.io/content/images/guide/store/state-management-lifecycle.png b/projects/ngrx.io/content/images/guide/store/state-management-lifecycle.png new file mode 100644 index 0000000000000000000000000000000000000000..649a8c970381a2a491531af0fc5090e6663b0a1f GIT binary patch literal 89719 zcmce;2V9fe@+cZbMNm*dKok&xfPkTd-c@Soy%&K{LJK9KH@hf;geE8;2qL``I#!V0 zq*tYb6sgkR3gF)R>~r=#|M%X#H@}|(-?z%ltm$heLF%gVWTY2KArJ@|LP16o0wE5B zK#mEYJOQ3eb-b4bKS-Pv4BQ})QCf@z_=nu!sGlwi^mP~lN=mbS7*DR{eDX?d$^TYB4D ziXfS!BpJm$MZp4&Rv2?ePe%tQH&IUsru}tA!S95}+)Rx7LooIdOg9J{GU}_SGfJaf ztr!Kk1YwrE`~r+ZB3!(JeEcFJ*BIeEyu#c(!rZ)kFkV4XejZUcobm9(1a@;pT8nDR z$Q|wl{*qv_#bBI8xw$<&Jh(jgxX`XP+`J+pBHTQ1Za5qUM!?*>oG|8|Fef+W-z&&i zxmmiRoG~c06C+_oa|<*UBf$h9JwU|0@v4fsCCZ6#4D19%4rf`( zm}9IYmz_(d;Qm;e;m4~G}-~}s)9xWIQW;pB!fce1oX$Ve~&T)9vvq^Om(h!77y zuK_Ucwqeeg61%DBpguRf=AGrhtFDs*TRyCk-!_GU>N|CIYAmFm;eFxALpLD{9)ceElVsXfo)~3wFDqBKLj`ry+~)8%2h?BAeSeIqxg*$F zOIuA-_OCp#|BkTG?|0n)Wd%)H869a^O-4(!vlk;k?oV+3vee-qrvJ8>G}_S_?F0_t zAJ+Nv{eN3YOIBG{8X)%%3;pr>zpZn_a$h+Uu=|Il4o3V})MVwXtt>HG|FFpKxBm?s zEm=)ng!Dh2*x}p%wu-8}rv5(wvj6J8&DYYtp)Jd(azpioysV0>sy3rCLQYoNKw9}9 z0sH3(guS>4w(o#hx&P#!e_`i8AO9Be8$kWI0j>O>m|gNe>l7wK)$A zZp|+UGw0Kb&=3tl`+8X0w?rL?z1_;>y%#Qtq z5&jheH*@#@HT;6+=5RqiK{!l=&l(Bi2g)2~A!q@I30VVzTk-SpTJQk1`yb)w)8-Kp z6%ZCBDCq+e`TrUI!woEL&7EwlfCI_>S26v6iIF*62+j`|5r*;b0^`juY%Ky45wW&} z37HG=Sy~BM@bjAs{b!8+gB}0BfsrNJ$=%BJFMQ@~?h2GX2G|D)CTmx;Bcr*qvjfU< z-{5h(J0TAp%s)hp5rby@)AIi#FCeX4QGelvzwYt}2#o(5_xrEB_djz){uA&0pFgR6 zRd=8oxc{y-4*r%oAg3JRfc8CM(f_0${-@jsTw_t-TKyMi%bH)vQV0$lHX&XiILwld zpATjsVh;R3K4CsMkEI|l+*S~&p; zb_KDX-w7-uk47To<D?f8@_U zA(=Ohf++X*2Y!s?*6-gTkS}Lh0{Nc-Hxs6F7dv(c-SyLwsv}1O*PlUDO|4uy zb#OyAyUMuaMCk`~i(5OCO%H!Whn?I-`B@G&%*({=3j6;?3(a)oG=xFss4#EjXB{YR z2)*0*V`trzWJDng=g%~qw^>uxv?dp0@b5D`oxuz~C@d0#Pc9{ra1T7@oNP^7Hl7tN9$fLtbxpxSEp-n{-(qFc&WUr z1w^%H4(E)hfU|gaR{>(CZeT26*iH}c6B}l!OPGS=6d>y-5#G9TR*T%TmuCBL`f_sL zfBinUilAdW5Kr}Dwm{A&84r}a@xhA290;$pYuxt%fT{>GILF=YE}^bCRTnSR(^2BX z?G{-n-a$rg^gf4VU(3G8G_6Y;S+x+QeXBDcrU;Q2WkzKM*N+Sn<`p>iqHh1&JRD&j zsX}^0*ot3ha+rH&?E|pgD9)dqnReR&99ip|RZr5tV+R*GVr*bM9*!vrUTao@KE?aQ z39)!u=fFG>q=!`>ab$ZAt8lY?P}1Svx^LM2 zkiP>MvkzdIcKa4mdyBf9>Y)-i;v6M!<#x-}r`Ueu;E!-RsY6->3WWj2KchH#%o*^~ zd0GV6CU(+Q7$+VE30Zjz2$29Fn*-Y-UA7PBK!#+1T!~*Dq<9C|!V)^j{>$mPRn?_MZChysaIq>q;5m)PA)zKHNpDl^awDL=Q` z@)|%mi0e|?3`!ONFs2%Z*r@*<#w9z#L=Lm|a%7>0={3~b@^hcr$SB^0H7lk^YtR~- z4eNV!jeA=Boj;yM@55ON=kQ&?Y5WxXF!+cf+8S)g2F(f!JH2ZHPAt0ooAJB9^Dv&0 zfS*62yUuoDn*m{ILUvUa^%4?-(QoHQ76$EV5u~%}*5ActOm`o_cyMGXxHn}K_sHNZ zN9a)a3K{aaT@@LR@jV5PWUR+<>+FU@^^CN zi|unp7=beoWgogCy{UN;|x)y_9j&~M3Tvh&r&=}A8tV<~cZdDB^LIi-*zTXPT04xO0$5Sc z$;?w=6z_QB!n6sy34z^Ag2ZF~&hbB42pV7;$6=+tStYL-*0ewCu3h+w8_-fV0JocW zCH_s2cc6q>zBuYHZ&ys1P`JDMvq*Zmr(F0!*%x9YzYYAC_53`Kl)%iPqSc#)H_v(S3s z>FmN4T(Wzdu2P8x_x<<|1ii<#n>_LYhY)yD5zNG!%*@mOGI zhsk1TN_4sJCv;zyuGWbza|ofRZ~sYhIB_~qB=E?)7x~%83)TEPH>J*cED7Pvj+o4q zBQBF}$JK1I8eXPjx-a{OxUM`ylnym+{g_+#o;$cTv#%To`rlWf|X!zu9L{%ZzZXURIZwi_^pY>}zr z8&v8Z9^ED6!?ba$*r`I*nUaOKeZKOTPafB6edUqoi`ENR0Qm=} z$lcFneR`;AI1#CB^5f=VhNQ&X=HEU%_Zo5&%^=zx?3?RPq~FaFooGnJmOz4U*$4dfg+)F4M-R&An_scsOSQeZe%>Ti)*H5%6uZrxKIl<1 zmpdSLoabL>2O|o{IrO5pvcGojzTlUm93W>im)3c8{Jmn+DbpN1qJTEe+ml#Tn?dph z7%d;yp{-}6B-p8izEO8b-6H3!u!|{SRc#kjgJLIMq|sLO)_0u6ODh?KxC%)9a*sTb z(+<|?yzr~w&WyX*wN%2?gU=ae0;fg_x@Cp5UTs=7OI6a&%&Q_!}uID%B)Y(MGon)Z=e_ZIbx=-$l@ zDrd0^-4*lbuWll0Hqu5@qd;NF;y(RpS+uO9ZI4{vT*h3Qy0n9zIk5*bh}(`#Zjc_| zyx#3sc9p+jPW{Kk^v{!r05bx3O(%Qr_1iw}D5~-(p?_d=`V`H~+I)3a|J?;`MmNgu zjeDmK2Q$bMguSVNWQ23)6wAf{`A4_V1Fl@h8=c>ae@I5;h_GRe2!TO*ww zT0mPuD2+q1rPiy&EB;$ml<-}H_SC+6OqM0-pHlW(jUm4(O-;_YvGK2B-C zeBt_2zn%^u;5;meCwgQ>5QID9HTT(M2b(prYwpz=l!XMk7M5)7O#j;Sa;5vN!jtw{ zd3m5BSJ`^nrPQsXe&Htq)MLw-Jd3hVnmTTIKbF>;T2+7TzJc$r;(FpafAcqH*Uhvc zM1kvG=}YZw3EAr~SFzw=XG`Zi-=(b`A4+qd)vZ2fw6v@8?G+#?oAV^Xa3f1Ue+xa0Cv|SL^6)49&Y=piN=& zoZA>av$2*@wzX5=%|pXH6Kzv-<#3}{0gVJmCC9}XeqrRI$ja7V-&-<%V+x|$rhaE0pa%7|qas+j7Q zAFHioxIXWls>JjZhf0&5AB-%X9=e}Masn6o5krqdj}Pd3WxHZu>^U{9HDN7R4b0u& zY7-OrKoP{-J{Vc&+gxOkQz`*Z8p7hbVU~1#c7p>GSUAP=yLMMm-pOF)(xxkEiOKBq z&soyaQySYESISD8mRVq7=SC}p6R0;zmixQZ+gWHyzOk`n<=Ci2`dS3R13IoesP-3(SRg^`0e5fTO#{6mGft@+z%Y*X&*V)e+TZsi+;Gcdp>? zPFWd9BRb&tyUq;�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

=o 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 Date: Fri, 9 Aug 2019 20:22:41 -0400 Subject: [PATCH 03/18] docs: add game prop to setScores createAction code example Closes #2054 --- projects/ngrx.io/content/guide/store/reducers.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/projects/ngrx.io/content/guide/store/reducers.md b/projects/ngrx.io/content/guide/store/reducers.md index 874fe7a282..bbf3317050 100644 --- a/projects/ngrx.io/content/guide/store/reducers.md +++ b/projects/ngrx.io/content/guide/store/reducers.md @@ -25,7 +25,7 @@ import { createAction } from '@ngrx/store'; export const homeScore = createAction('[Scoreboard Page] Home Score'); export const awayScore = createAction('[Scoreboard Page] Away Score'); export const resetScore = createAction('[Scoreboard Page] Score Reset'); -export const setScores = createAction('[Scoreboard Page] Set Scores'); +export const setScores = createAction('[Scoreboard Page] Set Scores', props<{game: Game}>()); From 214e7dc3080ec81afff29140882a695db22cc129 Mon Sep 17 00:00:00 2001 From: Jordan Date: Sun, 11 Aug 2019 22:49:03 -0400 Subject: [PATCH 04/18] docs: add auxiliary verb for getting started (#2057) Closes #2056 --- projects/ngrx.io/content/guide/store/index.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/projects/ngrx.io/content/guide/store/index.md b/projects/ngrx.io/content/guide/store/index.md index b2639b7461..03f8756175 100644 --- a/projects/ngrx.io/content/guide/store/index.md +++ b/projects/ngrx.io/content/guide/store/index.md @@ -7,7 +7,7 @@ Store is RxJS powered state management for Angular applications, inspired by Red - [Actions](guide/store/actions) describe unique events that are dispatched from components and services. - State changes are handled by pure functions called [reducers](guide/store/reducers) that take the current state and the latest action to compute a new state. - [Selectors](guide/store/selectors) are pure functions used to select, derive and compose pieces of state. -- State accessed with the `Store`, an observable of state and an observer of actions. +- State is accessed with the `Store`, an observable of state and an observer of actions. ## Installation From 6851fb6fa953f414d7460ac2294b07d6bc75f709 Mon Sep 17 00:00:00 2001 From: tja4472 Date: Wed, 21 Aug 2019 03:54:37 +0100 Subject: [PATCH 05/18] docs(data): update entity-actions examples (#2069) update the entityActionFactory.create examples to adapt the new API and actions. 1. entityActionFactory.create with an optional parameter should use {tag: string} signature 2. the action of QUERY_ALL now looks like ngrx/data/query-all/XXX --- .../content/guide/data/entity-actions.md | 20 +++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/projects/ngrx.io/content/guide/data/entity-actions.md b/projects/ngrx.io/content/guide/data/entity-actions.md index d29b0b2149..178c6f3db9 100644 --- a/projects/ngrx.io/content/guide/data/entity-actions.md +++ b/projects/ngrx.io/content/guide/data/entity-actions.md @@ -113,8 +113,9 @@ e.g., `'[Hero] NgRx Data/query-all'`. Here's an example that uses the injectable `EntityActionFactory` to construct the default "query all heroes" action. ```typescript -const action = entityActionFactory( - 'Hero', EntityOp.QUERY_ALL, null, 'Load Heroes On Start' +const action = this.entityActionFactory.create( + 'Hero', + EntityOp.QUERY_ALL ); store.dispatch(action); @@ -123,8 +124,8 @@ store.dispatch(action); Thanks to the NgRx Data _Effects_, this produces _two_ actions in the log, the first to initiate the request and the second with the successful response: ```typescript -[Hero] NgRx Data/query-all -[Hero] NgRx Data/query-all-success +[Hero] ngrx/data/query-all +[Hero] ngrx/data/query-all/success ``` This default `entityName` tag identifies the action's target entity collection. @@ -138,8 +139,11 @@ where that action is dispatched by your code. For example, ```typescript -const action = entityActionFactory( - 'Hero', EntityOp.QUERY_ALL, null, 'Load Heroes On Start' +const action = this.entityActionFactory.create( + 'Hero', + EntityOp.QUERY_ALL, + null, + { tag: 'Load Heroes On Start' } ); store.dispatch(action); @@ -148,8 +152,8 @@ store.dispatch(action); The action log now looks like this: ```typescript -[Load Heroes On Start] NgRx Data/query-all -[Load Heroes On Start] NgRx Data/query-all-success +[Load Heroes On Start] ngrx/data/query-all +[Load Heroes On Start] ngrx/data/query-all/success ``` ### Handcrafted _EntityAction_ From c014e1520f701e27025c8c12b9c80893dd391935 Mon Sep 17 00:00:00 2001 From: Benjamin Blackwood Date: Wed, 21 Aug 2019 12:55:28 +1000 Subject: [PATCH 06/18] docs: fix small typo in intro (#2065) --- projects/ngrx.io/content/guide/store/testing.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/projects/ngrx.io/content/guide/store/testing.md b/projects/ngrx.io/content/guide/store/testing.md index 80fe285ebe..d4d2c1a0b3 100644 --- a/projects/ngrx.io/content/guide/store/testing.md +++ b/projects/ngrx.io/content/guide/store/testing.md @@ -7,7 +7,7 @@ You can write tests validating behaviors corresponding to the specific state sna

-**Note:** All dispatched actions don't affect to the state, but you can see them in the `Actions` stream. +**Note:** All dispatched actions don't affect the state, but you can see them in the `Actions` stream.
From 0e9c4f4a20ca92a71ee331889109c7861708725f Mon Sep 17 00:00:00 2001 From: Bitcollage Date: Wed, 21 Aug 2019 05:00:12 +0200 Subject: [PATCH 07/18] refactor: remove unused imports for better developer UX (#2066) --- .../spec/actions/entity-action-factory.spec.ts | 2 -- .../actions/entity-action-operators.spec.ts | 1 - .../actions/entity-cache-changes-set.spec.ts | 6 +----- .../dataservices/data-service-error.spec.ts | 2 +- .../dataservices/default-data.service.spec.ts | 3 +-- .../dataservices/entity-data.service.spec.ts | 5 ----- .../spec/effects/entity-cache-effects.spec.ts | 13 ++----------- .../effects/entity-effects.marbles.spec.ts | 2 +- .../data/spec/effects/entity-effects.spec.ts | 2 +- modules/data/spec/entity-data.module.spec.ts | 4 ++-- .../entity-collection-service.spec.ts | 15 +++------------ .../entity-services/entity-services.spec.ts | 17 +++-------------- .../spec/reducers/entity-cache-reducer.spec.ts | 1 - .../selectors/related-entity-selectors.spec.ts | 12 +++--------- .../data/src/actions/entity-action-factory.ts | 1 - .../src/actions/entity-action-operators.ts | 5 +---- modules/data/src/actions/entity-action.ts | 1 - .../src/actions/entity-cache-change-set.ts | 5 ----- .../default-data-service-config.ts | 2 +- .../src/dataservices/default-data.service.ts | 2 +- .../dataservices/entity-cache-data.service.ts | 6 +----- .../src/dataservices/http-url-generator.ts | 2 +- .../persistence-result-handler.service.ts | 4 +--- .../src/dispatchers/entity-cache-dispatcher.ts | 14 +++----------- .../data/src/dispatchers/entity-commands.ts | 1 - .../src/dispatchers/entity-dispatcher-base.ts | 4 ++-- .../dispatchers/entity-dispatcher-factory.ts | 8 ++------ .../data/src/effects/entity-cache-effects.ts | 1 - .../src/effects/entity-effects-scheduler.ts | 2 +- modules/data/src/effects/entity-effects.ts | 9 +-------- .../src/entity-data-without-effects.module.ts | 18 +++--------------- .../entity-definition.service.ts | 3 +-- .../src/entity-metadata/entity-definition.ts | 9 ++------- .../entity-collection-service-base.ts | 3 --- ...tity-collection-service-elements-factory.ts | 2 -- .../entity-services/entity-services-base.ts | 9 ++------- .../src/entity-services/entity-services.ts | 1 - modules/data/src/reducers/constants.ts | 2 +- .../data/src/reducers/entity-cache-reducer.ts | 1 - .../src/reducers/entity-change-tracker-base.ts | 18 +++--------------- .../data/src/reducers/entity-change-tracker.ts | 7 +------ .../entity-collection-reducer-methods.ts | 9 ++------- .../entity-collection-reducer-registry.ts | 2 +- .../src/selectors/entity-cache-selector.ts | 14 ++------------ .../data/src/selectors/entity-selectors$.ts | 10 +--------- modules/data/src/selectors/entity-selectors.ts | 5 +---- package.json | 2 +- .../src/app/core/effects/user.effects.ts | 2 +- projects/example-app/src/app/reducers/index.ts | 1 - 49 files changed, 55 insertions(+), 215 deletions(-) diff --git a/modules/data/spec/actions/entity-action-factory.spec.ts b/modules/data/spec/actions/entity-action-factory.spec.ts index 0c1801ea8f..7e648b731b 100644 --- a/modules/data/spec/actions/entity-action-factory.spec.ts +++ b/modules/data/spec/actions/entity-action-factory.spec.ts @@ -1,11 +1,9 @@ import { - EntityAction, EntityActionOptions, EntityActionPayload, EntityOp, EntityActionFactory, MergeStrategy, - CorrelationIdGenerator, } from '../../'; class Hero { diff --git a/modules/data/spec/actions/entity-action-operators.spec.ts b/modules/data/spec/actions/entity-action-operators.spec.ts index 02d2b8f2d7..b4a9ed29f4 100644 --- a/modules/data/spec/actions/entity-action-operators.spec.ts +++ b/modules/data/spec/actions/entity-action-operators.spec.ts @@ -1,5 +1,4 @@ import { Action } from '@ngrx/store'; -import { Actions } from '@ngrx/effects'; import { Subject } from 'rxjs'; diff --git a/modules/data/spec/actions/entity-cache-changes-set.spec.ts b/modules/data/spec/actions/entity-cache-changes-set.spec.ts index 3c53af7020..9a51ac6e48 100644 --- a/modules/data/spec/actions/entity-cache-changes-set.spec.ts +++ b/modules/data/spec/actions/entity-cache-changes-set.spec.ts @@ -1,8 +1,4 @@ -import { - ChangeSet, - ChangeSetOperation, - changeSetItemFactory as cif, -} from '../../'; +import { ChangeSetOperation, changeSetItemFactory as cif } from '../../'; describe('changeSetItemFactory', () => { const hero = { id: 1, name: 'Hero 1' }; diff --git a/modules/data/spec/dataservices/data-service-error.spec.ts b/modules/data/spec/dataservices/data-service-error.spec.ts index 4ef9fbb219..630a764af6 100644 --- a/modules/data/spec/dataservices/data-service-error.spec.ts +++ b/modules/data/spec/dataservices/data-service-error.spec.ts @@ -1,5 +1,5 @@ import { HttpErrorResponse } from '@angular/common/http'; -import { DataServiceError, RequestData } from '../../'; +import { DataServiceError } from '../../'; describe('DataServiceError', () => { describe('#message', () => { diff --git a/modules/data/spec/dataservices/default-data.service.spec.ts b/modules/data/spec/dataservices/default-data.service.spec.ts index 071806d67e..00378d4ad8 100644 --- a/modules/data/spec/dataservices/default-data.service.spec.ts +++ b/modules/data/spec/dataservices/default-data.service.spec.ts @@ -1,6 +1,6 @@ import { TestBed } from '@angular/core/testing'; -import { HttpClient, HttpResponse } from '@angular/common/http'; +import { HttpClient } from '@angular/common/http'; import { HttpClientTestingModule, HttpTestingController, @@ -14,7 +14,6 @@ import { DefaultDataService, DefaultDataServiceFactory, DefaultHttpUrlGenerator, - EntityHttpResourceUrls, HttpUrlGenerator, DefaultDataServiceConfig, DataServiceError, diff --git a/modules/data/spec/dataservices/entity-data.service.spec.ts b/modules/data/spec/dataservices/entity-data.service.spec.ts index e7a43773a2..51bb5d2736 100644 --- a/modules/data/spec/dataservices/entity-data.service.spec.ts +++ b/modules/data/spec/dataservices/entity-data.service.spec.ts @@ -7,11 +7,6 @@ import { Observable } from 'rxjs'; import { Update } from '@ngrx/entity'; import { - createEntityDefinition, - EntityDefinition, - EntityMetadata, - EntityMetadataMap, - ENTITY_METADATA_TOKEN, DefaultDataService, DefaultDataServiceFactory, HttpUrlGenerator, diff --git a/modules/data/spec/effects/entity-cache-effects.spec.ts b/modules/data/spec/effects/entity-cache-effects.spec.ts index 7a24186597..14210a0fe9 100644 --- a/modules/data/spec/effects/entity-cache-effects.spec.ts +++ b/modules/data/spec/effects/entity-cache-effects.spec.ts @@ -2,17 +2,8 @@ import { TestBed } from '@angular/core/testing'; import { Action } from '@ngrx/store'; import { Actions } from '@ngrx/effects'; - -import { - asapScheduler, - Observable, - of, - merge, - ReplaySubject, - Subject, - throwError, -} from 'rxjs'; -import { first, mergeMap, observeOn, tap } from 'rxjs/operators'; +import { observeOn } from 'rxjs/operators'; +import { asapScheduler, ReplaySubject, Subject } from 'rxjs'; import { EntityCacheEffects, diff --git a/modules/data/spec/effects/entity-effects.marbles.spec.ts b/modules/data/spec/effects/entity-effects.marbles.spec.ts index 3bb238bcf4..32094c00f2 100644 --- a/modules/data/spec/effects/entity-effects.marbles.spec.ts +++ b/modules/data/spec/effects/entity-effects.marbles.spec.ts @@ -2,7 +2,7 @@ import { TestBed } from '@angular/core/testing'; import { cold, hot, getTestScheduler } from 'jasmine-marbles'; -import { Observable, of, Subject } from 'rxjs'; +import { Observable } from 'rxjs'; import { Actions } from '@ngrx/effects'; import { Update } from '@ngrx/entity'; diff --git a/modules/data/spec/effects/entity-effects.spec.ts b/modules/data/spec/effects/entity-effects.spec.ts index aebee4e4de..a2c4b4ddbc 100644 --- a/modules/data/spec/effects/entity-effects.spec.ts +++ b/modules/data/spec/effects/entity-effects.spec.ts @@ -4,7 +4,7 @@ import { Action } from '@ngrx/store'; import { Actions } from '@ngrx/effects'; import { Update } from '@ngrx/entity'; -import { Observable, of, merge, ReplaySubject, throwError, timer } from 'rxjs'; +import { of, merge, ReplaySubject, throwError, timer } from 'rxjs'; import { delay, first, mergeMap } from 'rxjs/operators'; import { diff --git a/modules/data/spec/entity-data.module.spec.ts b/modules/data/spec/entity-data.module.spec.ts index 93f401fd30..0132670e50 100644 --- a/modules/data/spec/entity-data.module.spec.ts +++ b/modules/data/spec/entity-data.module.spec.ts @@ -11,8 +11,8 @@ import { Actions, Effect, EffectsModule } from '@ngrx/effects'; // Not using marble testing import { TestBed } from '@angular/core/testing'; -import { Observable, of, Subject } from 'rxjs'; -import { map, skip, tap } from 'rxjs/operators'; +import { Observable } from 'rxjs'; +import { map, skip } from 'rxjs/operators'; import { EntityCache, diff --git a/modules/data/spec/entity-services/entity-collection-service.spec.ts b/modules/data/spec/entity-services/entity-collection-service.spec.ts index 06e10d1334..36fe10df22 100644 --- a/modules/data/spec/entity-services/entity-collection-service.spec.ts +++ b/modules/data/spec/entity-services/entity-collection-service.spec.ts @@ -1,19 +1,11 @@ import { Injectable } from '@angular/core'; -import { ComponentFixture, inject, TestBed } from '@angular/core/testing'; +import { TestBed } from '@angular/core/testing'; import { HttpErrorResponse } from '@angular/common/http'; import { Action, StoreModule, Store } from '@ngrx/store'; import { Actions, EffectsModule } from '@ngrx/effects'; -import { Observable, of, ReplaySubject, throwError, timer } from 'rxjs'; -import { - delay, - filter, - first, - mergeMap, - skip, - tap, - withLatestFrom, -} from 'rxjs/operators'; +import { Observable, of, throwError, timer } from 'rxjs'; +import { delay, filter, mergeMap, tap, withLatestFrom } from 'rxjs/operators'; import { commandDispatchTest } from '../dispatchers/entity-dispatcher.spec'; import { @@ -24,7 +16,6 @@ import { EntityAction, EntityActionFactory, EntityCache, - EntityCollection, EntityOp, EntityMetadataMap, EntityDataModule, diff --git a/modules/data/spec/entity-services/entity-services.spec.ts b/modules/data/spec/entity-services/entity-services.spec.ts index a2f8d3f36e..4dec048237 100644 --- a/modules/data/spec/entity-services/entity-services.spec.ts +++ b/modules/data/spec/entity-services/entity-services.spec.ts @@ -1,19 +1,8 @@ -import { Injectable } from '@angular/core'; -import { ComponentFixture, inject, TestBed } from '@angular/core/testing'; -import { HttpErrorResponse } from '@angular/common/http'; +import { TestBed } from '@angular/core/testing'; import { Action, StoreModule, Store } from '@ngrx/store'; import { Actions, EffectsModule } from '@ngrx/effects'; - -import { Observable, of, ReplaySubject, throwError, timer } from 'rxjs'; -import { - delay, - filter, - first, - mergeMap, - skip, - tap, - withLatestFrom, -} from 'rxjs/operators'; +import { Observable } from 'rxjs'; +import { first, skip } from 'rxjs/operators'; import { EntityAction, diff --git a/modules/data/spec/reducers/entity-cache-reducer.spec.ts b/modules/data/spec/reducers/entity-cache-reducer.spec.ts index f66ec95975..2d5235bdf7 100644 --- a/modules/data/spec/reducers/entity-cache-reducer.spec.ts +++ b/modules/data/spec/reducers/entity-cache-reducer.spec.ts @@ -28,7 +28,6 @@ import { ChangeSet, ChangeSetOperation, Logger, - EntityMetadata, } from '../..'; class Hero { diff --git a/modules/data/spec/selectors/related-entity-selectors.spec.ts b/modules/data/spec/selectors/related-entity-selectors.spec.ts index 0d56cd407f..612b1dbb24 100644 --- a/modules/data/spec/selectors/related-entity-selectors.spec.ts +++ b/modules/data/spec/selectors/related-entity-selectors.spec.ts @@ -1,15 +1,9 @@ -import { ComponentFixture, TestBed } from '@angular/core/testing'; -import { - Action, - createSelector, - Selector, - StoreModule, - Store, -} from '@ngrx/store'; +import { TestBed } from '@angular/core/testing'; +import { createSelector, StoreModule, Store } from '@ngrx/store'; import { Actions } from '@ngrx/effects'; import { Update } from '@ngrx/entity'; -import { Observable, Subject } from 'rxjs'; +import { Observable } from 'rxjs'; import { skip } from 'rxjs/operators'; import { diff --git a/modules/data/src/actions/entity-action-factory.ts b/modules/data/src/actions/entity-action-factory.ts index b2b838ca57..9f69700f78 100644 --- a/modules/data/src/actions/entity-action-factory.ts +++ b/modules/data/src/actions/entity-action-factory.ts @@ -1,5 +1,4 @@ import { Injectable } from '@angular/core'; -import { Action } from '@ngrx/store'; import { EntityOp } from './entity-op'; import { diff --git a/modules/data/src/actions/entity-action-operators.ts b/modules/data/src/actions/entity-action-operators.ts index 82adeab936..a712c05253 100644 --- a/modules/data/src/actions/entity-action-operators.ts +++ b/modules/data/src/actions/entity-action-operators.ts @@ -1,7 +1,4 @@ -import { Action } from '@ngrx/store'; -import { Actions } from '@ngrx/effects'; - -import { Observable, OperatorFunction } from 'rxjs'; +import { OperatorFunction } from 'rxjs'; import { filter } from 'rxjs/operators'; import { EntityAction } from './entity-action'; diff --git a/modules/data/src/actions/entity-action.ts b/modules/data/src/actions/entity-action.ts index f658e4f680..2bdce209cf 100644 --- a/modules/data/src/actions/entity-action.ts +++ b/modules/data/src/actions/entity-action.ts @@ -1,4 +1,3 @@ -import { Injectable } from '@angular/core'; import { Action } from '@ngrx/store'; import { EntityOp } from './entity-op'; diff --git a/modules/data/src/actions/entity-cache-change-set.ts b/modules/data/src/actions/entity-cache-change-set.ts index 6da7c10eab..e9c4dcd201 100644 --- a/modules/data/src/actions/entity-cache-change-set.ts +++ b/modules/data/src/actions/entity-cache-change-set.ts @@ -1,10 +1,5 @@ -import { Action } from '@ngrx/store'; import { Update } from '@ngrx/entity'; -import { EntityActionOptions } from './entity-action'; -import { EntityCacheAction } from './entity-cache-action'; -import { DataServiceError } from '../dataservices/data-service-error'; - export enum ChangeSetOperation { Add = 'Add', Delete = 'Delete', diff --git a/modules/data/src/dataservices/default-data-service-config.ts b/modules/data/src/dataservices/default-data-service-config.ts index 0beff79a1c..674d762560 100644 --- a/modules/data/src/dataservices/default-data-service-config.ts +++ b/modules/data/src/dataservices/default-data-service-config.ts @@ -1,4 +1,4 @@ -import { HttpUrlGenerator, EntityHttpResourceUrls } from './http-url-generator'; +import { EntityHttpResourceUrls } from './http-url-generator'; /** * Optional configuration settings for an entity collection data service diff --git a/modules/data/src/dataservices/default-data.service.ts b/modules/data/src/dataservices/default-data.service.ts index 02b5d5b835..1108dadd35 100644 --- a/modules/data/src/dataservices/default-data.service.ts +++ b/modules/data/src/dataservices/default-data.service.ts @@ -6,7 +6,7 @@ import { } from '@angular/common/http'; import { Observable, of, throwError } from 'rxjs'; -import { catchError, delay, map, tap, timeout } from 'rxjs/operators'; +import { catchError, delay, map, timeout } from 'rxjs/operators'; import { Update } from '@ngrx/entity'; diff --git a/modules/data/src/dataservices/entity-cache-data.service.ts b/modules/data/src/dataservices/entity-cache-data.service.ts index 8efe1256b8..101e5def77 100644 --- a/modules/data/src/dataservices/entity-cache-data.service.ts +++ b/modules/data/src/dataservices/entity-cache-data.service.ts @@ -1,9 +1,5 @@ import { Injectable, Optional } from '@angular/core'; -import { - HttpClient, - HttpErrorResponse, - HttpParams, -} from '@angular/common/http'; +import { HttpClient } from '@angular/common/http'; import { Observable, throwError } from 'rxjs'; import { catchError, delay, map, timeout } from 'rxjs/operators'; diff --git a/modules/data/src/dataservices/http-url-generator.ts b/modules/data/src/dataservices/http-url-generator.ts index 24418f4d60..c950ccf59a 100644 --- a/modules/data/src/dataservices/http-url-generator.ts +++ b/modules/data/src/dataservices/http-url-generator.ts @@ -1,4 +1,4 @@ -import { Inject, Injectable, InjectionToken, Optional } from '@angular/core'; +import { Injectable } from '@angular/core'; import { Pluralizer } from '../utils/interfaces'; /** diff --git a/modules/data/src/dataservices/persistence-result-handler.service.ts b/modules/data/src/dataservices/persistence-result-handler.service.ts index accb398b50..e4f9cc7dad 100644 --- a/modules/data/src/dataservices/persistence-result-handler.service.ts +++ b/modules/data/src/dataservices/persistence-result-handler.service.ts @@ -1,15 +1,13 @@ import { Injectable } from '@angular/core'; import { Action } from '@ngrx/store'; -import { Observable, of } from 'rxjs'; - import { DataServiceError, EntityActionDataServiceError, } from './data-service-error'; import { EntityAction } from '../actions/entity-action'; import { EntityActionFactory } from '../actions/entity-action-factory'; -import { EntityOp, makeErrorOp, makeSuccessOp } from '../actions/entity-op'; +import { makeErrorOp, makeSuccessOp } from '../actions/entity-op'; import { Logger } from '../utils/interfaces'; /** diff --git a/modules/data/src/dispatchers/entity-cache-dispatcher.ts b/modules/data/src/dispatchers/entity-cache-dispatcher.ts index d2f255246c..cdeedaf691 100644 --- a/modules/data/src/dispatchers/entity-cache-dispatcher.ts +++ b/modules/data/src/dispatchers/entity-cache-dispatcher.ts @@ -1,24 +1,16 @@ import { Injectable, Inject } from '@angular/core'; -import { - Action, - createSelector, - ScannedActionsSubject, - select, - Store, -} from '@ngrx/store'; +import { Action, ScannedActionsSubject, Store } from '@ngrx/store'; import { Observable, of, Subscription, throwError } from 'rxjs'; -import { filter, map, mergeMap, shareReplay, take } from 'rxjs/operators'; +import { filter, mergeMap, shareReplay, take } from 'rxjs/operators'; import { CorrelationIdGenerator } from '../utils/correlation-id-generator'; -import { EntityAction, EntityActionOptions } from '../actions/entity-action'; -import { EntityActionFactory } from '../actions/entity-action-factory'; +import { EntityActionOptions } from '../actions/entity-action'; import { EntityCache } from '../reducers/entity-cache'; import { EntityDispatcherDefaultOptions } from './entity-dispatcher-default-options'; import { MergeStrategy } from '../actions/merge-strategy'; import { PersistanceCanceled } from './entity-dispatcher'; -import { UpdateResponseData } from '../actions/update-response-data'; import { ChangeSet, ChangeSetItem } from '../actions/entity-cache-change-set'; import { diff --git a/modules/data/src/dispatchers/entity-commands.ts b/modules/data/src/dispatchers/entity-commands.ts index 3b563c306e..96d2b8d262 100644 --- a/modules/data/src/dispatchers/entity-commands.ts +++ b/modules/data/src/dispatchers/entity-commands.ts @@ -1,6 +1,5 @@ import { Observable } from 'rxjs'; import { EntityActionOptions } from '../actions/entity-action'; -import { MergeStrategy } from '../actions/merge-strategy'; import { QueryParams } from '../dataservices/interfaces'; /** Commands that update the remote server. */ diff --git a/modules/data/src/dispatchers/entity-dispatcher-base.ts b/modules/data/src/dispatchers/entity-dispatcher-base.ts index aaf5761533..f33d598821 100644 --- a/modules/data/src/dispatchers/entity-dispatcher-base.ts +++ b/modules/data/src/dispatchers/entity-dispatcher-base.ts @@ -1,7 +1,7 @@ -import { Action, createSelector, select, Store } from '@ngrx/store'; +import { Action, createSelector, Store } from '@ngrx/store'; import { IdSelector, Update } from '@ngrx/entity'; -import { Observable, of, throwError, OperatorFunction } from 'rxjs'; +import { Observable, of, throwError } from 'rxjs'; import { filter, map, diff --git a/modules/data/src/dispatchers/entity-dispatcher-factory.ts b/modules/data/src/dispatchers/entity-dispatcher-factory.ts index 5f21792643..d71c38b700 100644 --- a/modules/data/src/dispatchers/entity-dispatcher-factory.ts +++ b/modules/data/src/dispatchers/entity-dispatcher-factory.ts @@ -1,24 +1,20 @@ import { Inject, Injectable, OnDestroy } from '@angular/core'; import { Action, Store, ScannedActionsSubject } from '@ngrx/store'; -import { IdSelector, Update } from '@ngrx/entity'; +import { IdSelector } from '@ngrx/entity'; import { Observable, Subscription } from 'rxjs'; import { shareReplay } from 'rxjs/operators'; import { CorrelationIdGenerator } from '../utils/correlation-id-generator'; import { EntityDispatcherDefaultOptions } from './entity-dispatcher-default-options'; -import { defaultSelectId, toUpdateFactory } from '../utils/utilities'; -import { EntityAction } from '../actions/entity-action'; +import { defaultSelectId } from '../utils/utilities'; import { EntityActionFactory } from '../actions/entity-action-factory'; import { EntityCache } from '../reducers/entity-cache'; import { EntityCacheSelector, ENTITY_CACHE_SELECTOR_TOKEN, - createEntityCacheSelector, } from '../selectors/entity-cache-selector'; import { EntityDispatcher } from './entity-dispatcher'; import { EntityDispatcherBase } from './entity-dispatcher-base'; -import { EntityOp } from '../actions/entity-op'; -import { QueryParams } from '../dataservices/interfaces'; /** Creates EntityDispatchers for entity collections */ @Injectable() diff --git a/modules/data/src/effects/entity-cache-effects.ts b/modules/data/src/effects/entity-cache-effects.ts index 39b468b67c..4c844e626d 100644 --- a/modules/data/src/effects/entity-cache-effects.ts +++ b/modules/data/src/effects/entity-cache-effects.ts @@ -38,7 +38,6 @@ import { import { EntityCacheDataService } from '../dataservices/entity-cache-data.service'; import { ENTITY_EFFECTS_SCHEDULER } from './entity-effects-scheduler'; import { Logger } from '../utils/interfaces'; -import { PersistenceResultHandler } from '../dataservices/persistence-result-handler.service'; @Injectable() export class EntityCacheEffects { diff --git a/modules/data/src/effects/entity-effects-scheduler.ts b/modules/data/src/effects/entity-effects-scheduler.ts index 5e028c3b6f..5808e3ce9f 100644 --- a/modules/data/src/effects/entity-effects-scheduler.ts +++ b/modules/data/src/effects/entity-effects-scheduler.ts @@ -1,4 +1,4 @@ -import { Inject, Injectable, InjectionToken, Optional } from '@angular/core'; +import { InjectionToken } from '@angular/core'; import { SchedulerLike } from 'rxjs'; // See https://github.com/ReactiveX/rxjs/blob/master/doc/marble-testing.md diff --git a/modules/data/src/effects/entity-effects.ts b/modules/data/src/effects/entity-effects.ts index 363e9f5e8b..71a9a14ea8 100644 --- a/modules/data/src/effects/entity-effects.ts +++ b/modules/data/src/effects/entity-effects.ts @@ -4,14 +4,7 @@ import { Actions, Effect } from '@ngrx/effects'; import { Update } from '@ngrx/entity'; import { asyncScheduler, Observable, of, race, SchedulerLike } from 'rxjs'; -import { - concatMap, - catchError, - delay, - filter, - map, - mergeMap, -} from 'rxjs/operators'; +import { catchError, delay, filter, map, mergeMap } from 'rxjs/operators'; import { EntityAction } from '../actions/entity-action'; import { EntityActionFactory } from '../actions/entity-action-factory'; diff --git a/modules/data/src/entity-data-without-effects.module.ts b/modules/data/src/entity-data-without-effects.module.ts index 4acb6f090b..61b2009938 100644 --- a/modules/data/src/entity-data-without-effects.module.ts +++ b/modules/data/src/entity-data-without-effects.module.ts @@ -10,7 +10,6 @@ import { import { Action, - ActionReducer, combineReducers, MetaReducer, ReducerManager, @@ -24,13 +23,9 @@ import { EntityActionFactory } from './actions/entity-action-factory'; import { EntityCache } from './reducers/entity-cache'; import { EntityCacheDispatcher } from './dispatchers/entity-cache-dispatcher'; import { entityCacheSelectorProvider } from './selectors/entity-cache-selector'; -import { EntityCollectionService } from './entity-services/entity-collection-service'; import { EntityCollectionServiceElementsFactory } from './entity-services/entity-collection-service-elements-factory'; import { EntityCollectionServiceFactory } from './entity-services/entity-collection-service-factory'; -import { - EntityCollectionServiceMap, - EntityServices, -} from './entity-services/entity-services'; +import { EntityServices } from './entity-services/entity-services'; import { EntityCollection } from './reducers/entity-collection'; import { EntityCollectionCreator } from './reducers/entity-collection-creator'; import { EntityCollectionReducerFactory } from './reducers/entity-collection-reducer'; @@ -38,12 +33,7 @@ import { EntityCollectionReducerMethodsFactory } from './reducers/entity-collect import { EntityCollectionReducerRegistry } from './reducers/entity-collection-reducer-registry'; import { EntityDispatcherFactory } from './dispatchers/entity-dispatcher-factory'; import { EntityDefinitionService } from './entity-metadata/entity-definition.service'; -import { EntityEffects } from './effects/entity-effects'; -import { - EntityMetadataMap, - ENTITY_METADATA_TOKEN, -} from './entity-metadata/entity-metadata'; - +import { EntityMetadataMap } from './entity-metadata/entity-metadata'; import { EntityCacheReducerFactory } from './reducers/entity-cache-reducer'; import { ENTITY_CACHE_NAME, @@ -54,13 +44,11 @@ import { } from './reducers/constants'; import { DefaultLogger } from './utils/default-logger'; -import { DefaultPluralizer } from './utils/default-pluralizer'; -import { EntitySelectors } from './selectors/entity-selectors'; import { EntitySelectorsFactory } from './selectors/entity-selectors'; import { EntitySelectors$Factory } from './selectors/entity-selectors$'; import { EntityServicesBase } from './entity-services/entity-services-base'; import { EntityServicesElements } from './entity-services/entity-services-elements'; -import { Logger, Pluralizer, PLURAL_NAMES_TOKEN } from './utils/interfaces'; +import { Logger, PLURAL_NAMES_TOKEN } from './utils/interfaces'; export interface EntityDataModuleConfig { entityMetadata?: EntityMetadataMap; diff --git a/modules/data/src/entity-metadata/entity-definition.service.ts b/modules/data/src/entity-metadata/entity-definition.service.ts index 29631f2816..2c568632d2 100644 --- a/modules/data/src/entity-metadata/entity-definition.service.ts +++ b/modules/data/src/entity-metadata/entity-definition.service.ts @@ -1,4 +1,4 @@ -import { Inject, Injectable, InjectionToken, Optional } from '@angular/core'; +import { Inject, Injectable, Optional } from '@angular/core'; import { createEntityDefinition, EntityDefinition } from './entity-definition'; import { @@ -6,7 +6,6 @@ import { EntityMetadataMap, ENTITY_METADATA_TOKEN, } from './entity-metadata'; -import { ENTITY_CACHE_NAME } from '../reducers/constants'; export interface EntityDefinitions { [entityName: string]: EntityDefinition; diff --git a/modules/data/src/entity-metadata/entity-definition.ts b/modules/data/src/entity-metadata/entity-definition.ts index ad15199616..193c68cc17 100644 --- a/modules/data/src/entity-metadata/entity-definition.ts +++ b/modules/data/src/entity-metadata/entity-definition.ts @@ -1,14 +1,9 @@ -import { EntityState, EntityAdapter, createEntityAdapter } from '@ngrx/entity'; -import { Comparer, Dictionary, IdSelector, Update } from '@ngrx/entity'; +import { EntityAdapter, createEntityAdapter } from '@ngrx/entity'; +import { Comparer, IdSelector } from '@ngrx/entity'; -import { - EntitySelectors, - EntitySelectorsFactory, -} from '../selectors/entity-selectors'; import { EntityDispatcherDefaultOptions } from '../dispatchers/entity-dispatcher-default-options'; import { defaultSelectId } from '../utils/utilities'; import { EntityCollection } from '../reducers/entity-collection'; -import { EntityFilterFn } from './entity-filters'; import { EntityMetadata } from './entity-metadata'; export interface EntityDefinition { diff --git a/modules/data/src/entity-services/entity-collection-service-base.ts b/modules/data/src/entity-services/entity-collection-service-base.ts index 3044e87f70..02d23c0025 100644 --- a/modules/data/src/entity-services/entity-collection-service-base.ts +++ b/modules/data/src/entity-services/entity-collection-service-base.ts @@ -1,13 +1,10 @@ -import { Injectable } from '@angular/core'; import { Action, Store } from '@ngrx/store'; -import { Actions } from '@ngrx/effects'; import { Dictionary, IdSelector, Update } from '@ngrx/entity'; import { Observable } from 'rxjs'; import { EntityAction, EntityActionOptions } from '../actions/entity-action'; import { EntityActionGuard } from '../actions/entity-action-guard'; -import { EntityCache } from '../reducers/entity-cache'; import { EntityCollection, ChangeStateMap, diff --git a/modules/data/src/entity-services/entity-collection-service-elements-factory.ts b/modules/data/src/entity-services/entity-collection-service-elements-factory.ts index 6ea26ec862..113beea20e 100644 --- a/modules/data/src/entity-services/entity-collection-service-elements-factory.ts +++ b/modules/data/src/entity-services/entity-collection-service-elements-factory.ts @@ -1,6 +1,4 @@ import { Injectable } from '@angular/core'; -import { EntityCollectionService } from './entity-collection-service'; -import { EntityCollectionServiceBase } from './entity-collection-service-base'; import { EntityDispatcher } from '../dispatchers/entity-dispatcher'; import { EntityDispatcherFactory } from '../dispatchers/entity-dispatcher-factory'; import { EntityDefinitionService } from '../entity-metadata/entity-definition.service'; diff --git a/modules/data/src/entity-services/entity-services-base.ts b/modules/data/src/entity-services/entity-services-base.ts index cfcf41554f..8cef5ee329 100644 --- a/modules/data/src/entity-services/entity-services-base.ts +++ b/modules/data/src/entity-services/entity-services-base.ts @@ -1,4 +1,4 @@ -import { Inject, Injectable } from '@angular/core'; +import { Injectable } from '@angular/core'; import { Action, Store } from '@ngrx/store'; import { Observable } from 'rxjs'; @@ -6,14 +6,9 @@ import { Observable } from 'rxjs'; import { EntityAction } from '../actions/entity-action'; import { EntityCache } from '../reducers/entity-cache'; import { EntityCollectionService } from './entity-collection-service'; -import { EntityCollectionServiceBase } from './entity-collection-service-base'; import { EntityCollectionServiceFactory } from './entity-collection-service-factory'; import { EntityCollectionServiceMap, EntityServices } from './entity-services'; -import { EntitySelectorsFactory } from '../selectors/entity-selectors'; -import { - EntitySelectors$, - EntitySelectors$Factory, -} from '../selectors/entity-selectors$'; +import { EntitySelectors$ } from '../selectors/entity-selectors$'; import { EntityServicesElements } from './entity-services-elements'; // tslint:disable:member-ordering diff --git a/modules/data/src/entity-services/entity-services.ts b/modules/data/src/entity-services/entity-services.ts index af4ae4c0e5..aeabd6e3d6 100644 --- a/modules/data/src/entity-services/entity-services.ts +++ b/modules/data/src/entity-services/entity-services.ts @@ -4,7 +4,6 @@ import { Observable } from 'rxjs'; import { EntityAction } from '../actions/entity-action'; import { EntityCache } from '../reducers/entity-cache'; import { EntityCollectionService } from './entity-collection-service'; -import { EntityCollectionServiceFactory } from './entity-collection-service-factory'; // tslint:disable:member-ordering diff --git a/modules/data/src/reducers/constants.ts b/modules/data/src/reducers/constants.ts index 152cb215f5..3991f681f3 100644 --- a/modules/data/src/reducers/constants.ts +++ b/modules/data/src/reducers/constants.ts @@ -1,5 +1,5 @@ import { InjectionToken } from '@angular/core'; -import { Action, ActionReducer, MetaReducer } from '@ngrx/store'; +import { MetaReducer } from '@ngrx/store'; import { EntityCache } from './entity-cache'; export const ENTITY_CACHE_NAME = 'entityCache'; diff --git a/modules/data/src/reducers/entity-cache-reducer.ts b/modules/data/src/reducers/entity-cache-reducer.ts index f26e0d4ea8..81faac1a29 100644 --- a/modules/data/src/reducers/entity-cache-reducer.ts +++ b/modules/data/src/reducers/entity-cache-reducer.ts @@ -2,7 +2,6 @@ import { Injectable } from '@angular/core'; import { Action, ActionReducer } from '@ngrx/store'; import { EntityAction } from '../actions/entity-action'; -import { EntityActionDataServiceError } from '../dataservices/data-service-error'; import { EntityCache } from './entity-cache'; import { diff --git a/modules/data/src/reducers/entity-change-tracker-base.ts b/modules/data/src/reducers/entity-change-tracker-base.ts index 91ad97d969..46f36bd1b7 100644 --- a/modules/data/src/reducers/entity-change-tracker-base.ts +++ b/modules/data/src/reducers/entity-change-tracker-base.ts @@ -1,19 +1,7 @@ -import { - EntityAdapter, - EntityState, - Dictionary, - IdSelector, - Update, -} from '@ngrx/entity'; - -import { - ChangeState, - ChangeStateMap, - ChangeType, - EntityCollection, -} from './entity-collection'; +import { EntityAdapter, IdSelector, Update } from '@ngrx/entity'; + +import { ChangeType, EntityCollection } from './entity-collection'; import { defaultSelectId } from '../utils/utilities'; -import { EntityAction, EntityActionOptions } from '../actions/entity-action'; import { EntityChangeTracker } from './entity-change-tracker'; import { MergeStrategy } from '../actions/merge-strategy'; import { UpdateResponseData } from '../actions/update-response-data'; diff --git a/modules/data/src/reducers/entity-change-tracker.ts b/modules/data/src/reducers/entity-change-tracker.ts index b494d0cd0a..a402077f3d 100644 --- a/modules/data/src/reducers/entity-change-tracker.ts +++ b/modules/data/src/reducers/entity-change-tracker.ts @@ -1,10 +1,5 @@ import { Update } from '@ngrx/entity'; -import { - ChangeState, - ChangeStateMap, - ChangeType, - EntityCollection, -} from './entity-collection'; +import { EntityCollection } from './entity-collection'; import { MergeStrategy } from '../actions/merge-strategy'; import { UpdateResponseData } from '../actions/update-response-data'; diff --git a/modules/data/src/reducers/entity-collection-reducer-methods.ts b/modules/data/src/reducers/entity-collection-reducer-methods.ts index 3883876711..3cba7c5e64 100644 --- a/modules/data/src/reducers/entity-collection-reducer-methods.ts +++ b/modules/data/src/reducers/entity-collection-reducer-methods.ts @@ -1,17 +1,12 @@ import { Injectable } from '@angular/core'; - -import { Action } from '@ngrx/store'; -import { EntityAdapter, Dictionary, IdSelector, Update } from '@ngrx/entity'; - -import { merge } from 'rxjs/operators'; - +import { EntityAdapter, IdSelector, Update } from '@ngrx/entity'; import { ChangeStateMap, ChangeType, EntityCollection, } from './entity-collection'; import { EntityChangeTrackerBase } from './entity-change-tracker-base'; -import { defaultSelectId, toUpdateFactory } from '../utils/utilities'; +import { toUpdateFactory } from '../utils/utilities'; import { EntityAction } from '../actions/entity-action'; import { EntityActionDataServiceError } from '../dataservices/data-service-error'; import { EntityActionGuard } from '../actions/entity-action-guard'; diff --git a/modules/data/src/reducers/entity-collection-reducer-registry.ts b/modules/data/src/reducers/entity-collection-reducer-registry.ts index 29ed2d166a..fa74a52473 100644 --- a/modules/data/src/reducers/entity-collection-reducer-registry.ts +++ b/modules/data/src/reducers/entity-collection-reducer-registry.ts @@ -1,5 +1,5 @@ import { Inject, Injectable, Optional } from '@angular/core'; -import { ActionReducer, compose, MetaReducer } from '@ngrx/store'; +import { compose, MetaReducer } from '@ngrx/store'; import { EntityAction } from '../actions/entity-action'; import { EntityCollection } from './entity-collection'; diff --git a/modules/data/src/selectors/entity-cache-selector.ts b/modules/data/src/selectors/entity-cache-selector.ts index 732e361f73..88ec62d155 100644 --- a/modules/data/src/selectors/entity-cache-selector.ts +++ b/modules/data/src/selectors/entity-cache-selector.ts @@ -1,15 +1,5 @@ -import { - Inject, - Injectable, - InjectionToken, - Optional, - FactoryProvider, -} from '@angular/core'; -import { - createFeatureSelector, - createSelector, - MemoizedSelector, -} from '@ngrx/store'; +import { InjectionToken, Optional, FactoryProvider } from '@angular/core'; +import { createFeatureSelector, MemoizedSelector } from '@ngrx/store'; import { EntityCache } from '../reducers/entity-cache'; import { ENTITY_CACHE_NAME, diff --git a/modules/data/src/selectors/entity-selectors$.ts b/modules/data/src/selectors/entity-selectors$.ts index 4c8684386c..f1dde43f95 100644 --- a/modules/data/src/selectors/entity-selectors$.ts +++ b/modules/data/src/selectors/entity-selectors$.ts @@ -1,11 +1,5 @@ import { Inject, Injectable } from '@angular/core'; - -import { - createFeatureSelector, - createSelector, - Selector, - Store, -} from '@ngrx/store'; +import { Store } from '@ngrx/store'; import { Actions } from '@ngrx/effects'; import { Dictionary } from '@ngrx/entity'; @@ -25,8 +19,6 @@ import { EntityCollection, ChangeStateMap, } from '../reducers/entity-collection'; -import { EntityCollectionCreator } from '../reducers/entity-collection-creator'; -import { EntitySelectorsFactory } from './entity-selectors'; /** * The selector observable functions for entity collection members. diff --git a/modules/data/src/selectors/entity-selectors.ts b/modules/data/src/selectors/entity-selectors.ts index 67bd11652a..a8810802a6 100644 --- a/modules/data/src/selectors/entity-selectors.ts +++ b/modules/data/src/selectors/entity-selectors.ts @@ -2,11 +2,9 @@ import { Inject, Injectable, Optional } from '@angular/core'; // Prod build requires `MemoizedSelector even though not used. import { MemoizedSelector } from '@ngrx/store'; -import { createFeatureSelector, createSelector, Selector } from '@ngrx/store'; +import { createSelector, Selector } from '@ngrx/store'; import { Dictionary } from '@ngrx/entity'; -import { Observable } from 'rxjs'; - import { EntityCache } from '../reducers/entity-cache'; import { ENTITY_CACHE_SELECTOR_TOKEN, @@ -19,7 +17,6 @@ import { ChangeStateMap, } from '../reducers/entity-collection'; import { EntityCollectionCreator } from '../reducers/entity-collection-creator'; -import { EntityFilterFn } from '../entity-metadata/entity-filters'; import { EntityMetadata } from '../entity-metadata/entity-metadata'; /** diff --git a/package.json b/package.json index 8d4ea4714f..d91037aabe 100644 --- a/package.json +++ b/package.json @@ -187,4 +187,4 @@ "pre-commit": "lint-staged" } } -} \ No newline at end of file +} diff --git a/projects/example-app/src/app/core/effects/user.effects.ts b/projects/example-app/src/app/core/effects/user.effects.ts index 5d11660efb..2733e1e3ff 100644 --- a/projects/example-app/src/app/core/effects/user.effects.ts +++ b/projects/example-app/src/app/core/effects/user.effects.ts @@ -1,4 +1,4 @@ -import { Injectable, Inject } from '@angular/core'; +import { Injectable } from '@angular/core'; import { fromEvent, merge, timer } from 'rxjs'; import { map, switchMapTo } from 'rxjs/operators'; diff --git a/projects/example-app/src/app/reducers/index.ts b/projects/example-app/src/app/reducers/index.ts index 89337bcf8c..2e74f6ac70 100644 --- a/projects/example-app/src/app/reducers/index.ts +++ b/projects/example-app/src/app/reducers/index.ts @@ -4,7 +4,6 @@ import { ActionReducer, MetaReducer, Action, - combineReducers, ActionReducerMap, } from '@ngrx/store'; import { environment } from '../../environments/environment'; From 0385c353b0007cf9cfc22d06b27ebbcefbe250fc Mon Sep 17 00:00:00 2001 From: Ryan Streur Date: Wed, 21 Aug 2019 20:02:14 -0700 Subject: [PATCH 08/18] docs: fix typo in serializability intro section (#2076) --- projects/ngrx.io/content/marketing/docs.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/projects/ngrx.io/content/marketing/docs.md b/projects/ngrx.io/content/marketing/docs.md index bad2c7bac6..ededc7e213 100644 --- a/projects/ngrx.io/content/marketing/docs.md +++ b/projects/ngrx.io/content/marketing/docs.md @@ -9,7 +9,7 @@ NgRx provides state management for creating maintainable explicit applications, ### Serializability -By normalizing state changes and pass them through observables, NgRx provides serializability and ensures state is predictably stored. This enables to save the state to an external storage, for example, `localStorage`. +By normalizing state changes and passing them through observables, NgRx provides serializability and ensures state is predictably stored. This enables to save the state to an external storage, for example, `localStorage`. In addition, it also allows to inspect, download, upload, and dispatch actions, all from the [Store Devtools](guide/store-devtools). From ddab4cd2aea9b73726e0954746ee57655b40466f Mon Sep 17 00:00:00 2001 From: mxdmedia <34487837+mxdmedia@users.noreply.github.com> Date: Wed, 21 Aug 2019 22:20:02 -0500 Subject: [PATCH 09/18] docs(data): improve DefaultDataServiceConfig root parameter docs (#2075) Adds more details for the DefaultDataServiceConfig api docs and Entity Dataservice doc page. Specifically, added details and examples for providing a remote api to the DefaultDataServiceConfig root parameter. Current docs do not include this information, and it this makes it clear how one would use a remote api, which is a very common use case. Closes #2071 --- modules/data/src/dataservices/default-data-service-config.ts | 5 ++++- projects/ngrx.io/content/guide/data/entity-dataservice.md | 4 ++-- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/modules/data/src/dataservices/default-data-service-config.ts b/modules/data/src/dataservices/default-data-service-config.ts index 674d762560..b4bfff3329 100644 --- a/modules/data/src/dataservices/default-data-service-config.ts +++ b/modules/data/src/dataservices/default-data-service-config.ts @@ -5,7 +5,10 @@ import { EntityHttpResourceUrls } from './http-url-generator'; * such as the `DefaultDataService`. */ export abstract class DefaultDataServiceConfig { - /** root path of the web api (default: 'api') */ + /** + * root path of the web api. may also include protocol, domain, and port + * for remote api, e.g.: `'https://api-domain.com:8000/api/v1'` (default: 'api') + */ root?: string; /** * Known entity HttpResourceUrls. diff --git a/projects/ngrx.io/content/guide/data/entity-dataservice.md b/projects/ngrx.io/content/guide/data/entity-dataservice.md index 931b3d9f22..e667dfe086 100644 --- a/projects/ngrx.io/content/guide/data/entity-dataservice.md +++ b/projects/ngrx.io/content/guide/data/entity-dataservice.md @@ -101,7 +101,7 @@ The shared configuration values are almost always specific to the application an The NgRx Data library defines a `DefaultDataServiceConfig` for conveying shared configuration to an entity collection data service. -The most important configuration property, `root`, returns the _root_ of every web api URL, the parts that come before the entity resource name. +The most important configuration property, `root`, returns the _root_ of every web api URL, the parts that come before the entity resource name. If you are using a remote API, this value can include the protocol, domain, port, and root path, such as `https://my-api-domain.com:8000/api/v1`. For a `DefaultDataService`, the default value is `'api'`, which results in URLs such as `api/heroes`. @@ -121,7 +121,7 @@ First, create a custom configuration object of type `DefaultDataServiceConfig` : ```typescript const defaultDataServiceConfig: DefaultDataServiceConfig = { - root: 'api', + root: 'https://my-api-domain.com:8000/api/v1', timeout: 3000, // request timeout } ``` From 34c0420d06d075a1c81de6e50cc992b85e5bd268 Mon Sep 17 00:00:00 2001 From: Marcin Majkowski Date: Thu, 22 Aug 2019 05:22:30 +0200 Subject: [PATCH 10/18] fix(data): use correct guard when handling optimistic update (#2060) Closes #2059 --- modules/data/src/dispatchers/entity-dispatcher-base.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/data/src/dispatchers/entity-dispatcher-base.ts b/modules/data/src/dispatchers/entity-dispatcher-base.ts index f33d598821..1e1aa7d496 100644 --- a/modules/data/src/dispatchers/entity-dispatcher-base.ts +++ b/modules/data/src/dispatchers/entity-dispatcher-base.ts @@ -344,7 +344,7 @@ export class EntityDispatcherBase implements EntityDispatcher { options ); if (options.isOptimistic) { - this.guard.mustBeEntity(action as EntityAction); + this.guard.mustBeUpdate(action); } this.dispatch(action); return this.getResponseData$>( From eb5dbb9979cadf40780d323ff30bec5cd3b96458 Mon Sep 17 00:00:00 2001 From: Kamran Asif Date: Fri, 23 Aug 2019 13:02:00 -0400 Subject: [PATCH 11/18] Update index.ts (#2081) fix(store): Expose ActionType interface from store/src/models. ActionType is useful for extracting the response type of the new action creators. --- modules/store/src/index.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/modules/store/src/index.ts b/modules/store/src/index.ts index 420576bb8b..2650461279 100644 --- a/modules/store/src/index.ts +++ b/modules/store/src/index.ts @@ -4,6 +4,7 @@ export { ActionReducer, ActionReducerMap, ActionReducerFactory, + ActionType, Creator, MetaReducer, Selector, From 6946e2eb97c32440eb3923fac031b6b639069a8b Mon Sep 17 00:00:00 2001 From: John Crowson Date: Mon, 26 Aug 2019 20:45:21 -0600 Subject: [PATCH 12/18] feat(store): add verbose error message for undefined feature state in development mode (#2078) Closes #1897 --- modules/store/spec/selector.spec.ts | 129 ++++++++++++++++++++++++---- modules/store/src/selector.ts | 18 +++- 2 files changed, 127 insertions(+), 20 deletions(-) diff --git a/modules/store/spec/selector.spec.ts b/modules/store/spec/selector.spec.ts index 4f24b2f7a4..368a4ed187 100644 --- a/modules/store/spec/selector.spec.ts +++ b/modules/store/spec/selector.spec.ts @@ -1,3 +1,4 @@ +import * as ngCore from '@angular/core'; import { cold } from 'jasmine-marbles'; import { createSelector, @@ -40,9 +41,11 @@ describe('Selectors', () => { it('should deliver the value of selectors to the projection function', () => { const projectFn = jasmine.createSpy('projectionFn'); - const selector = createSelector(incrementOne, incrementTwo, projectFn)( - {} - ); + const selector = createSelector( + incrementOne, + incrementTwo, + projectFn + )({}); expect(projectFn).toHaveBeenCalledWith(countOne, countTwo); }); @@ -50,7 +53,11 @@ describe('Selectors', () => { it('should allow an override of the selector return', () => { const projectFn = jasmine.createSpy('projectionFn').and.returnValue(2); - const selector = createSelector(incrementOne, incrementTwo, projectFn); + const selector = createSelector( + incrementOne, + incrementTwo, + projectFn + ); expect(selector.projector()).toBe(2); @@ -63,7 +70,11 @@ describe('Selectors', () => { it('should be possible to test a projector fn independent from the selectors it is composed of', () => { const projectFn = jasmine.createSpy('projectionFn'); - const selector = createSelector(incrementOne, incrementTwo, projectFn); + const selector = createSelector( + incrementOne, + incrementTwo, + projectFn + ); selector.projector('', ''); @@ -81,7 +92,10 @@ describe('Selectors', () => { return state.unchanged; }); const projectFn = jasmine.createSpy('projectionFn'); - const selector = createSelector(neverChangingSelector, projectFn); + const selector = createSelector( + neverChangingSelector, + projectFn + ); selector(firstState); selector(secondState); @@ -115,7 +129,10 @@ describe('Selectors', () => { it('should allow you to release memoized arguments', () => { const state = { first: 'state' }; const projectFn = jasmine.createSpy('projectionFn'); - const selector = createSelector(incrementOne, projectFn); + const selector = createSelector( + incrementOne, + projectFn + ); selector(state); selector(state); @@ -127,9 +144,18 @@ describe('Selectors', () => { }); it('should recursively release ancestor selectors', () => { - const grandparent = createSelector(incrementOne, a => a); - const parent = createSelector(grandparent, a => a); - const child = createSelector(parent, a => a); + const grandparent = createSelector( + incrementOne, + a => a + ); + const parent = createSelector( + grandparent, + a => a + ); + const child = createSelector( + parent, + a => a + ); spyOn(grandparent, 'release').and.callThrough(); spyOn(parent, 'release').and.callThrough(); @@ -245,16 +271,20 @@ describe('Selectors', () => { describe('createSelector with arrays', () => { it('should deliver the value of selectors to the projection function', () => { const projectFn = jasmine.createSpy('projectionFn'); - const selector = createSelector([incrementOne, incrementTwo], projectFn)( - {} - ); + const selector = createSelector( + [incrementOne, incrementTwo], + projectFn + )({}); expect(projectFn).toHaveBeenCalledWith(countOne, countTwo); }); it('should be possible to test a projector fn independent from the selectors it is composed of', () => { const projectFn = jasmine.createSpy('projectionFn'); - const selector = createSelector([incrementOne, incrementTwo], projectFn); + const selector = createSelector( + [incrementOne, incrementTwo], + projectFn + ); selector.projector('', ''); @@ -272,7 +302,10 @@ describe('Selectors', () => { return state.unchanged; }); const projectFn = jasmine.createSpy('projectionFn'); - const selector = createSelector([neverChangingSelector], projectFn); + const selector = createSelector( + [neverChangingSelector], + projectFn + ); selector(firstState); selector(secondState); @@ -304,7 +337,10 @@ describe('Selectors', () => { it('should allow you to release memoized arguments', () => { const state = { first: 'state' }; const projectFn = jasmine.createSpy('projectionFn'); - const selector = createSelector([incrementOne], projectFn); + const selector = createSelector( + [incrementOne], + projectFn + ); selector(state); selector(state); @@ -316,9 +352,18 @@ describe('Selectors', () => { }); it('should recursively release ancestor selectors', () => { - const grandparent = createSelector([incrementOne], a => a); - const parent = createSelector([grandparent], a => a); - const child = createSelector([parent], a => a); + const grandparent = createSelector( + [incrementOne], + a => a + ); + const parent = createSelector( + [grandparent], + a => a + ); + const child = createSelector( + [parent], + a => a + ); spyOn(grandparent, 'release').and.callThrough(); spyOn(parent, 'release').and.callThrough(); @@ -433,9 +478,11 @@ describe('Selectors', () => { describe('createFeatureSelector', () => { let featureName = '@ngrx/router-store'; let featureSelector: (state: any) => number; + let warnSpy: jasmine.Spy; beforeEach(() => { featureSelector = createFeatureSelector(featureName); + warnSpy = spyOn(console, 'warn'); }); it('should memoize the result', () => { @@ -455,6 +502,50 @@ describe('Selectors', () => { ); expect(featureState$).toBeObservable(expected$); + expect(warnSpy).not.toHaveBeenCalled(); + }); + + it('should warn if the feature does not exist in the state', () => { + spyOn(ngCore, 'isDevMode').and.returnValue(true); + + const state = { otherState: '' }; + + const state$ = cold('a', { a: state }); + const expected$ = cold('a', { a: undefined }); + + const featureState$ = state$.pipe( + map(featureSelector), + distinctUntilChanged() + ); + + expect(featureState$).toBeObservable(expected$); + expect(warnSpy).toHaveBeenCalledWith( + 'The feature name "@ngrx/router-store" does not exist ' + + 'in the state, therefore createFeatureSelector cannot ' + + 'access it. Be sure it is imported in a loaded module using ' + + "StoreModule.forRoot('@ngrx/router-store', ...) or " + + "StoreModule.forFeature('@ngrx/router-store', ...). If the " + + 'default state is intended to be undefined, as is the case ' + + 'with router state, this development-only warning message can ' + + 'be ignored.' + ); + }); + + it('should not warn if not in development mode', () => { + spyOn(ngCore, 'isDevMode').and.returnValue(false); + + const state = { otherState: '' }; + + const state$ = cold('a', { a: state }); + const expected$ = cold('a', { a: undefined }); + + const featureState$ = state$.pipe( + map(featureSelector), + distinctUntilChanged() + ); + + expect(featureState$).toBeObservable(expected$); + expect(warnSpy).not.toHaveBeenCalled(); }); }); diff --git a/modules/store/src/selector.ts b/modules/store/src/selector.ts index 3600cd78a9..5de9eee060 100644 --- a/modules/store/src/selector.ts +++ b/modules/store/src/selector.ts @@ -1,4 +1,5 @@ import { Selector, SelectorWithProps } from './models'; +import { isDevMode } from '@angular/core'; export type AnyFn = (...args: any[]) => any; @@ -274,6 +275,7 @@ export function createSelector( Selector, Selector, Selector, + Selector, Selector, Selector @@ -602,7 +604,21 @@ export function createFeatureSelector( featureName: any ): MemoizedSelector { return createSelector( - (state: any) => state[featureName], + (state: any) => { + const featureState = state[featureName]; + if (isDevMode() && featureState === undefined) { + console.warn( + `The feature name \"${featureName}\" does ` + + 'not exist in the state, therefore createFeatureSelector ' + + 'cannot access it. Be sure it is imported in a loaded module ' + + `using StoreModule.forRoot('${featureName}', ...) or ` + + `StoreModule.forFeature('${featureName}', ...). If the default ` + + 'state is intended to be undefined, as is the case with router ' + + 'state, this development-only warning message can be ignored.' + ); + } + return featureState; + }, (featureState: any) => featureState ); } From 303f9fee9cbd94c83302be9199ed8d1120f4f365 Mon Sep 17 00:00:00 2001 From: EV Date: Tue, 27 Aug 2019 04:47:14 +0200 Subject: [PATCH 13/18] docs(store-devtools): add recipe to exclude store-devtools from the build (#2073) Closes #1521 --- .../guide/store-devtools/recipes/exclude.md | 53 +++++++++++++++++++ projects/ngrx.io/content/navigation.json | 9 ++++ 2 files changed, 62 insertions(+) create mode 100644 projects/ngrx.io/content/guide/store-devtools/recipes/exclude.md diff --git a/projects/ngrx.io/content/guide/store-devtools/recipes/exclude.md b/projects/ngrx.io/content/guide/store-devtools/recipes/exclude.md new file mode 100644 index 0000000000..dbe3c6a0da --- /dev/null +++ b/projects/ngrx.io/content/guide/store-devtools/recipes/exclude.md @@ -0,0 +1,53 @@ +# Excluding Store Devtools In Production + +To prevent Store Devtools from being included in your bundle, you can exclude it from the build process. + + +## Step 1: Create build specific files + +Create a folder for your build specific files. In this case, it is `build-specifics`. Now create a file for a common build. Within this file, export an array that defines the `StoreDevtoolsModule`. + + +import { StoreDevtoolsModule } from '@ngrx/store-devtools'; + +export const extModules = [ + StoreDevtoolsModule.instrument({ + maxAge: 25 + }) +]; + + +Now create a file for a production build (`ng build --prod=true`) that simply exports an empty array. + + +export const extModules = []; + + +## Step 2: Import extModules + +Modify `app.module.ts` to include `extModules` in the `imports` array. + + +import { extModules } from './build-specifics'; + +@NgModule({ + imports: [ + StoreModule.forRoot(reducers), + // Instrumentation must be imported after importing StoreModule + extModules, + ], +}) + + +## Step 3: Modify angular.json + +Add a new entry in the `fileReplacements` section in your `angular.json`. For more information on this topic, look at the build section of the angular documentation. [Configure target-specific file replacements](https://angular.io/guide/build#configure-target-specific-file-replacements) + + +"fileReplacements": [ + { + "replace": "src/app/build-specifics/index.ts", + "with": "src/app/build-specifics/index.prod.ts" + } +] + \ No newline at end of file diff --git a/projects/ngrx.io/content/navigation.json b/projects/ngrx.io/content/navigation.json index fa45d29112..b1f3d4c815 100644 --- a/projects/ngrx.io/content/navigation.json +++ b/projects/ngrx.io/content/navigation.json @@ -148,6 +148,15 @@ { "title": "Instrumentation", "url": "guide/store-devtools/config" + }, + { + "title": "Recipes", + "children": [ + { + "title": "Exclude from Production", + "url": "guide/store-devtools/recipes/exclude" + } + ] } ] }, From 2d37b488799311b299af16bbe8b597c02e628a4f Mon Sep 17 00:00:00 2001 From: Brandon Date: Tue, 27 Aug 2019 07:12:36 -0500 Subject: [PATCH 14/18] fix(store): add DefaultProjectorFn to public API (#2090) Allows you to fully type the selector without reaching into the src folder --- modules/store/src/index.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/modules/store/src/index.ts b/modules/store/src/index.ts index 2650461279..8e3e2b65b1 100644 --- a/modules/store/src/index.ts +++ b/modules/store/src/index.ts @@ -33,6 +33,7 @@ export { MemoizedSelector, MemoizedSelectorWithProps, resultMemoize, + DefaultProjectorFn, } from './selector'; export { State, StateObservable, reduceState } from './state'; export { From 7445dd4e87e200f31b2d53c48de2be6eba34d38c Mon Sep 17 00:00:00 2001 From: Brandon Date: Tue, 27 Aug 2019 07:14:02 -0500 Subject: [PATCH 15/18] ci: fix filters on tags for publishing to npm and deployment of docs (#2091) --- .circleci/config.yml | 49 ++++++++++++++++++++++++++------------------ 1 file changed, 29 insertions(+), 20 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index a247d3cdef..b946a1b254 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -82,6 +82,11 @@ jobs: - ~/.cache/yarn - ~/.cache/Cypress - node_modules + # required since `publish-*` jobs have tag filters AND requires `test` + # https://circleci.com/docs/2.0/workflows/#executing-workflows-for-a-git-tag + filters: + tags: + only: /.*/ schematics-core-check: <<: *run_in_browser @@ -211,7 +216,9 @@ jobs: - run: name: Authenticate with registry command: echo "//registry.npmjs.org/:_authToken=$npm_TOKEN" > ~/repo/.npmrc - - run: yarn run publish:stable + - run: + name: Publish stable to npm + command: ./node_modules/.bin/ts-node ./build/publish-stable.ts publish-next: <<: *run_in_node @@ -224,7 +231,9 @@ jobs: - run: name: Authenticate with registry command: echo "//registry.npmjs.org/:_authToken=$npm_TOKEN" > ~/repo/.npmrc - - run: yarn run publish:next + - run: + name: Publish next to npm + command: ./node_modules/.bin/ts-node ./build/publish-next.ts cleanup-previews: <<: *run_in_node @@ -282,27 +291,27 @@ workflows: filters: branches: only: master - # - publish-stable: - # requires: - # - test - # filters: - # branches: - # ignore: /.*/ - # tags: - # only: /\d+\.\d+\.\d+(?!-\w+\.\d)/ - # - deploy-docs-stable: - # requires: - # - test - # filters: - # branches: - # ignore: /.*/ - # tags: - # only: /\d+\.\d+\.\d+(?!-\w+\.\d)/ - - publish-next: + - publish-stable: requires: - test filters: + tags: + only: /8\.\d+\.\d+(?!-\w+\.\d)/ branches: ignore: /.*/ + - deploy-docs-stable: + requires: + - test + filters: tags: - only: /\d+\.\d+\.\d+(-\w+\.\d)/ \ No newline at end of file + only: /8\.\d+\.\d+(?!-\w+\.\d)/ + branches: + ignore: /.*/ + - publish-next: + requires: + - test + filters: + tags: + only: /8\.\d+\.\d+(-\w+\.\d)/ + branches: + ignore: /.*/ \ No newline at end of file From 7cadbc0f72ac1bd2fe76ad0ff75006a0092d1614 Mon Sep 17 00:00:00 2001 From: Tim Deschryver <28659384+timdeschryver@users.noreply.github.com> Date: Thu, 29 Aug 2019 04:36:53 +0200 Subject: [PATCH 16/18] fix(store): should not run schematics when not using named imports (#2095) Closes #2093 --- .../store/migrations/8_0_0-beta/index.spec.ts | 44 +++++++++++++++++++ modules/store/migrations/8_0_0-beta/index.ts | 38 ++++++++++++++-- 2 files changed, 78 insertions(+), 4 deletions(-) diff --git a/modules/store/migrations/8_0_0-beta/index.spec.ts b/modules/store/migrations/8_0_0-beta/index.spec.ts index 1dd5e627b1..10d0f4ff97 100644 --- a/modules/store/migrations/8_0_0-beta/index.spec.ts +++ b/modules/store/migrations/8_0_0-beta/index.spec.ts @@ -110,4 +110,48 @@ describe('Store Migration 8_0_0 beta', () => { expect(file).toBe(expected); }); + + it(`should not run schematics when not using named imports`, () => { + const contents = ` + import * as store from '@ngrx/store'; + + @NgModule({ + imports: [ + CommonModule, + BrowserModule, + BrowserAnimationsModule, + HttpClientModule, + AuthModule, + AppRoutingModule, + store.StoreModule.forRoot(reducers), + ], + providers: [ + { + provide: store.META_REDUCERS, + useValue: [fooReducer, barReducer] + } + ] + bootstrap: [AppComponent], + }) + export class AppModule {} + `; + + appTree.create('./app.module.ts', contents); + const runner = new SchematicTestRunner('schematics', collectionPath); + + let logs: string[] = []; + runner.logger.subscribe(log => logs.push(log.message)); + + const newTree = runner.runSchematic( + `ngrx-${pkgName}-migration-02`, + {}, + appTree + ); + const file = newTree.readContent('app.module.ts'); + + expect(file).toBe(contents); + + expect(logs.length).toBe(1); + expect(logs[0]).toMatch(/NgRx 8 Migration: Unable to run the schematics/); + }); }); diff --git a/modules/store/migrations/8_0_0-beta/index.ts b/modules/store/migrations/8_0_0-beta/index.ts index 433fd0ba59..e906000312 100644 --- a/modules/store/migrations/8_0_0-beta/index.ts +++ b/modules/store/migrations/8_0_0-beta/index.ts @@ -1,5 +1,11 @@ import * as ts from 'typescript'; -import { Rule, chain, Tree } from '@angular-devkit/schematics'; +import { tags, logging } from '@angular-devkit/core'; +import { + Rule, + chain, + Tree, + SchematicContext, +} from '@angular-devkit/schematics'; import { ReplaceChange, createReplaceChange, @@ -10,7 +16,7 @@ import { const META_REDUCERS = 'META_REDUCERS'; function updateMetaReducersToken(): Rule { - return (tree: Tree) => { + return (tree: Tree, context: SchematicContext) => { visitTSSourceFiles(tree, sourceFile => { const createChange = (node: ts.Node) => createReplaceChange( @@ -22,7 +28,11 @@ function updateMetaReducersToken(): Rule { const changes: ReplaceChange[] = []; changes.push( - ...findMetaReducersImportStatements(sourceFile, createChange) + ...findMetaReducersImportStatements( + sourceFile, + createChange, + context.logger + ) ); changes.push(...findMetaReducersAssignment(sourceFile, createChange)); @@ -37,11 +47,22 @@ export default function(): Rule { function findMetaReducersImportStatements( sourceFile: ts.SourceFile, - createChange: (node: ts.Node) => ReplaceChange + createChange: (node: ts.Node) => ReplaceChange, + logger: logging.LoggerApi ) { + let canRunSchematics = false; + const metaReducerImports = sourceFile.statements .filter(ts.isImportDeclaration) .filter(isNgRxStoreImport) + .filter(p => { + canRunSchematics = Boolean( + p.importClause && + p.importClause.namedBindings && + (p.importClause!.namedBindings! as ts.NamedImports).elements + ); + return canRunSchematics; + }) .map(p => (p.importClause!.namedBindings! as ts.NamedImports).elements.filter( isMetaReducersImportSpecifier @@ -50,6 +71,15 @@ function findMetaReducersImportStatements( .reduce((imports, curr) => imports.concat(curr), []); const changes = metaReducerImports.map(createChange); + if (!canRunSchematics && changes.length === 0) { + logger.info(tags.stripIndent` + NgRx 8 Migration: Unable to run the schematics to rename \`META_REDUCERS\` to \`USER_PROVIDED_META_REDUCERS\` + in file '${sourceFile.fileName}'. + + For more info see https://ngrx.io/guide/migration/v8#meta_reducers-token. + `); + } + return changes; function isNgRxStoreImport(importDeclaration: ts.ImportDeclaration) { From 4025f6c4c8b7a47fe8c01aff312849b4241a8ada Mon Sep 17 00:00:00 2001 From: Siyang Kern Zhao Date: Wed, 28 Aug 2019 22:38:47 -0400 Subject: [PATCH 17/18] docs(store): export wrapped counterReducer to avoid AOT compile error (#2089) --- .../content/examples/store/src/app/counter.reducer.ts | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/projects/ngrx.io/content/examples/store/src/app/counter.reducer.ts b/projects/ngrx.io/content/examples/store/src/app/counter.reducer.ts index f593fa8584..4940496c69 100644 --- a/projects/ngrx.io/content/examples/store/src/app/counter.reducer.ts +++ b/projects/ngrx.io/content/examples/store/src/app/counter.reducer.ts @@ -4,8 +4,12 @@ import { increment, decrement, reset } from './counter.actions'; export const initialState = 0; -export const counterReducer = createReducer(initialState, +const _counterReducer = createReducer(initialState, on(increment, state => state + 1), on(decrement, state => state - 1), on(reset, state => 0), ); + +export function counterReducer(state, action) { + return _counterReducer(state, action); +} From 9d9bac6f0a6218fdaa15e1c7c7a2e3de0cc0bd16 Mon Sep 17 00:00:00 2001 From: Brandon Roberts Date: Wed, 28 Aug 2019 21:46:35 -0500 Subject: [PATCH 18/18] chore: release 8.3.0 --- CHANGELOG.md | 14 ++++++++++++++ package.json | 2 +- 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6c26b276f1..6d684fa8a0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,17 @@ + + +# [8.3.0](https://github.com/ngrx/platform/compare/8.2.0...8.3.0) (2019-08-29) + +### Bug Fixes + +- **data:** use correct guard when handling optimistic update ([#2060](https://github.com/ngrx/platform/issues/2060)) ([34c0420](https://github.com/ngrx/platform/commit/34c0420)), closes [#2059](https://github.com/ngrx/platform/issues/2059) +- **store:** add DefaultProjectorFn to public API ([#2090](https://github.com/ngrx/platform/issues/2090)) ([2d37b48](https://github.com/ngrx/platform/commit/2d37b48)) +- **store:** should not run schematics when not using named imports ([#2095](https://github.com/ngrx/platform/issues/2095)) ([7cadbc0](https://github.com/ngrx/platform/commit/7cadbc0)), closes [#2093](https://github.com/ngrx/platform/issues/2093) + +### Features + +- **store:** add verbose error message for undefined feature state in development mode ([#2078](https://github.com/ngrx/platform/issues/2078)) ([6946e2e](https://github.com/ngrx/platform/commit/6946e2e)), closes [#1897](https://github.com/ngrx/platform/issues/1897) + # [8.2.0](https://github.com/ngrx/platform/compare/8.1.0...8.2.0) (2019-07-31) diff --git a/package.json b/package.json index d91037aabe..fd570e8486 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@ngrx/platform", - "version": "8.2.0", + "version": "8.3.0", "description": "monorepo for ngrx development", "scripts": { "build": "bazel build //modules/...",