-
Notifications
You must be signed in to change notification settings - Fork 11
Initial draft for new loaders using gifs #1071
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
Codecov Report
@@ Coverage Diff @@
## main #1071 +/- ##
=======================================
Coverage 85.08% 85.09%
=======================================
Files 825 825
Lines 17066 17086 +20
Branches 2216 2220 +4
=======================================
+ Hits 14521 14539 +18
- Misses 2514 2516 +2
Partials 31 31
Continue to review full report at Codecov.
|
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
Discussed this in our call today. Overall a good change. Few Action items:
|
This comment has been minimized.
This comment has been minimized.
updated, please check the description I have added usage section |
This comment has been minimized.
This comment has been minimized.
// Second param for structural directive is undefined until this.data$ is defined | ||
// So putting this assignment in constuctor will not work | ||
// This will execute only once as this method is called only | ||
this.wrapperInjector = Injector.create({ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We don't need to create a new injector. It would be problematic and also it wouldn't work since right now we are only creating a new instance of component when data$ reference itself change. New emits on data$ is automatically passed via the state$ property.
What I would recommend it to modify line 45 instead and add loaderType$ as a property in LoadAsyncWrapperParameters
.
Create a ReplaySubject
for loaderType ->
private readonly loaderTypeSubject: BehaviourSubject<LoaderType> = new BehaviourSubject(<default-value>);
private readonly loaderType$: Observable<LoaderType>= this.loaderTypeSubject.asObservable();
Then use add loaderType$ on like 46.
and add a separate ngOnChanges trigger for loaderType, that would just emit on this subject.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
updated
LoaderHorizontal = 'assets/images/loader-horizontal.gif' | ||
} | ||
|
||
export const enum LoaderTypes { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LoaderType
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
updated
export const enum LoaderTypes { | ||
SmallCircle = 'small-circle', | ||
Horizontal = 'horizontal', | ||
LargeSquare = 'large-square' |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Spoke to Michael.
Let's use smallCircle directly in Spinner. We can remove it from here
Horizontal can be renamed to ExpandableRow
. LargeSquare can be renamed to 'Page'.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Also, we would need to bring back the old svg icon approach for other skeleton loaders.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ok, will update the names,
Do you mean to use the small-circle as default? Not sure what is meant by the Spinner.
One thing I want to highlight here there is no need to use both ht-icon and image tag. An image tag can also work with an SVG source path.
But if we put it back then we need to put more logic on what type of loader goes where and then computing the image path and icon path(in case there are multiple) will go in 2 totally separate directions. I would prefer to keep one kind of logic (either SVG or IMG tag) as it would be straightforward and won't create any confusion.
|
||
public ngOnChanges(): void { | ||
// Unfortunatly passing undefined is overwriting default value | ||
this.type = this.type ?? LoaderTypes.Horizontal; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We shouldn't be modifying the input property. From where, is it getting the undefined value?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
updated
This comment has been minimized.
This comment has been minimized.
I will continue on writing test cases, is there anything else pending on this PR? |
@@ -23,8 +24,11 @@ import { | |||
export class LoadAsyncDirective implements OnChanges, OnDestroy { | |||
@Input('htLoadAsync') | |||
public data$?: Observable<unknown>; | |||
@Input() | |||
public htLoadAsyncLoaderType!: LoaderType; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this should be optional. You can assign a default value here
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
updated
private readonly wrapperParamsSubject: ReplaySubject<LoadAsyncWrapperParameters> = new ReplaySubject(1); | ||
private readonly wrapperInjector: Injector; | ||
private wrapperInjector!: Injector; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
any reason for removing the readonly?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
updated
export class LoaderComponent implements OnChanges { | ||
@Input() | ||
public type: LoaderType = LoaderType.ExpandableRow; | ||
public imagePath: ImagesAssetPath = ImagesAssetPath.LoaderExpandableRow; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is formatting right? Can add a new line after L17
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done
export class LoaderComponent {} | ||
export class LoaderComponent implements OnChanges { | ||
@Input() | ||
public type: LoaderType = LoaderType.ExpandableRow; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should this be the default?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
updated
@@ -39,9 +40,13 @@ export class LoadAsyncWrapperComponent { | |||
|
|||
public content?: TemplateRef<LoadAsyncContext>; | |||
|
|||
private readonly loaderTypeSubject: BehaviorSubject<LoaderType> = new BehaviorSubject<LoaderType>(LoaderType.Spinner); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We are setting different default options at multiple places. It would be useful if we set it at only one place
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
then, I need to put undefined as the initial value.
This comment has been minimized.
This comment has been minimized.
private readonly wrapperParamsSubject: ReplaySubject<LoadAsyncWrapperParameters> = new ReplaySubject(1); | ||
private readonly wrapperInjector: Injector; | ||
private readonly wrapperInjector!: Injector; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this required?
@Component({ | ||
selector: 'ht-load-async-wrapper', | ||
template: ` | ||
<div *ngIf="this.state$ | async as state" class="fill-container" [ngSwitch]="state.type"> | ||
<ng-container *ngSwitchCase="'${LoadAsyncStateType.Loading}'"> | ||
<ht-loader></ht-loader> | ||
<ng-container *ngIf="this.loaderType$ | async as loaderType"> | ||
<ht-loader [type]="loaderType"></ht-loader> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ng-container is not needed. You can use async
pipe directly with ht-loader
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
can do <ht-loader [type]="loaderType$ | async"></ht-loader>
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
loaderType here will be defined since we are setting default value.
public constructor(@Inject(ASYNC_WRAPPER_PARAMETERS$) parameters$: Observable<LoadAsyncWrapperParameters>) { | ||
this.state$ = parameters$.pipe( | ||
tap(params => (this.content = params.content)), | ||
tap(params => this.loaderTypeSubject.next(params.loaderType)), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
do we gain anything by storing it as observable? If we store the loaderType
similar to content
, would it cause any issues?
export class LoaderComponent {} | ||
export class LoaderComponent implements OnChanges { | ||
@Input() | ||
public type!: LoaderType; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This property can be optional right?
case LoaderType.Spinner: | ||
return ImagesAssetPath.LoaderSpinner; | ||
default: | ||
return assertUnreachable(this.type); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
may be we can leave type
as optional and in default section here, we can assign the default image path instead of throwing exception
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actually, No. When a consumer is passing a wrong value it should throw an error, on the other hand, if the consumer is not passing a value it should show default value.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
import { createHostFactory, SpectatorHost } from '@ngneat/spectator/jest'; | ||
import { LoaderComponent } from './loader.component'; | ||
|
||
describe('Link component', () => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
name
@@ -23,8 +24,11 @@ import { | |||
export class LoadAsyncDirective implements OnChanges, OnDestroy { | |||
@Input('htLoadAsync') | |||
public data$?: Observable<unknown>; | |||
@Input() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@Input('htLoadAsyncLoaderType')
public loaderType: LoaderType;
This should work
@@ -49,6 +53,7 @@ export class LoadAsyncDirective implements OnChanges, OnDestroy { | |||
this.wrapperView = this.wrapperView || this.buildWrapperView(); | |||
this.wrapperParamsSubject.next({ | |||
state$: this.loadAsyncService.mapObservableState(this.data$), | |||
loaderType: this.htLoadAsyncLoaderType, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So basically, if htLoadAsyncLoaderType changes, then this if block will not be triggered? So, how would you handle the case when loaderType changes after init?
Why don't you send loaderType
to mapObservableState
as another param? then this function can add this loaderType in interface LoadingAsyncState { type: LoadAsyncStateType.Loading; }
Also, update L52 to also include change on LoaderType
@Input() | ||
public type: LoaderType = LoaderType.Spinner; | ||
|
||
public imagePath: ImagesAssetPath = ImagesAssetPath.LoaderSpinner; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If we keep it unassigned, would it get the same value from getImagePathFromType
call inside ngOnChanges?
public constructor(@Inject(ASYNC_WRAPPER_PARAMETERS$) parameters$: Observable<LoadAsyncWrapperParameters>) { | ||
this.state$ = parameters$.pipe( | ||
tap(params => (this.content = params.content)), | ||
tap(params => this.loaderTypeSubject.next(params.loaderType)), | ||
switchMap(parameter => parameter.state$), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As per prev comments, we can add loadertype as part of LoadingState. We wouldn't need to store another subject here. We can reference it from the state object directly.
@alok-traceable I am guessing this is not ready for another round of review, right? |
@itssharmasandeep Can we close this one? |
Closing this, as #1217 contains the same changes from this one |
Description
New gif loader.
Checklist:
Usages
As directive
*htLoadAsync="applicationInsights.apiDistributionByRiskSeries$ as apiDistributionByRiskSeries; loaderType: '${LoaderTypes.LargeSquare}'"
As component
<ht-loader [type]="${LoaderTypes.LargeSquare}"></ht-loader>