Skip to content

WIP: Filterable deprecations #361

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

Draft
wants to merge 10 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
82 changes: 82 additions & 0 deletions app/controllers/filters.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
import Controller from '@ember/controller';
import { computed } from '@ember/object';
import semver from 'semver';

export default Controller.extend({
queryParams: ['from', 'to'],

from: null,
to: null,

// The model is initially an array of arrays, one for each project/version pair
// (e.g. `ember-data-2.x`), so we need to flatten it to make filtering easier
flattenedDeprecations: computed('model.[]', function() {
return this.model.reduce((acc, elem) => {
let rawArray = elem.toArray();
return acc.concat(rawArray);
}, []);
}),

// Create a deduped list of semver-coerced versions from all the deprecations that were loaded.
// We'll use this as the basis for our filter dropdowns
versions: computed('[email protected]', function() {
let versionsList = this.flattenedDeprecations.reduce((acc, elem) => {
let coerced = semver.coerce(elem.since);
let version = coerced && coerced.version;

if (!acc.includes(version) && parseFloat(version)) {
acc.push(version);
}

return acc;
}, []);

return versionsList.sort();
}),

// `fromVersions` is the list of versions that the `from` dropdown uses. It's restricted so that
// you can't select a `from` version that is higher than your `to` version.
fromVersions: computed('versions.[]', 'to', function() {
return this.to ?
this.versions.filter(version => semver.lt(version, this.to)) :
this.versions;
}),

// `toVersions` is the list of versions that the `to` dropdown uses. It's restricted so that
// you can't select a `to` version that is lower than your `from` version.
toVersions: computed('versions.[]', 'from', function() {
return this.from ?
this.versions.filter(version => semver.gt(version, this.from)) :
this.versions;
}),

// This will usually just mirror the `from` query param, but in case that param is empty,
// this lets us just use the lowest possible version as a default
selectedFrom: computed('from', function() {
return this.from || this.get('versions.firstObject');
}),

// This will usually just mirror the `to` query param, but in case that param is empty,
// this lets us just use the highest possible version as a default
selectedTo: computed('to', function() {
return this.to || this.get('versions.lastObject');
}),

filteredDeprecations: computed('flattenedDeprecations', 'from', 'to', function() {
let deprecations = this.flattenedDeprecations;

return deprecations.filter(deprecation => {
let coerced = semver.coerce(deprecation.since);
let version = coerced && coerced.version;

// In case we're not able to get an actual semver version (like, if the version is a bunch
// of words or something) we just return false immediately rather than trying to pass it
// into the `semver` functions.
if (!version) {
return false;
}

return semver.gte(version, this.selectedFrom) && semver.lte(version, this.selectedTo);
});
}),
});
1 change: 1 addition & 0 deletions app/router.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ Router.map(function() {
this.route("show", {
path: ":project/:version"
});
this.route('filters');
});

export default Router;
30 changes: 30 additions & 0 deletions app/routes/filters.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import Route from '@ember/routing/route';
import config from 'deprecation-app/config/environment';
import { all } from 'rsvp';

export default Route.extend({
model() {
// Since we currently load the deprecation files in project/version buckets
// (e.g. ember-data-2.x), we need to instead get ahold of all of the deprecations at once
// so we can do more fine-grained filtering.

// Read the `contentFolders` config used to serve all the markdown files as static JSON assets
// and transform them in `store.query` param objects
let contentFolders = config.contentFolders.map(folder => {
let [ path, version ] = folder.split('/');

return {
path,
version: `${version}.x`
};
});

// Fire off queries for all the different project/version combinations.
// These will be flattened and filtered in the controller.
let queryObjectPromises = contentFolders.map(version => {
return this.store.query('content', version);
});

return all(queryObjectPromises);
}
});
33 changes: 33 additions & 0 deletions app/templates/filters.hbs
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
<div class="main" id="content" role="main">
<h2>Filter deprecations by version range</h2>

<span id="select-to">
From:
{{#x-select data-test-select-from=true value=selectedFrom action=(action (mut from)) as |xs|}}
{{#each fromVersions as |version|}}
{{#xs.option value=version}}
{{version}}
{{/xs.option}}
{{/each}}
{{/x-select}}
</span>

<span id="select-to">
To:
{{#x-select data-test-select-to=true value=selectedTo action=(action (mut to)) as |xs|}}
{{#each toVersions as |version|}}
{{#xs.option value=version}}
{{version}}
{{/xs.option}}
{{/each}}
{{/x-select}}
</span>

{{#each filteredDeprecations as |deprecation|}}
{{deprecation-article
data-test-deprecation-article=true
model=deprecation
renderIdOrUntil=deprecation.until
}}
{{/each}}
</div>
2 changes: 2 additions & 0 deletions app/templates/index.hbs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@
before you dive in.
</p>

{{#link-to 'filters'}}Filters page{{/link-to}}

<h3 class="anchorable-toc" id="toc_ember">Versions</h3>
<ul class="ember-version-graphics">
<li class="item">
Expand Down
4 changes: 2 additions & 2 deletions config/environment.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
'use strict';
"use strict";

module.exports = function(environment) {
let ENV = {
Expand Down Expand Up @@ -27,7 +27,7 @@ module.exports = function(environment) {
hostWhitelist: [/localhost:\d+/]
},

'algolia': {
algolia: {
algoliaId: 'Y1OMR4C7MF',
algoliaKey: '5d01c83734dc36754d9e94cbf6f8964d'
},
Expand Down
7 changes: 7 additions & 0 deletions content-folder-list.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
module.exports = [
"ember/v1",
"ember/v2",
"ember/v3",
"ember-data/v2",
"ember-cli/v2"
];
5 changes: 5 additions & 0 deletions ember-cli-build.js
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ module.exports = function(defaults) {
importBootstrapFont: false,
importBootstrapCSS: false
},

// TODO: remove once this issue is fixed https://github.com/ember-cli/ember-cli/issues/8075
'ember-cli-uglify': {
uglify: {
Expand All @@ -54,5 +55,9 @@ module.exports = function(defaults) {
using: [{ transformation: "cjs", as: "semver-compare" }]
});

app.import("node_modules/semver/semver.js", {
using: [{ transformation: "cjs", as: "semver" }]
});

return app.toTree();
};
3 changes: 3 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -61,12 +61,15 @@
"ember-set-body-class": "^0.4.2",
"ember-source": "~3.9.1",
"ember-styleguide": "2.5.0",
"ember-test-selectors": "^1.0.0",
"ember-tether": "^1.0.0",
"emberx-select": "^3.1.1",
"eslint-plugin-ember": "^6.5.1",
"loader.js": "^4.7.0",
"prember": "^1.0.2",
"qunit-dom": "^0.8.5",
"sass": "^1.20.3",
"semver": "^5.5.1",
"semver-compare": "^1.0.0"
},
"engines": {
Expand Down
38 changes: 38 additions & 0 deletions tests/acceptance/filtering-by-versions-test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import { module, test } from 'qunit';
import { visit, currentURL, findAll } from '@ember/test-helpers';
import { setupApplicationTest } from 'ember-qunit';
import { select } from 'deprecation-app/tests/helpers/x-select';

const countDeprecationArticles = () => {
return findAll('[data-test-deprecation-article').length;
};

module('Acceptance | filtering by versions', function(hooks) {
setupApplicationTest(hooks);

test('filtering', async function(assert) {
await visit('/filters');

assert.equal(currentURL(), '/filters', 'we start out with no query params');
assert.dom('select[data-test-select-from]').hasValue('1.11.0');
assert.dom('[data-test-deprecation-article]').exists();

let itemsCount = countDeprecationArticles();

await select('[data-test-select-from]', '2.0.0');

assert.equal(currentURL(), '/filters?from=2.0.0', 'selecting a "from" range updates the query param');

let fromCount = countDeprecationArticles();

assert.ok(itemsCount > fromCount, 'There should be fewer deprecations showing now that we\'ve filtered');

await select('[data-test-select-to]', '2.8.0');

assert.equal(currentURL(), '/filters?from=2.0.0&to=2.8.0', 'selecting a "to" range updates the query param');

let toCount = countDeprecationArticles();

assert.ok(fromCount > toCount, 'Adding to `to` filter should reduce the number of visible items even further');
});
});
Loading