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: block
elements. - 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
div
s.
I put the markup for the two badges in:
app/templates/components/badge-appveyor.hbs
app/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.hbs
app/components/badge-new.js
I'd rather just have to add the ordering and create the template...
Confirm :P The custom element spec mandates that naming to avoid possible future collisions, since non-dasherized names are reserved.
[edit]
ci-badges
? ;)