diff --git a/addons/core/addon/components/dropdown/index.hbs b/addons/core/addon/components/dropdown/index.hbs
index f52926e90..36fbe29d2 100644
--- a/addons/core/addon/components/dropdown/index.hbs
+++ b/addons/core/addon/components/dropdown/index.hbs
@@ -13,6 +13,7 @@
@color='secondary'
@text={{@name}}
@count={{@checkedItems.length}}
+ {{!-- {{on 'click' this.open}} --}}
/>
{{#if @isSearchable}}
diff --git a/addons/core/addon/components/dropdown/index.js b/addons/core/addon/components/dropdown/index.js
index ba84cd198..779d90e27 100644
--- a/addons/core/addon/components/dropdown/index.js
+++ b/addons/core/addon/components/dropdown/index.js
@@ -70,6 +70,16 @@ export default class DropdownComponent extends Component {
onClose();
}
+ /**
+ * Sets selectedItems to checkedItems when the user opens
+ * the dropdown and potentially has made changes
+ * outside of the scope of dropdown
+ */
+ @action
+ open() {
+ this.selectedItems = [...this.args.checkedItems];
+ }
+
/**
* Custom close method for dropdown that resets selectedItems
* to checkedItems when the user closes the dropdown
diff --git a/addons/core/addon/components/filter-tags/index.hbs b/addons/core/addon/components/filter-tags/index.hbs
new file mode 100644
index 000000000..89839fe7e
--- /dev/null
+++ b/addons/core/addon/components/filter-tags/index.hbs
@@ -0,0 +1,21 @@
+{{#if this.filters}}
+
+ {{t
+ 'titles.filters-applied'
+ }}
+ {{#each this.filters as |filter|}}
+
+ {{/each}}
+
+
+{{/if}}
\ No newline at end of file
diff --git a/addons/core/addon/components/filter-tags/index.js b/addons/core/addon/components/filter-tags/index.js
new file mode 100644
index 000000000..0bacd1c54
--- /dev/null
+++ b/addons/core/addon/components/filter-tags/index.js
@@ -0,0 +1,67 @@
+import Component from '@glimmer/component';
+import { inject as service } from '@ember/service';
+import { action } from '@ember/object';
+import { assert } from '@ember/debug';
+
+export default class FilterTagsIndexComponent extends Component {
+ // =services
+
+ @service router;
+
+ // =attributes
+
+ get filters() {
+ return Object.entries(this.args.filters).flatMap(([key, value]) => {
+ assert(`Tags must be an array for key ${key}`, Array.isArray(value));
+ const paramsSet = new Set(this.getCurrentQueryParams(key));
+ const filters = value.filter((item) => paramsSet.has(item.id));
+
+ return filters.map((item) => ({
+ id: item.id,
+ name: item.name,
+ type: key,
+ }));
+ });
+ }
+
+ // =methods
+
+ getCurrentQueryParams(key) {
+ let queryParamValue;
+ try {
+ queryParamValue = JSON.parse(this.router.currentRoute.queryParams[key]);
+ } catch {
+ // We should never get an error as we are always asserting the queryParam to an array
+ queryParamValue = [];
+ }
+ return queryParamValue;
+ }
+
+ /**
+ * Clears a single filter from queryParams for current route
+ * @param {object} tag
+ */
+ @action
+ removeFilter(tag) {
+ const queryParamValue = this.getCurrentQueryParams(tag.type);
+
+ const queryParams = {
+ [tag.type]: queryParamValue.filter((item) => item !== tag.id),
+ };
+
+ this.router.replaceWith({ queryParams });
+ }
+
+ /**
+ * Clears all filters based on provided queryParams
+ */
+ @action
+ clearAllFilters() {
+ const queryParams = Object.keys(this.args.filters).reduce((params, key) => {
+ params[key] = [];
+ return params;
+ }, {});
+
+ this.router.replaceWith({ queryParams });
+ }
+}
diff --git a/addons/core/addon/styles/addon.scss b/addons/core/addon/styles/addon.scss
new file mode 100644
index 000000000..445b3444f
--- /dev/null
+++ b/addons/core/addon/styles/addon.scss
@@ -0,0 +1,22 @@
+/**
+ * Copyright (c) HashiCorp, Inc.
+ * SPDX-License-Identifier: MPL-2.0
+ */
+
+.filters-applied {
+ display: flex;
+ flex-wrap: wrap;
+ align-items: center;
+ margin-bottom: 1rem;
+ gap: 0.5rem;
+
+ .filter-tag {
+ max-width: 200px;
+
+ .hds-tag__text {
+ overflow: hidden;
+ text-overflow: ellipsis;
+ white-space: nowrap;
+ }
+ }
+}
diff --git a/addons/core/app/components/filter-tags/index.js b/addons/core/app/components/filter-tags/index.js
new file mode 100644
index 000000000..4e722476f
--- /dev/null
+++ b/addons/core/app/components/filter-tags/index.js
@@ -0,0 +1 @@
+export { default } from 'core/components/filter-tags/index';
diff --git a/addons/core/app/styles/app.scss b/addons/core/app/styles/app.scss
new file mode 100644
index 000000000..3af54990c
--- /dev/null
+++ b/addons/core/app/styles/app.scss
@@ -0,0 +1,4 @@
+/**
+ * Copyright (c) HashiCorp, Inc.
+ * SPDX-License-Identifier: MPL-2.0
+ */
diff --git a/addons/core/package.json b/addons/core/package.json
index aebdde457..981aae0bb 100644
--- a/addons/core/package.json
+++ b/addons/core/package.json
@@ -37,12 +37,14 @@
"ember-browser-services": "^4.0.3",
"ember-cli-babel": "^7.26.11",
"ember-cli-htmlbars": "^6.2.0",
+ "ember-cli-sass": "^11.0.1",
"ember-feature-flags": "^6.0.0",
"ember-intl": "^6.0.0-beta.6",
"ember-loading": "^2.0.0",
"ember-truth-helpers": "^3.0.0",
"filesize": "^10.0.7",
- "intl-unofficial-duration-unit-format": "^3.1.0"
+ "intl-unofficial-duration-unit-format": "^3.1.0",
+ "sass": "^1.69.5"
},
"devDependencies": {
"@babel/eslint-parser": "^7.21.3",
@@ -82,6 +84,7 @@
"qunit": "^2.19.4",
"qunit-dom": "^2.0.0",
"rose": "*",
+ "sinon": "^17.0.1",
"webpack": "^5.78.0"
},
"peerDependencies": {
diff --git a/addons/core/tests/dummy/app/styles/app.css b/addons/core/tests/dummy/app/styles/app.css
index 25bf4df27..f350ec90f 100644
--- a/addons/core/tests/dummy/app/styles/app.css
+++ b/addons/core/tests/dummy/app/styles/app.css
@@ -3,3 +3,4 @@
* SPDX-License-Identifier: MPL-2.0
*/
+@import 'addon/styles/addons.scss';
diff --git a/addons/core/tests/integration/components/filter-tags/index-test.js b/addons/core/tests/integration/components/filter-tags/index-test.js
new file mode 100644
index 000000000..45e9cf820
--- /dev/null
+++ b/addons/core/tests/integration/components/filter-tags/index-test.js
@@ -0,0 +1,29 @@
+import { module, test } from 'qunit';
+import { setupRenderingTest } from 'ember-qunit';
+import { setupIntl } from 'ember-intl/test-support';
+import { render } from '@ember/test-helpers';
+import { hbs } from 'ember-cli-htmlbars';
+import sinon from 'sinon';
+
+module('Integration | Component | filter-tags/index', function (hooks) {
+ setupRenderingTest(hooks);
+ setupIntl(hooks);
+
+ hooks.afterEach(function () {
+ sinon.restore();
+ });
+
+ test('it renders', async function (assert) {
+ const router = this.owner.lookup('service:router');
+ sinon.stub(router, 'currentRoute').value({
+ queryParams: {
+ scopes: JSON.stringify(['1']),
+ },
+ });
+
+ this.set('filter', { scopes: [{ id: '1', name: 'Project 1' }] });
+ await render(hbs``);
+
+ assert.dom('.hds-tag__text').hasText('Project 1');
+ });
+});
diff --git a/addons/core/translations/actions/en-us.yaml b/addons/core/translations/actions/en-us.yaml
index c9fff6205..3bb2884c3 100644
--- a/addons/core/translations/actions/en-us.yaml
+++ b/addons/core/translations/actions/en-us.yaml
@@ -44,6 +44,7 @@ toggle-secret: Toggle secret visibility
minimize: Minimize
fullscreen: Fullscreen
clear-all-filters: Clear all filters
+clear-filters: Clear filters
learn-more: Learn more
refresh: Refresh
remove-resources: Remove resources and save
diff --git a/addons/core/translations/en-us.yaml b/addons/core/translations/en-us.yaml
index f451416e2..63bcf9866 100644
--- a/addons/core/translations/en-us.yaml
+++ b/addons/core/translations/en-us.yaml
@@ -39,6 +39,7 @@ titles:
choose-an-option: Choose an option
feature-edition: 'Edition: {edition}'
no-results-found: No results found
+ filters-applied: 'Filters Applied:'
unit: Unit
year: '{numberOfYears, plural, =1 {# year} other {# years}}'
days: '{days, plural, =1 {# day} other {# days}}'
diff --git a/addons/rose/app/components/rose/filter-tags/index.js b/addons/rose/app/components/rose/filter-tags/index.js
new file mode 100644
index 000000000..090ac627f
--- /dev/null
+++ b/addons/rose/app/components/rose/filter-tags/index.js
@@ -0,0 +1 @@
+export { default } from 'rose/components/rose/filter-tags/index';
diff --git a/addons/rose/package.json b/addons/rose/package.json
index 59b0a4318..73419cd70 100644
--- a/addons/rose/package.json
+++ b/addons/rose/package.json
@@ -44,7 +44,7 @@
"ember-radio-button": "github:yapplabs/ember-radio-button.git#b2ab65f",
"ember-uuid": "^2.1.0",
"jsonlint": "^1.6.3",
- "sass": "^1.55.0"
+ "sass": "^1.69.5"
},
"devDependencies": {
"@babel/core": "^7.18.5",
diff --git a/ui/desktop/app/controllers/scopes/scope/projects/targets/index.js b/ui/desktop/app/controllers/scopes/scope/projects/targets/index.js
index c79995103..63a7ba9aa 100644
--- a/ui/desktop/app/controllers/scopes/scope/projects/targets/index.js
+++ b/ui/desktop/app/controllers/scopes/scope/projects/targets/index.js
@@ -103,6 +103,20 @@ export default class ScopesScopeProjectsTargetsIndexController extends Controlle
return orderBy(sessions, 'created_time', 'desc');
}
+ /**
+ * Returns object of filters to be used for displaying selected filters
+ * @returns {object}
+ */
+ get filters() {
+ return {
+ scopes: this.model.projects,
+ availableSessions: this.availableSessionOptions,
+ type: [],
+ };
+ }
+
+ // =methods
+
/**
* Quick connect method used to call main connect method and handle
* connection errors unique to this route
@@ -202,6 +216,11 @@ export default class ScopesScopeProjectsTargetsIndexController extends Controlle
this.page = 1;
}
+ @action
+ toggleSessionsFlyout() {
+ this.sessionsFlyoutActive = !this.sessionsFlyoutActive;
+ }
+
/**
* Sets the scopes query param to value of selectedScopes
* to trigger a query and closes the dropdown
diff --git a/ui/desktop/app/templates/scopes/scope/projects/targets/index.hbs b/ui/desktop/app/templates/scopes/scope/projects/targets/index.hbs
index 9f36cce04..a5a8ed35a 100644
--- a/ui/desktop/app/templates/scopes/scope/projects/targets/index.hbs
+++ b/ui/desktop/app/templates/scopes/scope/projects/targets/index.hbs
@@ -62,6 +62,7 @@
{{! TODO: Target type filter}}
+
{{#if @model.targets}}
=5", "@sinonjs/fake-timers@^9.1.2":
version "9.1.2"
resolved "https://registry.yarnpkg.com/@sinonjs/fake-timers/-/fake-timers-9.1.2.tgz#4eaab737fab77332ab132d396a3c0d364bd0ea8c"
@@ -5348,6 +5362,20 @@
dependencies:
"@sinonjs/commons" "^1.7.0"
+"@sinonjs/fake-timers@^10.0.2":
+ version "10.3.0"
+ resolved "https://registry.yarnpkg.com/@sinonjs/fake-timers/-/fake-timers-10.3.0.tgz#55fdff1ecab9f354019129daf4df0dd4d923ea66"
+ integrity sha512-V4BG07kuYSUkTCSBHG8G8TNhM+F19jXFWnQtzj+we8DrkpSBCee9Z3Ms8yiGer/dlmhe35/Xdgyo3/0rQKg7YA==
+ dependencies:
+ "@sinonjs/commons" "^3.0.0"
+
+"@sinonjs/fake-timers@^11.2.2":
+ version "11.2.2"
+ resolved "https://registry.yarnpkg.com/@sinonjs/fake-timers/-/fake-timers-11.2.2.tgz#50063cc3574f4a27bd8453180a04171c85cc9699"
+ integrity sha512-G2piCSxQ7oWOxwGSAyFHfPIsyeJGXYtc6mFbnFA+kRXkiEnTl8c/8jul2S329iFBnDI9HGoeWWAZvuvOkZccgw==
+ dependencies:
+ "@sinonjs/commons" "^3.0.0"
+
"@sinonjs/fake-timers@^8.0.1":
version "8.1.0"
resolved "https://registry.yarnpkg.com/@sinonjs/fake-timers/-/fake-timers-8.1.0.tgz#3fdc2b6cb58935b21bfb8d1625eb1300484316e7"
@@ -5364,6 +5392,15 @@
lodash.get "^4.4.2"
type-detect "^4.0.8"
+"@sinonjs/samsam@^8.0.0":
+ version "8.0.0"
+ resolved "https://registry.yarnpkg.com/@sinonjs/samsam/-/samsam-8.0.0.tgz#0d488c91efb3fa1442e26abea81759dfc8b5ac60"
+ integrity sha512-Bp8KUVlLp8ibJZrnvq2foVhP0IVX2CIprMJPK0vqGqgrDa0OHVKeZyBykqskkrdxV6yKBPmGasO8LVjAKR3Gew==
+ dependencies:
+ "@sinonjs/commons" "^2.0.0"
+ lodash.get "^4.4.2"
+ type-detect "^4.0.8"
+
"@sinonjs/text-encoding@^0.7.1":
version "0.7.1"
resolved "https://registry.yarnpkg.com/@sinonjs/text-encoding/-/text-encoding-0.7.1.tgz#8da5c6530915653f3a1f38fd5f101d8c3f8079c5"
@@ -8286,9 +8323,9 @@ caniuse-lite@^1.0.0, caniuse-lite@^1.0.30001502, caniuse-lite@^1.0.30001517, can
integrity sha512-xrE//a3O7TP0vaJ8ikzkD2c2NgcVUvsEe2IvFTntV4Yd1Z9FVzh+gW+enX96L0psrbaFMcVcH2l90xNuGDWc8w==
caniuse-lite@^1.0.30001565:
- version "1.0.30001570"
- resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001570.tgz#b4e5c1fa786f733ab78fc70f592df6b3f23244ca"
- integrity sha512-+3e0ASu4sw1SWaoCtvPeyXp+5PsjigkSt8OXZbF9StH5pQWbxEjLAZE3n8Aup5udop1uRiKA7a4utUk/uoSpUw==
+ version "1.0.30001571"
+ resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001571.tgz#4182e93d696ff42930f4af7eba515ddeb57917ac"
+ integrity sha512-tYq/6MoXhdezDLFZuCO/TKboTzuQ/xR5cFdgXPfDtM7/kchBO3b4VWghE/OAi/DV7tTdhmLjZiZBZi1fA/GheQ==
capture-exit@^2.0.0:
version "2.0.0"
@@ -9832,9 +9869,9 @@ electron-to-chromium@^1.4.535:
integrity sha512-t2ZP4AcGE0iKCCQCBx/K2426crYdxD3YU6l0uK2EO3FZH0pbC4pFz/sZm2ruZsND6hQBTcDWWlo/MLpiOdif5g==
electron-to-chromium@^1.4.601:
- version "1.4.613"
- resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.613.tgz#529e4fc65576ecfd055d7d4619fade4fac446af2"
- integrity sha512-r4x5+FowKG6q+/Wj0W9nidx7QO31BJwmR2uEo+Qh3YLGQ8SbBAFuDFpTxzly/I2gsbrFwBuIjrMp423L3O5U3w==
+ version "1.4.615"
+ resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.615.tgz#b1c41839962d2e4e63dca05519da9040e34848c2"
+ integrity sha512-/bKPPcgZVUziECqDc+0HkT87+0zhaWSZHNXqF8FLd2lQcptpmUFwoCSWjCdOng9Gdq+afKArPdEg/0ZW461Eng==
elliptic@^6.5.3, elliptic@^6.5.4:
version "6.5.4"
@@ -16849,6 +16886,17 @@ nise@^5.1.1:
just-extend "^4.0.2"
path-to-regexp "^1.7.0"
+nise@^5.1.5:
+ version "5.1.5"
+ resolved "https://registry.yarnpkg.com/nise/-/nise-5.1.5.tgz#f2aef9536280b6c18940e32ba1fbdc770b8964ee"
+ integrity sha512-VJuPIfUFaXNRzETTQEEItTOP8Y171ijr+JLq42wHes3DiryR8vT+1TXQW/Rx8JNUhyYYWyIvjXTU6dOhJcs9Nw==
+ dependencies:
+ "@sinonjs/commons" "^2.0.0"
+ "@sinonjs/fake-timers" "^10.0.2"
+ "@sinonjs/text-encoding" "^0.7.1"
+ just-extend "^4.0.2"
+ path-to-regexp "^1.7.0"
+
no-case@^3.0.4:
version "3.0.4"
resolved "https://registry.yarnpkg.com/no-case/-/no-case-3.0.4.tgz#d361fd5c9800f558551a8369fc0dcd4662b6124d"
@@ -19163,15 +19211,6 @@ sane@^5.0.1:
minimist "^1.1.1"
walker "~1.0.5"
-sass@^1.55.0:
- version "1.55.0"
- resolved "https://registry.yarnpkg.com/sass/-/sass-1.55.0.tgz#0c4d3c293cfe8f8a2e8d3b666e1cf1bff8065d1c"
- integrity sha512-Pk+PMy7OGLs9WaxZGJMn7S96dvlyVBwwtToX895WmCpAOr5YiJYEUJfiJidMuKb613z2xNWcXCHEuOvjZbqC6A==
- dependencies:
- chokidar ">=3.0.0 <4.0.0"
- immutable "^4.0.0"
- source-map-js ">=0.6.2 <2.0.0"
-
sass@^1.69.5:
version "1.69.5"
resolved "https://registry.yarnpkg.com/sass/-/sass-1.69.5.tgz#23e18d1c757a35f2e52cc81871060b9ad653dfde"
@@ -19469,6 +19508,18 @@ sinon@^14.0.0:
nise "^5.1.1"
supports-color "^7.2.0"
+sinon@^17.0.1:
+ version "17.0.1"
+ resolved "https://registry.yarnpkg.com/sinon/-/sinon-17.0.1.tgz#26b8ef719261bf8df43f925924cccc96748e407a"
+ integrity sha512-wmwE19Lie0MLT+ZYNpDymasPHUKTaZHUH/pKEubRXIzySv9Atnlw+BUMGCzWgV7b7wO+Hw6f1TEOr0IUnmU8/g==
+ dependencies:
+ "@sinonjs/commons" "^3.0.0"
+ "@sinonjs/fake-timers" "^11.2.2"
+ "@sinonjs/samsam" "^8.0.0"
+ diff "^5.1.0"
+ nise "^5.1.5"
+ supports-color "^7.2.0"
+
sisteransi@^1.0.5:
version "1.0.5"
resolved "https://registry.yarnpkg.com/sisteransi/-/sisteransi-1.0.5.tgz#134d681297756437cc05ca01370d3a7a571075ed"