Skip to content

feat: conditional container widget #348

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

Merged
merged 7 commits into from
Nov 13, 2020
Merged

Conversation

jake-bassett
Copy link
Contributor

@jake-bassett jake-bassett commented Nov 11, 2020

Description

Container widget that allows a datasource to provide one of two different children[] based on a conditional query or check.

Testing

This is not the entire implementation. Just base code to enable an extended data source.

Checklist:

  • My changes generate no new warnings
  • I have added tests that prove my fix is effective or that my feature works
  • Any dependent changes have been merged and published in downstream modules

@jake-bassett jake-bassett requested a review from a team as a code owner November 11, 2020 18:32
@codecov
Copy link

codecov bot commented Nov 11, 2020

Codecov Report

Merging #348 (de81fd6) into main (46b4982) will decrease coverage by 0.03%.
The diff coverage is 70.58%.

Impacted file tree graph

@@            Coverage Diff             @@
##             main     #348      +/-   ##
==========================================
- Coverage   86.28%   86.24%   -0.04%     
==========================================
  Files         729      733       +4     
  Lines       14844    14875      +31     
  Branches     1896     1848      -48     
==========================================
+ Hits        12808    12829      +21     
- Misses       2005     2013       +8     
- Partials       31       33       +2     
Impacted Files Coverage Δ
...c/properties/property-types/model-template-type.ts 83.33% <ø> (ø)
...aphql/conditional/conditional-data-source.model.ts 0.00% <0.00%> (ø)
...oard/data/graphql/table/table-data-source.model.ts 87.50% <ø> (ø)
...nditional/conditional-widget-renderer.component.ts 60.00% <60.00%> (ø)
...oards/src/widgets/conditional/conditional.model.ts 66.66% <66.66%> (ø)
projects/dashboards/src/public-api.ts 100.00% <100.00%> (ø)
...c/widgets/conditional/conditional-widget.module.ts 100.00% <100.00%> (ø)
...dashboards/src/widgets/dashboard-widgets.module.ts 100.00% <100.00%> (ø)
...ects/dashboards/src/widgets/repeat/repeat.model.ts 38.70% <100.00%> (ø)
...cts/dashboards/src/widgets/repeat/repeat.module.ts 100.00% <100.00%> (ø)
... and 5 more

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update 46b4982...de81fd6. Read the comment docs.

type: ARRAY_PROPERTY.type,
required: true
})
public trueChildren: object[] = [];
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🤣

type: ARRAY_PROPERTY.type,
required: true
})
public falseChildren: object[] = [];
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🤣

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Shhhhh. Don't tell them! 😂

private readonly api!: ModelApi;

public getData(): Observable<boolean> {
return this.api.getData<boolean>();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Container may not have any data source. So why would this ever emit?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A conditional container widget will require a datasource to determine which children to return.

@@ -18,15 +20,17 @@ import { ContainerWidgetModel } from './container-widget.model';
</div>
`
})
export class ContainerWidgetRendererComponent extends WidgetRenderer<ContainerWidgetModel> implements AfterViewInit {
export class ContainerWidgetRendererComponent
extends WidgetRenderer<ContainerWidgetModel | ConditionalContainerWidgetModel>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So two issues with this approach that I see -

  1. The renderer now has to know about different types of models (not a huge deal)
  2. The conditional works at a container level - this seems more problematic. If I want to condition one widget (which is more likely the case), does that mean it gets padded? What if the condition should change the layout? In my mind, I was thinking the conditional would always work with a single widget - that widget however could be a container itself, and handle its own layout.

I think one nice to have thing with the single widget approach is that if we do eventually add support for conditional models, it would use the exact same model.

Copy link
Contributor Author

@jake-bassett jake-bassett Nov 11, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, I had the same thoughts but actually stopped and stashed the new conditional-container-widget.model.ts and conditional-container-widget-renderer.component.ts I was going with to get feedback on this minimal approach first.

Is that the suggestion then? We want this to have its own model widget model and renderer?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That'd be my suggestion, but of course alway welcome to push back. I would expect it to be no more code than this change (or close enough) and touch fewer existing files. It's trading a new pass through renderer for the changes to the existing renderer/container widget models. I also like the idea of going with simply conditional.model.ts- We can implement that by associating a renderer right now, but once we build out model support any JSON using this for widgets remains identical (because a widget is jut a model with an associated renderer)


@ModelProperty({
key: 'false',
type: PLAIN_OBJECT_PROPERTY.type,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ModelTemplatePropertyType.TYPE

}

public getModel(): Observable<ModelJson> {
return this.getData().pipe(map(result => (result ? this.true : this.false)));
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Based on how we're using this in the renderer, we should hydrate this modelJson, and return a real model - something like this.api.createChild(result ? this.true : this.false)

styleUrls: ['./conditional-widget-renderer.component.scss'],
changeDetection: ChangeDetectionStrategy.OnPush,
template: `
<div class="conditional-widget">
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

do we need the div? the instantiated widget should have its own container

`
})
export class ConditionalWidgetRendererComponent extends WidgetRenderer<ConditionalModel> {
@ViewChild('containerContent', { read: ViewContainerRef, static: true })
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Doesn't appear used

<ng-container [hdaDashboardModel]="this.getModel() | async"> </ng-container>
</div>
`
template: ` <ng-container [hdaDashboardModel]="this.getChildModel() | async"> </ng-container> `
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

by virtue of making this our fetch data implementation, this is already available as this.data$ - we could inline line 16 into fetchData.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll fix this locally. Thanks.

public getModel(): Observable<ModelJson> {
return this.model.getModel().pipe(takeUntil(this.destroyed$));
public getChildModel(): Observable<object> {
return this.model.getChildModel().pipe(takeUntil(this.destroyed$));
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: this takeUntil isn't a problem but not necessary ( we used to use these a lot more if you were looking at old code - now we try instead where possible to push the subscriptions into the DOM which will auto unsubscribe.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Will fix locally. Thanks.

@jake-bassett jake-bassett merged commit 8276198 into main Nov 13, 2020
@jake-bassett jake-bassett deleted the conditional-container-widget branch November 13, 2020 17:25
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants