Display Travis and Appveyor badges on crates.io.
- I want to show the badges on an individual crate's page and on a list of crates.
- I only want to do 1 ajax request for the data (and only do 1 SQL query on the backend).
- The Travis and Appveyor badges have different data and are constructed in slightly different ways.
- On a crate's page, I want the badges to display one per line, so within
display: blockelements. - On a page of a list of crates, I want the badges to display inline.
- I always want the Travis badge to appear before the Appveyor badge, and I think that knowledge should be encoded in one spot in Ember code somewhere (i.e. not the backend)
- We may add more badges in the future.
Here's the full code in context so far (I don't like it yet) but the ember parts and my reasoning is below:
I got my API to return JSON like this for a list of crates (same format for crate show page, only one crate in that case):
"crates": [{
"id": "rust_mixin",
"name": "rust_mixin",
"badges": [
{
"attributes": {
"repository": "huonw/external_mixin"
},
"badge_type": "appveyor"
},
{
"attributes": {
"branch": "master",
"repository": "huonw/external_mixin"
},
"badge_type": "travis-ci"
}
]
}, {
"id": "rust_mixin",
"name": "rust_mixin",
"badges": [
{
"attributes": {
"repository": "huonw/external_mixin",
"service": "bitbucket",
"branch": "master"
},
"badge_type": "appveyor"
}
]
}]In app/models/crate.js, I added this, with the annotated badges to have each badge know how to find its component:
export default DS.Model.extend({
// ... other stuff
badges: DS.attr(),
annotated_badges: Ember.computed.map('badges', function(badge) {
badge.component_name = `badge-${badge.badge_type}`;
return badge;
}),
});I created app/components/badge-appveyor.js:
import Ember from 'ember';
export default Ember.Component.extend({
tagName: 'span',
classNames: ['badge'],
});
and app/components/badge-travis-ci.js:
import Ember from 'ember';
export default Ember.Component.extend({
tagName: 'span',
classNames: ['badge'],
});
so that the markup for the badges wouldn't always be in display: block divs.
I put the markup for the two badges in:
app/templates/components/badge-appveyor.hbsapp/templates/components/badge-travis-ci.hbs
This seemed straightforward and nice.
I put the markup for all badges in app/templates/components/badges-ordered.hbs, I would have prefered to name this
badges.hbs but components have to have at least one hyphen in the name since someday badge might be an HTML element????
I haven't actually implemented the ordering part yet since I'm not sure how best to do it.... right now I just have:
{{#each badges as |badge|}}
{{component badge.component_name badge=badge}}
{{/each}}
I'd like this to look rubyish but I don't know quite how to make this actually work yet:
{{#each ['travis-ci', 'appveyor'] as |badge_type|}}
{{#if badges[badge_type]}}
{{component badge.component_name badge=badges[badge_type]}}
{{/if}}
{{/each}}
I'm calling the badges-ordered component in the crates list, where I want the badges to appear inline:
{{badges-ordered badges=crate.annotated_badges}}
When I want each badge to be in a display: block element on the crate show page, I'm doing this, which also doesn't take
into account the fixed ordering I want to do, which I would have to duplicate at this point:
{{#each crate.annotated_badges as |badge|}}
<p>
{{component badge.component_name badge=badge}}
</p>
{{/each}}
I haven't figured out how to do that best yet. Maybe change the CSS of span.badge to be display: block on the crate show
page???
-
Is this the best way to do this? I feel like I'm fighting against something else that Ember would rather I do, but I don't know what that is.
- Is component the right thing to use? the /components/*.js files feel repetitive and ceremonial.
- Should I be using a helper?
- I tried having a model for badge, but I don't think Ember liked that the data was already there? That's when I was getting the "Assertion Failed: You need to pass a model name to the store's modelFor method" errors so I took it out...
-
If I were to add a new badge, I'd need to add its ordering to the badges-ordered component and create each of these:
app/templates/components/badge-new.hbsapp/components/badge-new.jsI'd rather just have to add the ordering and create the template...
You can do
ember generate helper array, because the file generated passes the arguments through. Meaning you would do it like:{{#each (array 'travis-ci', 'appveyor']) as |badge_type|}}[edit]
badge=badges[badge_type]isbadge=(get badges badge_type)