refactor: 💡 move resource filter logic into dedicated class

This commit is contained in:
Randall Morey committed 2021-11-30 15:18:59 -05:00
1 parent 8193aac845
commit 5dc99ef5ad
6 files changed
+125 -48

No files matched your search

@@ -1,3 +1,94 @@
import EmberObject from '@ember/object';
import { getOwner } from '@ember/application';
/**
*
*/
class ResourceFilter extends EmberObject {
// =attributes
route;
name;
allowedValues;
defaultValue;
/**
*
*/
get filterKey() {
return `filter-${this.name}`;
}
/**
*
*/
get value() {
const value =
this.route.paramsFor(this.route.routeName)[this.filterKey] ||
JSON.stringify(this.defaultValue);
return value ? JSON.parse(value) : null;
}
/**
*
*/
set value(value) {
const queryParams = {};
queryParams[this.filterKey] = JSON.stringify(value);
this.route.transitionTo({ queryParams });
}
// =static methods
/**
*
*/
static setupRouteQueryParams(routeClass, name) {
const filterKey = `filter-${name}`;
// If the route has no query params specified yet, declare them.
if (!Object.keys(routeClass.queryParams).length)
routeClass.queryParams = {};
// If the route has no resource filters list specified yet, create one.
if (!routeClass.resourceFilterParams) routeClass.resourceFilterParams = [];
// Add the resource filter query parameter to the route. Resource filter
// param changes refresh the model but do not contribute to browser history.
// See https://guides.emberjs.com/release/routing/query-params/
routeClass.queryParams[filterKey] = {
refreshModel: true,
replace: true,
};
}
/**
*
*/
static getOrCreateRouteResourceFilter(
routeInstance,
name,
allowedValues,
defaultValue
) {
const owner = getOwner(routeInstance);
const containerKey = `route-resource-filter:${name}@${routeInstance.routeName}`;
const factory = owner.factoryFor(containerKey);
if (!factory) {
// create factory
class RouteResourceFilter extends this {
route = routeInstance;
name = name;
allowedValues = allowedValues;
defaultValue = defaultValue;
}
owner.register(containerKey, RouteResourceFilter);
}
const instance = owner.lookup(containerKey);
return instance;
}
}
/**
* A resource filter param is a concise way to express a route query parameter.
* Resource filter params abstract away a route's query parameter
@@ -40,29 +131,9 @@ export function resourceFilterParam(allowedValues, defaultValue) {
* @return {object{get, set}}
*/
return function (target, name /*, descriptor*/) {
const filterKey = `filter-${name}`;
const filterAllowedValuesKey = `filter-allowed-values-${name}`;
ResourceFilter.setupRouteQueryParams(target, name);
// If the route has no query params specified yet, declare them.
if (!Object.keys(target.queryParams).length) target.queryParams = {};
// If the route has no resource filters list specified yet, create one.
if (!target.resourceFilterParams) target.resourceFilterParams = [];
// Add the resource filter query parameter to the route. Resource filter
// param changes refresh the model but do not contribute to browser history.
// See https://guides.emberjs.com/release/routing/query-params/
target.queryParams[filterKey] = {
refreshModel: true,
replace: true,
};
// Note the name of this filter param.
target.resourceFilterParams.push(name);
// Store the allowed values for future lookup
// (via `ResourceFilterParamHelper`).
target[filterAllowedValuesKey] = allowedValues;
let instance;
// Override the decorated attribute with a getter and setter.
return {
@@ -70,10 +141,13 @@ export function resourceFilterParam(allowedValues, defaultValue) {
* Returns the JSON-parsed query parameter value OR defaultValue.
*/
get() {
const value =
this.paramsFor(this.routeName)[filterKey] ||
JSON.stringify(defaultValue);
return value ? JSON.parse(value) : null;
instance = ResourceFilter.getOrCreateRouteResourceFilter(
this,
name,
allowedValues,
defaultValue
);
return instance.value;
},
/**
@@ -83,9 +157,7 @@ export function resourceFilterParam(allowedValues, defaultValue) {
* @param value
*/
set(value) {
const queryParams = {};
queryParams[filterKey] = JSON.stringify(value);
this.transitionTo({ queryParams });
instance.value = value;
},
};
};
@@ -44,14 +44,14 @@ export default class HasResourceFilterParamSelectionsHelper extends Helper {
/**
* Returns true if the specified route has a value set for
* any resource filter.
* any resource filter passed into the helper.
* @param {string} routeName
* @param {string[]} names - names of resource filter fields
* @return {boolean}
*/
compute([routeName]) {
compute([routeName, ...names]) {
const owner = getOwner(this);
const route = owner.lookup(`route:${routeName}`);
const names = route.resourceFilterParams;
const selectedValues = names.map((name) => route[name] || null).flat();
const anyTruthy = selectedValues.reduce(
(previousValue, currentValue) => previousValue || currentValue,
@@ -50,13 +50,9 @@ export default class ResourceFilterParamHelper extends Helper {
*/
compute([routeName, name]) {
const owner = getOwner(this);
// Filter options
const route = owner.lookup(`route:${routeName}`);
const filterAllowedValuesKey = `filter-allowed-values-${name}`;
const allowedValues = route[filterAllowedValuesKey];
// Selected filters
const rawValue = route[name];
const selectedValue = rawValue || null;
const containerKey = `route-resource-filter:${name}@${routeName}`;
const resourceFilter = owner.lookup(containerKey);
const { allowedValues, value: selectedValue } = resourceFilter;
return { name, allowedValues, selectedValue };
}
@@ -39,7 +39,9 @@
{{#if
(or
@model
(has-resource-filter-param-selections 'scopes.scope.auth-methods')
(has-resource-filter-param-selections
'scopes.scope.auth-methods' 'type'
)
)
}}
<Rose::Toolbar>
@@ -74,7 +76,9 @@
{{/with}}
{{#if
(has-resource-filter-param-selections 'scopes.scope.auth-methods')
(has-resource-filter-param-selections
'scopes.scope.auth-methods' 'type'
)
}}
<Rose::Button
@style='inline-link-action'
@@ -208,7 +212,7 @@
</Rose::Table>
{{else if (has-resource-filter-param-selections
'scopes.scope.auth-methods'
'scopes.scope.auth-methods' 'type'
)}}
<Rose::Layout::Centered>
@@ -16,7 +16,8 @@
{{#if (feature-flag 'filter')}}
{{#if
(or
@model (has-resource-filter-param-selections 'scopes.scope.sessions')
@model
(has-resource-filter-param-selections 'scopes.scope.sessions' 'type')
)
}}
<Rose::Toolbar>
@@ -51,7 +52,9 @@
{{/with}}
{{#if
(has-resource-filter-param-selections 'scopes.scope.sessions')
(has-resource-filter-param-selections
'scopes.scope.sessions' 'type'
)
}}
<Rose::Button
@style='inline-link-action'
@@ -136,7 +139,9 @@
</table.body>
</Rose::Table>
{{else if (has-resource-filter-param-selections 'scopes.scope.sessions')}}
{{else if (has-resource-filter-param-selections
'scopes.scope.sessions' 'type'
)}}
<Rose::Layout::Centered>
<Rose::Message @title={{t 'titles.no-results'}} as |message|>
<message.description>
@@ -14,7 +14,7 @@
(or
@model
(has-resource-filter-param-selections
'scopes.scope.projects.sessions'
'scopes.scope.projects.sessions' 'type'
)
)
}}
@@ -51,7 +51,7 @@
{{#if
(has-resource-filter-param-selections
'scopes.scope.projects.sessions'
'scopes.scope.projects.sessions' 'type'
)
}}
<Rose::Button
@@ -143,7 +143,7 @@
</table.body>
</Rose::Table>
{{else if (has-resource-filter-param-selections
'scopes.scope.projects.sessions'
'scopes.scope.projects.sessions' 'type'
)}}
<Rose::Layout::Centered>
<Rose::Message @title={{t 'titles.no-results'}} as |message|>