Merge pull request #845 from hashicorp/feature-auth-methods-filters

Auth methods filters
This commit is contained in:
Randall Morey authored and GitHub committed 2021-11-15 09:39:43 -05:00
commit 297f2b158b
18 files changed
+233 -29

No files matched your search

@@ -52,7 +52,7 @@ export class ResourceFilter {
* @return {string}
*/
equals(key, value) {
return `"/item/${key}" == "${value}"`;
return value !== null ? `"/item/${key}" == "${value}"` : null;
}
/**
@@ -76,7 +76,7 @@ export class ResourceFilter {
* @return {string}
*/
parenthetical(expression) {
return `(${expression})`;
return expression ? `(${expression})` : null;
}
}
+3 -2
View File
@@ -55,8 +55,9 @@ export default function () {
this.get(
'/auth-methods',
({ authMethods }, { queryParams: { scope_id: scopeId } }) => {
return authMethods.where({ scopeId });
({ authMethods }, { queryParams: { scope_id: scopeId, filter } }) => {
const resultSet = authMethods.where({ scopeId });
return resultSet.filter(makeBooleanFilter(filter));
}
);
this.post('/auth-methods');
+1 -1
View File
@@ -22,7 +22,7 @@ export default function (server) {
// Auth
const globalAuthMethods = server.createList(
'auth-method',
4,
1,
{ scope: globalScope },
'withAccountsAndUsersAndManagedGroups'
);
@@ -46,6 +46,9 @@ export function resourceFilterParam(allowedValues, defaultValue) {
// 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/
@@ -54,6 +57,9 @@ export function resourceFilterParam(allowedValues, defaultValue) {
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;
@@ -0,0 +1,73 @@
import Helper from '@ember/component/helper';
import { inject as service } from '@ember/service';
import { getOwner } from '@ember/application';
import { action } from '@ember/object';
/**
* Use this helper to determine if a resource filter for a route has any
* currently selected value.
*
* @see resourceFilterParam (decorator)
*
* @example
*
* {{#if (has-resource-filter-param-selections 'route.name' 'field')}}
* Field has filter selections.
* {{/if}}
*/
export default class HasResourceFilterParamSelectionsHelper extends Helper {
// =services
@service router;
// =methods
// =lifecycle management methods
/**
* Recompute this helper when the route changes.
*/
constructor() {
super(...arguments);
this.router.on('routeDidChange', this.routeDidChange);
}
/**
* Stop listening to route events when this helper is destroyed.
*/
willDestroy() {
this.router.off('routeDidChange', this.routeDidChange);
super.willDestroy();
}
// =compute method
/**
* Returns true if the specified route has a value set for
* any resource filter.
* @param {string} routeName
* @return {boolean}
*/
compute([routeName]) {
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,
false
);
return Boolean(anyTruthy);
}
// =actions
/**
* Triggers a recompute (see above) when the route changes, especially when
* route query params change.
*/
@action
routeDidChange() {
this.recompute();
}
}
@@ -0,0 +1 @@
export { default } from 'core/helpers/has-resource-filter-param-selections';
+2 -1
View File
@@ -37,10 +37,10 @@
"ember-intl": "^5.7.0",
"ember-loading": "^0.4.0",
"ember-route-action-helper": "^2.0.8",
"ember-truth-helpers": "^3.0.0",
"rose": "*"
},
"devDependencies": {
"js-bexpr": "hashicorp/js-bexpr#9b4a4b54d85eba67fdfc0990133d1518d890b1e1",
"@ember/optional-features": "^2.0.0",
"@ember/test-helpers": "^2.4.2",
"@glimmer/component": "^1.0.4",
@@ -73,6 +73,7 @@
"eslint-plugin-prettier": "^4.0.0",
"eslint-plugin-qunit": "^6.2.0",
"faker": "^5.5.3",
"js-bexpr": "hashicorp/js-bexpr#9b4a4b54d85eba67fdfc0990133d1518d890b1e1",
"loader.js": "^4.7.0",
"npm-run-all": "^4.1.5",
"prettier": "^2.4.0",
@@ -35,3 +35,4 @@ close: Close
toggle-secret: Toggle secret visibility
minimize: Minimize
fullscreen: Fullscreen
clear-all-filters: Clear all filters
+2
View File
@@ -29,11 +29,13 @@ titles:
welcome-to-boundary: Welcome to Boundary
label: Label
value: Value
no-results: No Results
descriptions:
empty-set: There are no items to display yet. You may be able to add items or try back later.
origin-initialization: To get started, please enter your origin URL
create-but-not-list: You do not have permission to list {resource}, but you can create new instances.
neither-list-nor-create: You do not have permission to list or create {resource}.
no-results: We found no matching records.
questions:
delete-confirm: Are you sure you want to delete this resource?
remove-confirm: Are you sure you want to remove this association?
@@ -18,6 +18,9 @@
<span class="rose-dropdown-trigger-text">
{{@text}}
{{#if @count}}
<Rose::Badge>{{@count}}</Rose::Badge>
{{/if}}
</span>
</summary>
@@ -1,6 +1,6 @@
import { Meta, Story, Preview } from '@storybook/addon-docs/blocks';
import { hbs } from 'ember-cli-htmlbars';
import { boolean, object } from '@storybook/addon-knobs';
import { number, boolean, object } from '@storybook/addon-knobs';
import { action } from '@storybook/addon-actions';
<Meta title="Rose|Dropdown" component="Dropdown" />
@@ -12,7 +12,7 @@ A simple dropdown component with support for links and buttons.
<Preview>
<Story name="Basic Dropdown" height="7rem">{{
template: hbs`
<Rose::Dropdown @text="Choose One&hellip;" @icon="flight-icons/svg/org-16" @showCaret={{showCaret}} as |dropdown|>
<Rose::Dropdown @text="Choose One&hellip;" @count={{count}} @icon="flight-icons/svg/org-16" @showCaret={{showCaret}} as |dropdown|>
<dropdown.link @route="index">Menu item</dropdown.link>
<dropdown.link @route="about">Menu item</dropdown.link>
<dropdown.separator />
@@ -24,6 +24,7 @@ A simple dropdown component with support for links and buttons.
</Rose::Dropdown>
`,
context: {
count: number('count', 0),
showCaret: boolean('showCaret', true),
},
}}</Story>
@@ -39,6 +39,11 @@ $chevronGrey: url("data:image/svg+xml;utf-8,<svg viewBox='0 0 24 24' fill='%2362
border-radius: sizing.rems(xxxs);
white-space: nowrap;
.rose-badge {
padding-top: 0;
padding-bottom: 0;
}
// Hide default twistie triangle
// Webkit / Chromium
&::-webkit-details-marker {
@@ -98,6 +103,10 @@ $chevronGrey: url("data:image/svg+xml;utf-8,<svg viewBox='0 0 24 24' fill='%2362
&[open] > .rose-dropdown-trigger {
background-color: var(--ui-gray-subtler-4);
.rose-badge {
--background-color: var(--ui-gray-subtler-3);
}
}
.rose-dropdown-content {
@@ -6,8 +6,11 @@ $xxxxs: sizing.rems(xxxxs); // 1
.rose-toolbar {
background-color: var(--ui-gray-subtler-6);
padding: $xxs + $xxxxs;
.rose-form {
padding: $xxs + $xxxxs;
button {
display: inline-block;
font-weight: normal;
vertical-align: middle;
}
}
+2 -2
View File
@@ -35,7 +35,8 @@
"ember-named-blocks-polyfill": "^0.2.4",
"ember-radio-button": "^2.0.1",
"ember-uuid": "^2.1.0",
"emberx-select": "github:adopted-ember-addons/emberx-select#bc5f774"
"emberx-select": "github:adopted-ember-addons/emberx-select#bc5f774",
"ember-composable-helpers": "^4.5.0"
},
"devDependencies": {
"@babel/core": "^7.15.5",
@@ -65,7 +66,6 @@
"ember-cli-sass": "^10.0.1",
"ember-cli-sri": "^2.1.1",
"ember-cli-terser": "^4.0.2",
"ember-composable-helpers": "^4.5.0",
"ember-disable-prototype-extensions": "^1.1.3",
"ember-export-application-global": "^2.0.1",
"ember-inline-svg": "^1.0.0",
@@ -23,6 +23,11 @@ module('Integration | Component | rose/dropdown', function (hooks) {
assert.equal(find('.rose-dropdown-trigger').textContent.trim(), 'Click me');
});
test('it supports a count', async function (assert) {
await render(hbs`<Rose::Dropdown @text="Click me" @count="2" />`);
assert.equal(find('.rose-badge').textContent.trim(), '2');
});
test('it supports an icon', async function (assert) {
await render(
hbs`<Rose::Dropdown @icon="flight-icons/svg/user-circle-16" />`
@@ -4,6 +4,7 @@ import { action } from '@ember/object';
import loading from 'ember-loading/decorator';
import { confirm } from 'core/decorators/confirm';
import { notifySuccess, notifyError } from 'core/decorators/notify';
import { resourceFilterParam } from 'core/decorators/resource-filter-param';
export default class ScopesScopeAuthMethodsRoute extends Route {
// =services
@@ -12,6 +13,11 @@ export default class ScopesScopeAuthMethodsRoute extends Route {
@service notify;
@service session;
@service can;
@service resourceFilterStore;
// =attributes
@resourceFilterParam(['password', 'oidc']) type;
// =methods
@@ -32,7 +38,12 @@ export default class ScopesScopeAuthMethodsRoute extends Route {
if (
this.can.can('list collection', scope, { collection: 'auth-methods' })
) {
return this.store.query('auth-method', { scope_id });
const { type } = this;
return this.resourceFilterStore.queryBy(
'auth-method',
{ type },
{ scope_id }
);
}
}
@@ -185,4 +196,22 @@ export default class ScopesScopeAuthMethodsRoute extends Route {
const value = { from, to };
array.addObject(value);
}
/**
* Sets the specified resource filter field to the specified value.
* @param {string} field
* @param value
*/
@action
filterBy(field, value) {
this[field] = value;
}
/**
* Clears and filter selections.
*/
@action
clearAllFilters() {
this.type = [];
}
}
@@ -35,8 +35,58 @@
</page.actions>
<page.body>
{{#if @model}}
{{#if
(or
@model
(has-resource-filter-param-selections 'scopes.scope.auth-methods')
)
}}
<Rose::Toolbar>
<Rose::Form as |form|>
{{#with
(resource-filter-param 'scopes.scope.auth-methods' 'type')
as |filter|
}}
<Rose::Dropdown
@text={{t (concat 'form.' filter.name '.label')}}
@count={{filter.selectedValue.length}}
@ignoreClickInside={{true}}
as |dropdown|
>
<form.checkboxGroup
@name={{filter.name}}
@items={{filter.allowedValues}}
@selectedItems={{filter.selectedValue}}
@onChange={{route-action 'filterBy' filter.name}}
as |group|
>
<dropdown.item>
<group.checkbox
@label={{t
(concat 'resources.auth-method.types.' group.item)
}}
value={{group.item}}
/>
</dropdown.item>
</form.checkboxGroup>
</Rose::Dropdown>
{{/with}}
{{#if
(has-resource-filter-param-selections 'scopes.scope.auth-methods')
}}
<Rose::Button
@style='inline-link-action'
@iconLeft='flight-icons/svg/x-16'
{{on 'click' (route-action 'clearAllFilters')}}
>{{t 'actions.clear-all-filters'}}</Rose::Button>
{{/if}}
</Rose::Form>
</Rose::Toolbar>
{{/if}}
{{#if @model}}
{{#if (feature-flag 'primary-auth-method')}}
{{#unless this.hasPrimaryAuthMethod}}
<Rose::Notification
@@ -157,6 +207,18 @@
</table.body>
</Rose::Table>
{{else if (has-resource-filter-param-selections
'scopes.scope.auth-methods'
)}}
<Rose::Layout::Centered>
<Rose::Message @title={{t 'titles.no-results'}} as |message|>
<message.description>
{{t 'descriptions.no-results'}}
</message.description>
</Rose::Message>
</Rose::Layout::Centered>
{{else}}
<Rose::Layout::Centered>
+22 -15
View File
@@ -6993,14 +6993,14 @@ browserify-zlib@^0.2.0:
pako "~1.0.5"
browserslist@4.14.2, browserslist@^4.0.0, browserslist@^4.12.0, browserslist@^4.14.5, browserslist@^4.16.5, browserslist@^4.16.6, browserslist@^4.16.7, browserslist@^4.17.3:
version "4.17.4"
resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.17.4.tgz#72e2508af2a403aec0a49847ef31bd823c57ead4"
integrity sha512-Zg7RpbZpIJRW3am9Lyckue7PLytvVxxhJj1CaJVlCWENsGEAOlnlt8X0ZxGRPp7Bt9o8tIRM5SEXy4BCPMJjLQ==
version "4.17.6"
resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.17.6.tgz#c76be33e7786b497f66cad25a73756c8b938985d"
integrity sha512-uPgz3vyRTlEiCv4ee9KlsKgo2V6qPk7Jsn0KAn2OBqbqKo3iNcPEC1Ti6J4dwnz+aIRfEEEuOzC9IBk8tXUomw==
dependencies:
caniuse-lite "^1.0.30001265"
electron-to-chromium "^1.3.867"
caniuse-lite "^1.0.30001274"
electron-to-chromium "^1.3.886"
escalade "^3.1.1"
node-releases "^2.0.0"
node-releases "^2.0.1"
picocolors "^1.0.0"
bser@2.1.1:
@@ -7311,10 +7311,10 @@ caniuse-api@^3.0.0:
lodash.memoize "^4.1.2"
lodash.uniq "^4.5.0"
caniuse-lite@^1.0.0, caniuse-lite@^1.0.30001109, caniuse-lite@^1.0.30001157, caniuse-lite@^1.0.30001265:
version "1.0.30001271"
resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001271.tgz#0dda0c9bcae2cf5407cd34cac304186616cc83e8"
integrity sha512-BBruZFWmt3HFdVPS8kceTBIguKxu4f99n5JNp06OlPD/luoAMIaIK5ieV5YjnBLH3Nysai9sxj9rpJj4ZisXOA==
caniuse-lite@^1.0.0, caniuse-lite@^1.0.30001109, caniuse-lite@^1.0.30001157, caniuse-lite@^1.0.30001274:
version "1.0.30001279"
resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001279.tgz#eb06818da481ef5096a3b3760f43e5382ed6b0ce"
integrity sha512-VfEHpzHEXj6/CxggTwSFoZBBYGQfQv9Cf42KPlO79sWXCD1QNKWKsKzFeWL7QpZHJQYAvocqV6Rty1yJMkqWLQ==
capture-exit@^2.0.0:
version "2.0.0"
@@ -9151,10 +9151,10 @@ electron-rebuild@^2.0.3:
tar "^6.0.5"
yargs "^16.0.0"
electron-to-chromium@^1.3.867:
version "1.3.884"
resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.884.tgz#0cd8c3a80271fd84a81f284c60fb3c9ecb33c166"
integrity sha512-kOaCAa+biA98PwH5BpCkeUeTL6mCeg8p3Q3OhqzPyqhu/5QUnWAN2wr/3IK8xMQxIV76kfoQpP+Bn/wij/jXrg==
electron-to-chromium@^1.3.886:
version "1.3.895"
resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.895.tgz#9b0f8f2e32d8283bbb200156fd5d8dfd775f31ed"
integrity sha512-9Ww3fB8CWctjqHwkOt7DQbMZMpal2x2reod+/lU4b9axO1XJEDUpPMBxs7YnjLhhqpKXIIB5SRYN/B4K0QpvyQ==
element-resize-detector@^1.2.2:
version "1.2.3"
@@ -10335,6 +10335,13 @@ ember-template-recast@^5.0.1, ember-template-recast@^5.0.3:
tmp "^0.2.1"
workerpool "^6.1.4"
ember-truth-helpers@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/ember-truth-helpers/-/ember-truth-helpers-3.0.0.tgz#86766bdca4ac9b86bce3d262dff2aabc4a0ea384"
integrity sha512-hPKG9QqruAELh0li5xaiLZtr88ioWYxWCXisAWHWE0qCP4a2hgtuMzKUPpiTCkltvKjuqpzTZCU4VhQ+IlRmew==
dependencies:
ember-cli-babel "^7.22.1"
ember-try-config@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/ember-try-config/-/ember-try-config-3.0.0.tgz#012d8c90cae9eb624e2b62040bf7e76a1aa58edc"
@@ -16669,7 +16676,7 @@ node-pre-gyp@^0.11.0:
semver "^5.3.0"
tar "^4"
node-releases@^2.0.0:
node-releases@^2.0.1:
version "2.0.1"
resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-2.0.1.tgz#3d1d395f204f1f2f29a54358b9fb678765ad2fc5"
integrity sha512-CqyzN6z7Q6aMeF/ktcMVTzhAHCEpf8SOarwpzpf8pNBY2k5/oM34UHldUwp8VKI7uxct2HxSRdJjBaZeESzcxA==