Compare commits

...
209 Commits
Author SHA1 Message Date
Cameron Perera cb895024e0 fix: 🐛 update hidden secrets and flatten-nested-object logic (#2672) 2025-01-30 18:00:26 -06:00
Cameron Perera 2e94ebdb64 chore: 🤖 update cli version and CHANGELOG (#2670)
* chore: 🤖 update cli version and CHANGELOG

* chore: 🤖 fix dc release date in CHANGELOG
2025-01-29 12:06:27 -06:00
Cameron Perera ae1e6d2748 feat: 🎸 add showFilterGenerator to WorkerFilterGenerator comp (#2669)
✅ Closes: https://hashicorp.atlassian.net/browse/ICU-16282
2025-01-28 16:24:38 -08:00
Laurenandcameronperera c72d4f35a0 Vault cred store filter create (#2668)
* refactor: 💡 add worker filter back to create form

✅ Closes: ICU-16281

* add helper text to worker filter generator at creation state

* set isOptional to true

* set isOptional to true

---------

Co-authored-by: cameronperera <cameron.perera@hashicorp.com>
2025-01-28 16:46:11 -05:00
Michael Li 9742d824c4 test(e2e/desktop): Address failures in session tests (#2664)
* test(e2e): Address failures in session tests

* CR
2025-01-28 11:04:46 -05:00
Lisbet Alvarez 639aa47e19 refactor: 💡 Update text for fields in AWS & GCP host catalogs (#2667) 2025-01-27 15:36:30 -08:00
Michael Li 5fa0d11aa9 test(e2e/admin): Updates for 0.19.0 (#2665)
* test(e2e): Update "Inactive" locators

* test(e2e): Update worker filter locators

* test(e2e): Address flake

Ensure that the test has reached the org page before trying to click the Auth Methods link (there is an auth method link on both the global page and the org page).
2025-01-27 10:01:44 -05:00
Dharini Jeeva fed32aa57b chore: 🤖 add doc links for GCP plugin (#2666) 2025-01-24 12:45:56 -08:00
Carlos Alcaide Corvo 1e2134bd7e Refactor auth methods red test selectors (#2656)
* Refactor auth-methods list acceptance test selectors
2025-01-24 12:11:19 -08:00
Dharini Jeeva 064375d457 test: 💍 add e2e tests for credentials display in desktop (#2660)
* test: 💍 add e2e tests for credentials display in desktop
2025-01-23 14:30:54 -08:00
Dharini Jeeva deff38de56 fix: 🐛 include GCP plugin text (#2662)
* fix: 🐛 include GCP plugin text
2025-01-23 13:34:33 -08:00
Carlos Alcaide Corvo 15950d3a09 fix: 🐛 Fix HDS deprecation message (#2661)
Fix HDS deprecation message for HDS Dropdown interactive component using
@text rather than yielding it.
2025-01-23 08:15:12 -08:00
Carlos Alcaide Corvo c4539b8e30 Refactor auth-methods list acceptance test selectors (#2654)
Refactor auth-methods list acceptance test selectors
2025-01-22 14:32:16 -08:00
Carlos Alcaide Corvo 904864b14e Test icu 15459 auth method create test selectors refactor (#2653)
Refactor selectors
2025-01-20 09:45:15 -08:00
Zhihe Li 390d179917 feat: 🎸 Added GCP host sets and hosts (#2655)
✅ Closes: https://hashicorp.atlassian.net/browse/ICU-15994
2025-01-10 14:18:48 -08:00
Dharini Jeeva 3b6a421af2 chore: Updates to gcp hc form (#2649)
* chore: 🤖 add worker_filter field, updates to helper text
2025-01-10 14:18:48 -08:00
Dharini Jeeva cc8d4fe952 test: GCP plugin acceptance tests (#2648) 2025-01-10 14:18:48 -08:00
Dharini Jeeva dfa62dd04b chore: 🤖 gcp plugin creation in the UI (#2645)
gcp plugin creation and mirage changes
2025-01-10 14:18:48 -08:00
Dharini Jeeva 520020f2c6 Chore: refactor host catalog model and serializer to accommodate GCP plugin (#2627)
* chore: 🤖 GCP plugin support
2025-01-10 14:18:48 -08:00
hashiccandhashicc 31f1ed8dd4 test(e2e): add e2e test for scope chooser with filtered targets (#2644)
* test(e2e): add e2e test for scope chooser with filtered targets

Closes: https://hashicorp.atlassian.net/browse/ICU-16121

* Add missing copyright headers

* chore(e2e): use prettier on scope.spec.js

* refactor(e2e): use explicit checks for scope in summary

* refactor(e2e): move test hooks and associated variables to top-level

Move beforeEach and afterEach and the associated variables setup in
hooks to top-level within scope.spec.js. This matches the patterns
used in other tests.

* refactor(e2e): use simpler scoped locator for summary element within header-nav

---------

Co-authored-by: hashicc <hashicc@users.noreply.github.com>
2025-01-10 17:00:49 -05:00
Cameron Perera 5abd4f1f4f Icu 15470 credential store create test (#2650)
* refactor: 💡 clean up urls in create test file

✅ Closes: https://hashicorp.atlassian.net/browse/ICU-15470

* test: 💍 update cred store create to use selectors

✅ Closes: https://hashicorp.atlassian.net/browse/ICU-15470
2025-01-10 09:57:32 -06:00
Lisbet Alvarez 862ce645cf fix: 🐛 hds dialog text wrong color when system mode is dark (#2651) 2025-01-09 15:30:06 -08:00
Lisbet Alvarez 9eccbb91db refactor: 💡 Update name radio option label & set toggle default to on (#2652)
* refactor: 💡 Update name radio option label & default toggle on
2025-01-09 15:18:17 -08:00
Carlos Alcaide Corvo 343e1d2193 test: 💍 Refactor host list test selectors (#2629)
* test: 💍 Refactor host list test selectors
2025-01-08 09:14:29 -08:00
Zhihe Li 9a11925216 docs: ✏️ Update readme docs for e2e tests (#2647) 2025-01-07 17:28:28 -05:00
Lisbet Alvarez f7f1041daa fix: 🐛 oidc retry not working for secure links in desktop ui (#2641)
* fix: 🐛 oidc retry not working for secure links in desktop ui
2025-01-07 10:56:32 -08:00
Michael Li 1cbf3b227e test(e2e): Add additional assertions to UI tests (#2634)
* test(e2e): Address deprecation

* test(e2e): Add additional connection assertions on tests

* CR: Fix flake when waiting for sessions

If no sessions are available and the page needs to reload, we should wait to ensure that the page has loaded before checking what the state of the sessions are

* CR: Address flake in connect methods

Noticed an issue where a session recording was not playable. The theory is that the session didn't last long enough before it was cancelled. This adds a 2 second wait after establishing a connection before continuing.

* CR: Use authenticated state by default

* CR: Update dynamic host catalog assertion

* CR: Simplify host set checks

- Use .all() when looping
- Add check to see if we need to reload the page or not

* CR: Be more specific with locator

Ran into a conflict with the Static/Dynamic host catalog type and the Static/Dynamic credential type.

* CR: Update connection methods to be more resilient

Rather than using a hardcoded sleep, we will now run a command on the target and wait for a specific string to return before continuing.

* CR
2025-01-06 11:40:32 -05:00
Lisbet Alvarez faf4ecfac6 Fix memory leak issue when using fetch in oidc authentication (#2640)
* test: 💍 test 1

* chore: 🤖 remove waitForPromise use

* chore: 🤖 remove all other waitforpromise usage

* test: 💍 turn down polling

* test: 💍 use .json

* refactor: 💡 add waitForPromise back in & consume response body

* test: 💍 some testing

* test: 💍 more testing

* refactor: 💡 clean-up a bit

* refactor: 💡 use head method request & clean up comments

* refactor: 💡 use get method & consume response body

* test: 💍 fix token validation test cases
2025-01-03 14:06:27 -08:00
Michael Li ca4aad0a2b test(e2e): Add Admin UI test for OIDC auth method (#2638)
* test(e2e): Add managed group check in LDAP test

* test(e2e): Add oidc test

* CR: Suppress warning

* CR: Use toHaveText
2025-01-03 14:19:33 -05:00
hashicorp-tsccr[bot]andhashicorp-tsccr[bot] ed569306bb Result of tsccr-helper -log-level=info gha update -latest .github/ (#2642)
Co-authored-by: hashicorp-tsccr[bot] <hashicorp-tsccr[bot]@users.noreply.github.com>
2025-01-02 09:41:32 -08:00
Lisbet Alvarez 65abd7a4e3 fix: 🐛 code block error in console when value is empty on save (#2637) 2024-12-20 14:03:35 -08:00
Lauren 422cff4547 [ICU-15647] Replace Rose::Dialog with Hds::Modal in admin ui only (#2623)
* sort list

* refactor: 💡 Replace Rose::Dialog with Hds::Modal

✅ Closes: ICU-15647

* refactor targets-host-sources-test

* refactor update-test

* update test selectors

* refactor delete test

* refactor org scope test

* refactor delete scope and auth-method tests

* refactor update host catalogs tests

* refactor credential-stores credential update tests

* refactor credential-stores credentials delete tests

* refactor scopes update tests

* refactor storage buckets delete test

* refactor storage buckets delete test

* refactor credential library update test

* refactor targest workers test

* refactor workers create tags test

* refactor global scope test

* refactor users update test

* refactor host catalogs delete test

* refactor credential-store update tests

* refactor host catalogs, hosts and sets update tests

* remove unused vars

* rename selectors, remove attrs

* add @onDismiss callback
2024-12-20 14:16:43 -05:00
Lisbet Alvarez 7695135302 refactor: 💡 application state ability dependent descriptions (#2631)
* refactor: 💡 application state ability dependent descriptions

✅ Closes: https://hashicorp.atlassian.net/browse/ICU-15813
2024-12-17 16:03:56 -08:00
Cameron Perera 5be4868e9a refactor: 💡 rename arialabel to aria-labelledby for key/value (#2633)
* refactor: 💡 rename arialabel to aria-labelledby for key/value

✅ Closes: https://hashicorp.atlassian.net/browse/ICU-15701

* refactor: 💡 rename ariaLabelledBy to naming conventions

✅ Closes: https://hashicorp.atlassian.net/browse/ICU-15701
2024-12-17 13:58:04 -06:00
Cameron Perera fce97fd57a fix: 🐛 change disabled to readonly for form inputs (#2618)
✅ Closes: https://hashicorp.atlassian.net/browse/ICU-15666
2024-12-17 13:31:47 -06:00
Michael Li af8655ec45 test(e2e): Refactor imports for boundary cli helper methods (#2632)
* test(e2e): Update imports to match boundary-http conventions

* test(e2e): Remove cli from method name
2024-12-17 10:17:32 -05:00
Cameron Perera daed714b98 test: 💍 update selectors for credential-library tests (#2630)
delete and list

✅ Closes: https://hashicorp.atlassian.net/browse/ICU-15468
2024-12-16 16:31:07 -06:00
Carlos Alcaide Corvo 584e62cff3 test: 💍 Refactor host delete test selectors (#2626)
Refactor host-catalog host delete acceptance test selectors
2024-12-13 15:57:10 -08:00
Lisbet Alvarez 6d2f1dcbbf Cleanup worker filter translations (#2621)
* refactor: 💡 clean-up worker filter translations
2024-12-12 16:06:38 -08:00
Cameron Perera 5e7b74a7ed test: 💍 use selectors in update credential-libraries (#2624)
✅ Closes: https://hashicorp.atlassian.net/browse/ICU-15467
2024-12-12 12:26:52 -06:00
Dharini Jeeva 6de20b03ef chore: handle nested data from static json credentials (#2611) 2024-12-11 15:08:51 -08:00
2869020e65 Llb/worker filter improvements (#2614)
* test: 💍 clean up worker filter component tests (#2559)

* Icu 15741 add show filter generator toggle to worker filter component (#2562)

* feat: 🎸 add filter generator to worker filter component

✅ Closes: https://hashicorp.atlassian.net/browse/ICU-15741

* feat: 🎸 show add worker filter when none set for targets (#2564)

✅ Closes: https://hashicorp.atlassian.net/browse/ICU-15760

* Icu 15743 tag workflow (#2565)

* feat: 🎸 add tag generator workflow

✅ Closes: https://hashicorp.atlassian.net/browse/ICU-15743

* test: 💍 add test cases

✅ Closes: https://hashicorp.atlassian.net/browse/ICU-15743

* refactor: 💡 update selected type name to selectedGeneratorType

✅ Closes: https://hashicorp.atlassian.net/browse/ICU-15743

* Apply suggestions from code review

minor translation change

Co-authored-by: Lisbet Alvarez <107949262+lisbet-alvarez@users.noreply.github.com>

* refactor: 💡 update id for generated-value

✅ Closes: https://hashicorp.atlassian.net/browse/ICU-15743

---------

Co-authored-by: Lisbet Alvarez <lisbet.alvarez@hashicorp.com>
Co-authored-by: Lisbet Alvarez <107949262+lisbet-alvarez@users.noreply.github.com>

* Icu 15744 name workflow (#2566)

* feat: 🎸 add name workflow

✅ Closes: https://hashicorp.atlassian.net/browse/ICU-15744

* test: 💍 add "name" workflow tests for filter generator

✅ Closes: https://hashicorp.atlassian.net/browse/ICU-15744

* refactor: 💡 use const test selectors for filter generator

✅ Closes: https://hashicorp.atlassian.net/browse/ICU-15744

* refactor: 💡 add default option

✅ Closes: https://hashicorp.atlassian.net/browse/ICU-15744

* docs: ✏️ fix comment

✅ Closes: https://hashicorp.atlassian.net/browse/ICU-15744

---------

Co-authored-by: cameronperera <cameron.perera@hashicorp.com>

* refactor: 💡 move worker filter generator outside of rose::form (#2574)

* refactor: 💡 move worker filter generator outside of rose::form

* [ICU-15718] Add worker filter route, template for empty state (#2576)

* feat: 🎸 Vault Credential Store Worker Filter

The Worker Filters tab will display the associated worker filter and
have an empty state for when there is no worker filter assigned.

* add template

* Add missing copyright headers

* update styling, remove Rose component

* color primary is already default, remove

* add rose component, remove custom css

* fix test

* singularize lang

---------

Co-authored-by: laurenolivia <laurenolivia@users.noreply.github.com>

* feat: 🎸 update worker filter field to use code editor (#2578)

* feat: 🎸 update worker filter field to use code editor

✅ Closes: https://hashicorp.atlassian.net/browse/ICU-15737

* test: 💍 fix failing storage bucket tests

✅ Closes: https://hashicorp.atlassian.net/browse/ICU-15737

* test: 💍 update tests for new worker filter field (#2580)

* test: 💍 update tests for new worker filter field

✅ Closes: https://hashicorp.atlassian.net/browse/ICU-15739

* Update ui/admin/tests/acceptance/storage-buckets/update-test.js

Co-authored-by: Lisbet Alvarez <107949262+lisbet-alvarez@users.noreply.github.com>

---------

Co-authored-by: Lisbet Alvarez <107949262+lisbet-alvarez@users.noreply.github.com>

* [ICU-15719] Create edit worker filter route and template (#2582)

* add codeblock to template

* add cancel btn fn

* add controller test

* add save fn

* display formatted worker filter text inside codeblock

* move codeblock component outside rose::layout::centered

* remove console.log

* remove router.refresh() and refactor translations yaml

* refactor translations, add breadcrumb::item

* replace html elements with hds

* move component, delete file

* [ICU-15720] Add edit worker filter action to manage dropdown (#2593)

* add acceptance test file

* delete test file

* add edit option to manage dropdown

* update route in dropdown

* add check for model isVault

* add acceptance test file

* delete test file

* remove data test selectors, fix syntax

* [ICU-15721] Remove worker filter input field (#2596)

* remove worker filter input field from vault credential store form

* revert yaml

* [ICU-15838] Add vault credential store worker filter tests (#2595)

* add data test elements

* add subtests to update-test.js

* add subtext to check for .hasText()

* add subtest when worker filter exists

* update subtest name

* remove console.log

* clean up

* add new selectors

* refactor: 💡 worker filter clean-up (#2592)

* refactor: 💡 worker filter clean-up

✅ Closes: https://hashicorp.atlassian.net/browse/ICU-15816

* refactor: 💡 add aria labels & missing can save check

✅ Closes: https://hashicorp.atlassian.net/browse/ICU-15816

* refactor: 💡 pr feedback of using uuid

✅ Closes: https://hashicorp.atlassian.net/browse/ICU-15816

* Add missing copyright headers

* refactor: 💡 use unique-id helper for aria labels (pr feedback)

✅ Closes: https://hashicorp.atlassian.net/browse/ICU-15816

---------

Co-authored-by: lisbet-alvarez <lisbet-alvarez@users.noreply.github.com>

* refactor: 💡 update icon logic for egress worker filter (#2612)

* refactor: 💡 update worker_filter help translation

* refactor: 💡 add maxHeight to worker filter code blocks

* refactor: 💡 use existing default option for dropdowns

* refactor: 💡 hide copy button when no result to copy

and remove unused styles

---------

Co-authored-by: Lisbet Alvarez <107949262+lisbet-alvarez@users.noreply.github.com>
Co-authored-by: Lisbet Alvarez <lisbet.alvarez@hashicorp.com>
Co-authored-by: Lauren <lauren.burwell@hashicorp.com>
Co-authored-by: laurenolivia <laurenolivia@users.noreply.github.com>
Co-authored-by: lisbet-alvarez <lisbet-alvarez@users.noreply.github.com>
2024-12-11 14:00:27 -06:00
Carlos Alcaide Corvo 40c8ceeca6 Change validation field from name (optional) to address (required) (#2619) 2024-12-11 08:04:45 -08:00
Lisbet Alvarez 0623d4ad47 Fix e2e test page selectors due to hds refactor (#2610)
* chore: 🤖 fix e2e broken tests due to hds refactor

* chore: 🤖 remove unneeded change & fix another selector

* chore: 🤖 upgrade playwright

* chore: 🤖 remove unneeded dependency in desktop ui
2024-12-10 16:24:25 -08:00
dependabot[bot]andZhihe Li 0b9c235dd2 chore(deps-dev): bump nanoid from 5.0.8 to 5.0.9 (#2620)
Bumps [nanoid](https://github.com/ai/nanoid) from 5.0.8 to 5.0.9.
- [Release notes](https://github.com/ai/nanoid/releases)
- [Changelog](https://github.com/ai/nanoid/blob/main/CHANGELOG.md)
- [Commits](https://github.com/ai/nanoid/compare/5.0.8...5.0.9)

---
updated-dependencies:
- dependency-name: nanoid
  dependency-type: direct:development
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Zhihe Li <zhihe.li@hashicorp.com>
2024-12-10 16:53:38 -05:00
Zhihe Li e16b4e68c8 Icu 14778 add more sessions tests (#2615)
* test: 💍 Add desktop sessions tests

✅ Closes: https://hashicorp.atlassian.net/browse/ICU-14778

* chore: 🤖 Add support for dotenv and stop using relative paths

✅ Closes: https://hashicorp.atlassian.net/browse/ICU-14778

* refactor: 💡 Force usage of node 20

✅ Closes: https://hashicorp.atlassian.net/browse/ICU-14778
2024-12-10 16:11:12 -05:00
Cameron Perera 078e36f9b8 fix: 🐛 update @name attribute for RadioCard Groups (#2617)
✅ Closes: https://hashicorp.atlassian.net/browse/ICU-15676
2024-12-10 14:12:43 -06:00
Zhihe Li 8874d0be86 docs: ✏️ Add to readme how to run admin e2e against local branch (#2616)
* docs: ✏️ Add to readme how to run admin e2e against local branch

* chore: 🤖 Add packageManager field for corepack users
2024-12-10 12:30:57 -05:00
Carlos Alcaide Corvo b59afd3455 test: 💍 Update test selectors for update host test (#2609) 2024-12-09 09:42:16 -08:00
Lauren 85a2684532 refactor: 💡 Replace rose::separator comp with hds::separator (#2613)
* refactor: 💡 Replace rose::separator comp with hds::separator

This PR replaces the rose::separator with the hds::separator and removes
an integration test that is no longer needed

✅ Closes: ICU-15646

* retire rose::separator and remove styling

* remove separator import

* remove separator.js
2024-12-06 12:54:47 -05:00
Carlos Alcaide Corvo f9a7864b07 fix: 🐛 Delete peerDeps within our addons (#2605)
* fix: 🐛 Delete peerDeps within our addons
2024-12-04 17:17:51 -08:00
Lisbet Alvarez 371301b4ba refactor: 💡 use hds::applicationstate instead of rose::message (#2577)
* refactor: 💡 use hds::applicationstate instead of rose::message

✅ Closes: https://hashicorp.atlassian.net/browse/ICU-15639
2024-12-04 14:16:05 -08:00
Zhihe Li 9c10d79661 Icu 14777 add more target tests (#2594)
* refactor: 💡 Move global setup to root
* refactor: 💡 Move env variable test fixture to global setup file
* test: 💍 Add more DC e2e tests for targets
* docs: ✏️ Updated e2e README

✅ Closes: https://hashicorp.atlassian.net/browse/ICU-14777
2024-12-03 18:51:22 -05:00
Carlos Alcaide Corvo 018d879a0a fix: 🐛 Fix addons/auth yarn warning (#2604)
Fix unmet peer dep within addons/auth
2024-12-03 13:35:01 -08:00
Carlos Alcaide Corvo b64f1876dc Refactor icu 15872 await authenticatesession admin (#2603)
* Add await for all authenticateSession within /tests/acceptance

* Add await for all authenticateSession within /tests/unit
2024-12-03 10:27:27 -08:00
Carlos Alcaide Corvo 055607b3dd refactor: 💡 Clean up release triggers (#2602) 2024-12-03 07:44:32 -08:00
Carlos Alcaide Corvo 8a7fa26cb5 refactor: 💡 Delete build desktop win docker (#2601) 2024-12-02 15:47:09 -08:00
Carlos Alcaide Corvo 9cac16fe6a refactor: 💡 Add await to authenticateSession within desktop (#2600) 2024-12-02 15:30:28 -08:00
Carlos Alcaide Corvo 61297dba02 refactor: 💡 Add await to invalidSession within admin (#2599) 2024-12-02 15:05:26 -08:00
Lisbet Alvarez 2f8a53e3ea refactor: 💡 remove rose table references (#2589)
✅ Closes: https://hashicorp.atlassian.net/browse/ICU-15644
2024-12-02 12:22:01 -08:00
Carlos Alcaide Corvo 96b9a20844 refactor: 💡 Add await to invalidSession within desktop (#2598) 2024-12-02 11:51:12 -08:00
Carlos Alcaide Corvo 443f230251 refactor: 💡 Migrate ember-uuid to uuid (#2597)
* refactor: 💡 Migrate ember-uuid to uuid
2024-12-02 11:36:25 -08:00
86ee79e6bf Result of tsccr-helper -log-level=info gha update -latest .github/ (#2608)
Co-authored-by: hashicorp-tsccr[bot] <hashicorp-tsccr[bot]@users.noreply.github.com>
Co-authored-by: Carlos Alcaide Corvo <ccorvo@hashicorp.com>
2024-12-02 11:22:03 -08:00
Cameron Perera b24e5a2c22 fix: 🐛 default to light theme for acceptance tests (#2587)
* fix: 🐛 default to light theme for acceptance tests

* refactor: 💡 add async/await to authenticateSession
2024-12-02 12:51:24 -06:00
Carlos Alcaide Corvo 8c6b1aa69a Clean up auto-generated TODO comments (#2607) 2024-12-02 09:02:44 -08:00
Dharini Jeeva 36c2aee271 fix vault brokered credentials display (#2583)
* fix: 🐛 brokered credential display in credential panel
2024-11-26 14:34:10 -08:00
Carlos Alcaide Corvo b049635d28 chore: 🤖 Upgrade uuid (#2591)
Upgrade uuid
2024-11-26 09:23:41 -08:00
Carlos Alcaide Corvo 42dd029611 refactor: 💡 Remove rose:linkbutton (#2590)
Remove rose:linkbutton references and tests
2024-11-26 08:58:09 -08:00
Carlos Alcaide Corvo e02c50aef8 chore: 🤖 Upgrade sinon (#2585)
Upgrade sinon to v19
2024-11-26 08:41:23 -08:00
Carlos Alcaide Corvo d9cf112694 chore: 🤖 Upgrade lint-staged to v15 (#2586)
Upgrade lint-staged to v15
2024-11-22 15:17:07 -08:00
Carlos Alcaide Corvo a4456f50cd refactor: 💡 Delete not necessary comments (#2588) 2024-11-22 11:27:53 -08:00
Carlos Alcaide Corvo a358061f22 chore: 🤖 Delete ember-cli-app-version (#2584)
Delete ember-cli-app-version
2024-11-22 09:09:56 -08:00
Carlos Alcaide Corvo f155e8ad44 Migrate embe-autofocus-modifier to HTML autofocus standard (#2581) 2024-11-22 08:48:53 -08:00
Lisbet Alvarez c930bb235b style: 💄 fix z-index for rose-dialog modal (#2579) 2024-11-20 12:23:52 -08:00
Lisbet Alvarez 543cf4697f refactor: 💡 remove rose::notification in favor of hds (#2557)
* refactor: 💡 remove rose::notification in favor of hds

✅ Closes: https://hashicorp.atlassian.net/browse/ICU-15634
2024-11-19 15:18:18 -08:00
Carlos Alcaide Corvo 66e9e971a1 Upgrade ember-simple-auth to latest (#2573)
Upgrade ember-simple-auth to latest

* Change ember-auto-import from devDependencies to dependencies
2024-11-19 13:47:36 -08:00
Cameron Perera a961b5e4be chore: 🤖 bump fast-sourcemap-concat version (#2575) 2024-11-19 15:28:20 -06:00
Dharini Jeeva f8796b362e chore: 🤖 remove ember radio btn, update it with hds (#2556)
* chore: 🤖 remove ember radio btn, update it with hds
2024-11-19 13:03:29 -08:00
Dharini Jeeva 415f638028 Icu 15713 address deprecation warning for dropdown interactive element (#2561) 2024-11-19 11:32:06 -08:00
Carlos Alcaide Corvo 4523615829 chore: 🤖 Upgrade ember-cookies (#2572)
* chore: 🤖 Upgrade ember-cookies
2024-11-18 12:28:18 -08:00
Carlos Alcaide Corvo 61214af01a chore: 🤖 Upgrade and Migrate husky from v8 to v9 (#2571)
Upgrade and migrate Husky from v8 to v9.1.6
2024-11-18 11:51:30 -08:00
Zhihe Li 2f0bf5dc17 fix: 🐛 Fix unintentional changes to yarn lock (#2570) 2024-11-14 17:18:46 -05:00
Zhihe Li 6e71712092 refactor: 💡 Fix linting errors in e2e (#2563) 2024-11-14 16:44:11 -05:00
Zhihe Li 7e56e1cccf style: 💄 Run prettier on e2e tests (#2560) 2024-11-12 18:11:00 -05:00
Cameron Perera 1e3f533d83 refactor: 💡 move WorkerFilter component to more generic folder (#2558)
✅ Closes: https://hashicorp.atlassian.net/browse/ICU-15742
2024-11-12 14:10:06 -06:00
Lisbet Alvarez 57568f9a8c test: 💍 add missing controller unit tests in admin-ui (#2553)
* test: 💍 add missing controller unit tests in admin-ui

✅ Closes: https://hashicorp.atlassian.net/browse/ICU-14740
2024-11-12 09:27:07 -08:00
Zhihe Li 7c1814118d refactor: 💡 Move e2e tests to new folder (#2546)
* refactor: 💡 Move e2e tests to new folder

* refactor: 💡 Convert desktop tests to mjs and use es6 imports

* refactor: 💡 Use module setting for e2e directory and remove mjs

* refactor: 💡 Remove "e2e" in all scripts in package.json
2024-11-12 11:21:37 -05:00
Michael Li ca50a963fd test(e2e): Add extra timeout for "delete resources" test (#2524) 2024-11-11 09:10:13 -05:00
Cameron Perera 6e188c6996 Icu 15465 credential library create test (#2555)
* test: 💍 use commonSelectors in cred-lib tests

✅ Closes: https://hashicorp.atlassian.net/browse/ICU-15465

* test: 💍 create selectors for cred-lib acceptance tests

✅ Closes: https://hashicorp.atlassian.net/browse/ICU-15465

* test: 💍 finish selector refactor for cred-lib create

✅ Closes: https://hashicorp.atlassian.net/browse/ICU-15465
2024-11-08 15:12:43 -06:00
Carlos Alcaide Corvo 0095c5c666 chore: 🤖 Upgrade qunit-dom (#2552)
* chore: 🤖 Upgrade qunit-dom and qunit
2024-11-08 09:09:22 -08:00
Carlos Alcaide Corvo bdd7f303c4 test: 💍 Update test selectors for read hosts (#2549)
* test: 💍 Update test selectors for read hosts
2024-11-07 13:54:27 -08:00
Lisbet Alvarez f0383522d8 chore: 🤖 audit remaining resolutions (#2550) 2024-11-07 13:30:21 -08:00
Dharini Jeeva a32cc13171 Icu 15481 groups read and list test (#2551)
* refactor: 💡 test selectors in read and list groups
2024-11-06 15:13:17 -08:00
Dharini Jeeva dbda8c5674 Icu 15480 groups create test (#2544) 2024-11-06 10:59:16 -08:00
Carlos Alcaide Corvo 186873d9d4 Remove build debian in Mac OS and all its dependencies (#2543) 2024-11-06 10:19:49 -08:00
Carlos Alcaide Corvo 37482c0b36 chore: 🤖 Upgrade Concurrently (#2547)
Upgrade Concurrently from 8.2.0 to 9.1.0

✅ Closes: ICU-15651
2024-11-06 09:27:11 -08:00
hashicorp-tsccr[bot]andhashicorp-tsccr[bot] ccdc5a03ac Result of tsccr-helper -log-level=info gha update -latest .github/ (#2548)
Co-authored-by: hashicorp-tsccr[bot] <hashicorp-tsccr[bot]@users.noreply.github.com>
2024-11-04 10:54:51 -08:00
Carlos Alcaide Corvo 2ae24c4627 Change boundary-ui-releases to boundary-desktop-releases (#2535) 2024-11-04 10:16:09 -08:00
Carlos Alcaide Corvo b9e9fd21ee Chore icu 15637 upgrade ember test helpers (#2545)
* Upgrade ember-test helpers

* Upgrade ember-int and ember-cli-clipboard, as ember-test-helpers introduces a breaking change
2024-11-04 09:57:07 -08:00
Zack Moore 6eb83b2a25 Upgrade HDS dependency to 4.13 & migrate FlightIcon to Hds::Icon (#2540)
* updated hds and replaced deprecated flight-icon

* removed code trying to import from ember-flight-icons

* fixing linting issue

* fixing linting issue

* fixing dropdown test selectors

* updated dropdown selectors

* updated dropdown selectors

* updated dropdown selectors

* addressing pr feedback

* fixing linting error

* updating dropdown selectors
2024-11-04 11:29:56 -06:00
Carlos Alcaide Corvo 70aceb1699 Update test selectors for create hosts (#2542)
* Use of common and domain specific selectors for create host test.
2024-11-04 08:43:41 -08:00
Dharini Jeeva 5e208c4115 Enable storage bucket deletion (#2541)
* fix: 🐛 enable storage bucket deletion
2024-10-31 09:36:19 -07:00
Lisbet Alvarez 390f051e43 chore: 🤖 audit most recent resolutions (#2531)
* chore: 🤖 audit most recent resolutions
2024-10-28 16:28:26 -07:00
Cameron Perera ab0f1fd549 test: 💍 update test selectors for accounts update (#2539)
✅ Closes: https://hashicorp.atlassian.net/browse/ICU-14042
2024-10-28 14:27:55 -05:00
Zhihe Li 788df7b16d test: 💍 Add some settings page tests (#2538) 2024-10-28 15:10:54 -04:00
Lisbet Alvarez 01a2d8e9a6 refactor: 💡 remove route-action usage in admin ui (#2534)
✅ Closes: https://hashicorp.atlassian.net/browse/ICU-12945
2024-10-28 09:23:08 -07:00
Cameron Perera e842eb001d Icu 14039 accounts list, read, and set-password test (#2537)
* test: 💍 update test selectors for accounts list

✅ Closes: https://hashicorp.atlassian.net/browse/ICU-14039

* test: 💍 update test selectors for accounts read

✅ Closes: https://hashicorp.atlassian.net/browse/ICU-14039

* test: 💍 update test selectors for accounts set password

✅ Closes: https://hashicorp.atlassian.net/browse/ICU-14039
2024-10-25 15:58:09 -05:00
Cameron Perera f195e5dc9d Icu 15405 remove patch and resolutions due to ember cli upgrade (#2536)
* chore: 🤖 remove lodash.template patch

✅ Closes: https://hashicorp.atlassian.net/browse/ICU-15405

* chore: 🤖 remove markdown-it resolution

✅ Closes: https://hashicorp.atlassian.net/browse/ICU-15405

* chore: 🤖 async dependency clean up

✅ Closes: https://hashicorp.atlassian.net/browse/ICU-15405

* chore: 🤖 remove clean-css resolution

✅ Closes: https://hashicorp.atlassian.net/browse/ICU-15405

* chore: 🤖 remove winston/async resolution

✅ Closes: https://hashicorp.atlassian.net/browse/ICU-15405
2024-10-24 06:57:49 -05:00
Cameron Perera 7f7f0f1859 test: 💍 update test selectors for accounts delete (#2532)
✅ Closes: https://hashicorp.atlassian.net/browse/ICU-14038
2024-10-23 11:33:55 -05:00
Cameron Perera b494a703eb chore: 🤖 upgrade ember-cli version (#2533)
✅ Closes: https://hashicorp.atlassian.net/browse/ICU-15393
2024-10-23 09:40:45 -05:00
Lisbet Alvarez 0f52b86364 refactor: 💡 remove route-action usage for targets and sessions (#2528)
* refactor: 💡 remove route-action usage for targets and sessions

✅ Closes: https://hashicorp.atlassian.net/browse/ICU-15040
2024-10-22 13:16:58 -07:00
Cameron Perera 1b31188d5e test: 💍 selectors refactor for accounts create (#2527)
* test: 💍 selectors refactor for accounts create

✅ Closes: https://hashicorp.atlassian.net/browse/ICU-14037

* refactor: 💡 remove name & description duplicate selectors

✅ Closes: https://hashicorp.atlassian.net/browse/ICU-14037
2024-10-21 17:12:00 -05:00
Lisbet Alvarez 30e7268297 chore: 🤖 resolve socks to new version to fix ip vulnerability (#2529)
✅ Closes: https://hashicorp.atlassian.net/browse/ICU-14207
2024-10-21 10:22:32 -07:00
Dharini Jeeva 6956b30fd6 Update credentials (#2523)
* feat: 🎸 allow AWS host catalog credential type update
2024-10-18 14:33:14 -07:00
Cameron Perera 98d19ef591 test: 💍 add new selectors for accounts acceptance tests (#2525)
✅ Closes: https://hashicorp.atlassian.net/browse/ICU-14036
2024-10-18 09:56:31 -05:00
Carlos Alcaide Corvo f0ffcea424 chore: 🤖 Clean up Desktop out directory (#2521)
* chore: 🤖 Clean up Desktop out directory
2024-10-18 09:27:40 +02:00
Michael Li 6454fb7061 test(e2e): Add check for worker filters (#2513)
* test(e2e): Add check to add an ingress worker filter

* test(e2e): Add check for editing a worker filter
2024-10-17 12:51:49 -04:00
Lisbet Alvarez c0d7af7899 fix: 🐛 alias disappearing on target details page (#2519)
* fix: 🐛 alias disappearing on target details page

✅ Closes: https://hashicorp.atlassian.net/browse/ICU-15296

* test: 💍 fix test

✅ Closes: https://hashicorp.atlassian.net/browse/ICU-15296
2024-10-15 12:58:43 -07:00
Cameron Perera 2424395415 fix: 🐛 add bottom border back to ListWrapper component (#2522) 2024-10-15 13:54:14 -05:00
Zhihe Li dde2f259e8 chore: 🤖 Update changelog (#2516) 2024-10-11 11:58:16 -04:00
Zhihe Li e38c28c288 fix: 🐛 Push associated targets in sessions to ember store (#2518) 2024-10-10 17:03:27 -04:00
Dharini Jeeva 0ff91f9182 fix: 🐛 minor UI changes, ent flag for worker filter (#2517) 2024-10-10 12:44:12 -07:00
Lisbet Alvarez 857bf01596 style: 💄 issues with spacing in manage scopes pages for a role (#2515)
* style: 💄 issues with spacing in manage scopes pages for a role

✅ Closes: https://hashicorp.atlassian.net/browse/ICU-15287
2024-10-09 15:17:42 -07:00
Dharini Jeeva 965e82473d Types for aws host catalogs (#2514)
assume role dynamic AWS credentials
2024-10-09 14:49:22 -07:00
Dharini Jeeva 0d55812f64 Add worker type dynamic host catalog (#2511)
* fix: 🐛 add worker filter support for aws host catalogs
2024-10-08 10:58:52 -07:00
Lisbet Alvarez e807e1a3af fix: 🐛 cannot retry oidc authentication in desktop & admin (#2512)
* fix: 🐛 cannot retry oidc authentication in desktop & admin

✅ Closes: https://hashicorp.atlassian.net/browse/ICU-15250
2024-10-08 10:29:21 -07:00
Lisbet Alvarez 64e568bd72 fix: 🐛 deleting session recording causes error (#2510)
* fix: 🐛 deleting session recording causes error

✅ Closes: https://hashicorp.atlassian.net/browse/ICU-15236

* fix: 🐛 remove scope filter & remove unused translation

✅ Closes: https://hashicorp.atlassian.net/browse/ICU-15236
2024-10-04 08:14:30 -07:00
Carlos Alcaide CorvoandDharini Jeeva 401ff354e8 Llb ts desktop no cli (#2491)
Changes to allow Desktop client build with no CLI
---------
Co-authored-by: Dharini Jeeva <dharini@hashicorp.com>
2024-10-04 16:35:18 +02:00
Michael Li 9c31154941 test(e2e): Updates from 0.18.0 testing (#2509)
* test(e2e): Update locators that can't be found

* test(e2e): Fix race condition

It seems like the alias tests were failing as it was unable to open the Manage menu here. One theory is that we need to make sure the alias page has fully loaded before it tries to click the Manage button (the test might be finding the Manage button from the previous screen and clicking that)

* CR: Fix Alias header check
2024-10-04 08:39:20 -04:00
Lisbet Alvarez 1947365c91 chore: 🤖 resolve rollup vulnerability by removing ember-fetch (#2505)
✅ Closes: https://hashicorp.atlassian.net/browse/ICU-15189
2024-10-02 16:11:22 -07:00
Michael Li be528dae47 test(e2e): Add test for worker tags (#2507) 2024-10-02 14:04:38 -04:00
Cameron Perera d3c789c66c Icu 15181 add pagination to session recordings (#2502)
* refactor: 💡 move model hook to session-recordings/index route

✅ Closes: https://hashicorp.atlassian.net/browse/ICU-15130

* test: 💍 add missing tests for session recordings controller

✅ Closes: https://hashicorp.atlassian.net/browse/ICU-15130

* feat: 🎸 paginate session-recordings and search

✅ Closes: https://hashicorp.atlassian.net/browse/ICU-15130

* refactor: 💡 fix failing redirect and tests

✅ Closes: https://hashicorp.atlassian.net/browse/ICU-15130

* test: 💍 add search tests for session recordings

✅ Closes: https://hashicorp.atlassian.net/browse/ICU-15130

* feat: 🎸 add user filtering for session recordings

✅ Closes: https://hashicorp.atlassian.net/browse/ICU-15130

* feat: 🎸 add more attributes to indexed-db session recordings

✅ Closes: https://hashicorp.atlassian.net/browse/ICU-15130

* feat: 🎸 add target filter for session recordings

✅ Closes: https://hashicorp.atlassian.net/browse/ICU-15130

* refactor: 💡 update filterOptions method

✅ Closes: https://hashicorp.atlassian.net/browse/ICU-15130

* feat: 🎸 add scopes filtering to session recording

✅ Closes: https://hashicorp.atlassian.net/browse/ICU-15181

* feat: 🎸 add time filter to session recordings

✅ Closes: https://hashicorp.atlassian.net/browse/ICU-15181

* refactor: 💡 add no filter results text

✅ Closes: https://hashicorp.atlassian.net/browse/ICU-15181

* refactor: 💡 update Exist variables to doExist

✅ Closes: https://hashicorp.atlassian.net/browse/ICU-15181

* refactor: 💡 updates from PR feedback

✅ Closes: https://hashicorp.atlassian.net/browse/ICU-15181

* refactor: 💡 remove scope_id filter

✅ Closes: https://hashicorp.atlassian.net/browse/ICU-15181

* refactor: 💡 change session recording placeholder text

✅ Closes: https://hashicorp.atlassian.net/browse/ICU-15181

* chore: 🤖 increment indexedDB version

✅ Closes: https://hashicorp.atlassian.net/browse/ICU-15181

* test: 💍 add Date object tests for indexed-db

✅ Closes: https://hashicorp.atlassian.net/browse/ICU-15181

* refactor: 💡 small changes from PR feedback

✅ Closes: https://hashicorp.atlassian.net/browse/ICU-15181

* refactor: 💡 change times filter array to time date object

✅ Closes: https://hashicorp.atlassian.net/browse/ICU-15181

* test: 💍 add more date specific indexed-db test

✅ Closes: https://hashicorp.atlassian.net/browse/ICU-15181

* refactor: 💡 change Today time shortcut to "Last 24 hours"

✅ Closes: https://hashicorp.atlassian.net/browse/ICU-15181

* test: 💍 fix date mock in session-recording controller tests

✅ Closes: https://hashicorp.atlassian.net/browse/ICU-15181
2024-10-01 13:55:15 -05:00
Michael Li 15727f61fd test(e2e): Add Admin UI test for vault credential libraries (enterprise) (#2501) 2024-10-01 12:11:14 -04:00
hashicorp-tsccr[bot]andhashicorp-tsccr[bot] 486d8b116a Result of tsccr-helper -log-level=info gha update -latest . (#2506)
Co-authored-by: hashicorp-tsccr[bot] <hashicorp-tsccr[bot]@users.noreply.github.com>
2024-10-01 14:32:36 +02:00
91ffbfb315 icu-14735 add search & pagination to aliases (#2498)
* refactor: 💡 add search & pagination to aliases

✅ Closes: https://hashicorp.atlassian.net/browse/ICU-14735
---------

Co-authored-by: Dharini Jeeva <dharini@hashicorp.com>
Co-authored-by: Cameron Perera <cameron.perera@hashicorp.com>
2024-09-30 13:07:13 -07:00
Dharini Jeeva 9b33812f9e fix: 🐛 bucket types icon in target association (#2503)
* fix: 🐛 bucket types icon in target association
2024-09-27 12:23:16 -07:00
Zhihe Li b40c53fb45 feat: 🎸 Update alert designs (#2496) 2024-09-24 14:30:52 -04:00
Zhihe Li 97258f7525 Use updated cache daemon (#2475)
* feat: 🎸 Handle truncated cache daemon response
2024-09-24 14:30:52 -04:00
Zhihe Li ace65eab3a fix: 🐛 Fix theme selector not properly selecting option (#2495) 2024-09-24 11:58:26 -04:00
Zhihe Li 20e6df522a feat: 🎸 Hide daemon errors initially (#2477)
* feat: 🎸 Hide daemon errors initially

✅ Closes: https://hashicorp.atlassian.net/browse/ICU-14961

* feat: 🎸 Move the user and server cards up in settings

✅ Closes: https://hashicorp.atlassian.net/browse/ICU-14962
2024-09-24 11:58:26 -04:00
Dharini Jeeva c8abc3845a fix: 🐛 pass current usl to maintain session (#2472)
✅ Closes: https://hashicorp.atlassian.net/browse/ICU-14963
2024-09-24 11:58:26 -04:00
Zhihe Li 6cd2f0f7d8 fix: 🐛 Fix windows hanging when client agent isn't running (#2459) 2024-09-24 11:58:25 -04:00
Zhihe Li 1266930647 chore: 🤖 Remove client agent feature flag (#2449) 2024-09-24 11:58:25 -04:00
Dharini Jeeva 695d9d413d fix: 🐛 remove connected lable (#2446) 2024-09-24 11:58:25 -04:00
Zhihe Li edaf19f59b feat: 🎸 Add section for client agent in settings (#2442)
* feat: 🎸 Add section for client agent in settings

✅ Closes: https://hashicorp.atlassian.net/browse/ICU-14780
2024-09-24 11:58:25 -04:00
Dharini Jeeva de5defeab2 Icu 14781 add a section for server information (#2438) 2024-09-24 11:58:25 -04:00
Zhihe Li 63ec418cf0 feat: 🎸 Show cache daemon errors from status (#2437)
✅ Closes: https://hashicorp.atlassian.net/browse/ICU-14816
2024-09-24 11:58:25 -04:00
Zhihe Li e4f4394197 Icu 14403 add dropdown to select and save log verbosity (#2431)
* feat: 🎸 Add logging settings card

✅ Closes: https://hashicorp.atlassian.net/browse/ICU-14403
2024-09-24 11:58:25 -04:00
Dharini Jeeva 0b9357e9b3 chore: 🤖 add user info (#2425)
* chore: 🤖 add user info
2024-09-24 11:58:25 -04:00
Dharini Jeeva 777380e19f Add theme selection (#2428)
* fix: 🐛 remove theme from main menu bar and move to settings pag

* chore: 🤖 move toggletheme to app controller
2024-09-24 11:58:24 -04:00
Dharini Jeeva 25b3a940a3 Icu 14400 add a section for version info cli and dc (#2409)
* chore: 🤖 cli info
2024-09-24 11:58:24 -04:00
Dharini Jeeva a97f66e011 feat: 🎸 settings page (#2395)
* feat: 🎸 settings page
2024-09-24 11:58:24 -04:00
Cameron Perera fac7d2b128 small update to desktop README (#2497) 2024-09-23 16:05:10 -05:00
Dharini Jeeva ad1bb34453 fix: show username first and then password when credentials are listed (#2494) 2024-09-19 14:22:25 -07:00
Lisbet Alvarez 8605a54221 refactor: 💡 remove route-action usage for scopes in desktop (#2447)
* refactor: 💡 remove route-action usage for scopes in desktop

✅ Closes: https://hashicorp.atlassian.net/browse/ICU-12621
2024-09-17 16:36:47 -07:00
Lisbet Alvarez 98cd9dc1ec chore: 🤖 add resolution for send (#2490) 2024-09-16 12:27:13 -07:00
Cameron Perera bd857836ee Icu 14208 vulnerabilities in boundary UI enterprise lodash template 4 5 0 in yarn lock (#2485)
* fix: 🐛 add patch for lodash.template

✅ Closes: https://hashicorp.atlassian.net/browse/ICU-14208

* chore: 🤖 add patch-package and postinstall-postinstall

✅ Closes: https://hashicorp.atlassian.net/browse/ICU-14208

* fix: 🐛 add patch for lodash.template

✅ Closes: https://hashicorp.atlassian.net/browse/ICU-14208

* chore: 🤖 add patch-package and postinstall-postinstall

✅ Closes: https://hashicorp.atlassian.net/browse/ICU-14208
2024-09-16 09:27:40 -05:00
Carlos Alcaide Corvo 4974273bd0 chore: 🤖 Upgrade git-cz (#2488)
Upgrade git-cz from 4.8.0 to 4.9.0. As per git-cz changelog, there are
no breaking changes
2024-09-13 16:14:21 -07:00
Lisbet Alvarez c4e58fb780 refactor: 💡 change channel app state title & add alert msg (#2489)
* refactor: 💡 change channel app state title & add alert msg

✅ Closes: https://hashicorp.atlassian.net/browse/ICU-11148
2024-09-13 13:24:45 -07:00
dependabot[bot]andCameron Perera 2515efead6 chore(deps-dev): bump webpack from 5.88.2 to 5.94.0 (#2466)
Bumps [webpack](https://github.com/webpack/webpack) from 5.88.2 to 5.94.0.
- [Release notes](https://github.com/webpack/webpack/releases)
- [Commits](https://github.com/webpack/webpack/compare/v5.88.2...v5.94.0)

---
updated-dependencies:
- dependency-name: webpack
  dependency-type: direct:development
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Cameron Perera <cameron.perera@hashicorp.com>
2024-09-13 14:12:58 -05:00
Cameron Perera fda3ca9d4b fix: 🐛 add regex literal for isLocalHost check (#2484)
* fix: 🐛 add ':' to isLocalHost check

✅ Closes: https://hashicorp.atlassian.net/browse/ICU-13242

* refactor: 💡 use regex to verify href is localhost

✅ Closes: https://hashicorp.atlassian.net/browse/ICU-13242
2024-09-13 13:03:40 -05:00
Cameron Pereraandcameronperera 9648e1fa3b Add duration unit format (#2483)
* chore: 🤖 add @formatjs/intl-durationformat to addons/core

* refactor: 💡 replace old duration format with new package

* chore: 🤖 remove intl-unofficial-duration-unit-format

* Add missing copyright headers

* test: 💍 add more test cases

---------

Co-authored-by: cameronperera <cameronperera@users.noreply.github.com>
2024-09-13 09:43:08 -05:00
Lisbet Alvarez e395b1196c Chore resolve path to regexp vulnerability (#2482)
* chore: 🤖 resolve path-toregexp vulnerability

* chore: 🤖 resolve body-parser vulnerability
2024-09-11 14:20:47 -07:00
Lisbet Alvarez b7e6492d26 chore: 🤖 add resolution for micromatch (#2481) 2024-09-10 09:28:47 -07:00
Zhihe Li 6311d7587e fix: 🐛 Fix daemon getting killed if started before DC (#2480) 2024-09-09 14:55:38 -04:00
Cameron Perera 07573d6b2c Fix/json5 security issue (#2479)
* chore: 🤖 delete and re-install find-babel-config from yarn.lock

* chore: 🤖 remove json5 resolution
2024-09-06 14:45:38 -05:00
Lisbet Alvarez 90890441e1 chore: 🤖 upgrade braces to 3.0.3 to fix security vulnerability (#2476)
✅ Closes: https://hashicorp.atlassian.net/browse/ICU-14205
2024-09-06 10:32:30 -07:00
Cameron Perera 1430adce7e refactor: 💡 update test selectors for storage-buckets list (#2463)
* refactor: 💡 update test selectors for storage-buckets list

✅ Closes: https://hashicorp.atlassian.net/browse/ICU-14034

* refactor: 💡 update sidebar nav link test selector

✅ Closes: https://hashicorp.atlassian.net/browse/ICU-14034
2024-09-06 09:56:24 -05:00
Cameron Perera 89afee7297 chore: 🤖 upgrade semver versions (#2473)
✅ Closes: https://hashicorp.atlassian.net/browse/ICU-14213
2024-09-06 09:33:57 -05:00
Zhihe Li 78f89da348 style: 💄 Fix text description (#2478) 2024-09-05 17:53:19 -04:00
Cameron Perera 9bacb55e87 chore: 🤖 update TODO to with ICU ticket (#2474)
* chore: 🤖 update TODO to with ICU ticket

* chore: 🤖 add message back to todo
2024-09-05 10:21:17 -05:00
Cameron Perera dea4a62955 test: 💍 add TODO for a11y violations (#2471) 2024-09-04 15:44:42 -05:00
Lisbet Alvarez ef163709f2 Upgrade ember a11y testing to v7 (#2470)
* chore: 🤖 update ember-a11y-testing and @ember/test-helpers

* chore: 🤖 upgrade to v7

* chore: 🤖 upgrade deps and force resolutions to fix errors

* chore: 🤖 fix ember-a11y errors due to summary title not showing

* chore: 🤖 fix yarn.lock
2024-09-04 13:04:14 -07:00
hashicorp-tsccr[bot]andhashicorp-tsccr[bot] 0cfa814cdd Result of tsccr-helper -log-level=info gha update -latest . (#2469)
Co-authored-by: hashicorp-tsccr[bot] <hashicorp-tsccr[bot]@users.noreply.github.com>
2024-09-04 11:41:24 -07:00
Lisbet Alvarez 694c43296a chore: 🤖 remove request unused dependency resolution (#2467)
✅ Closes: https://hashicorp.atlassian.net/browse/ICU-14214
2024-08-29 12:17:27 -07:00
Lisbet Alvarez c98bfb5622 chore: 🤖 upgrade jsonpointer to v5 (#2465)
✅ Closes: https://hashicorp.atlassian.net/browse/ICU-14212
2024-08-28 09:33:47 -07:00
Michael Li 7cebece600 refact(e2e): Use fixtures for environment variables (#2452) 2024-08-28 11:54:58 -04:00
WadiandCameron Perera a9cfc43404 Icu 14663 update manage dropdown for credential stores form (#2454)
* refactor: 💡 Update Manage dropdown in credential-store

✅ Closes: https://hashicorp.atlassian.net/browse/ICU-14663

* refactor: 💡 Adjusted tests

✅ Closes: https://hashicorp.atlassian.net/browse/ICU-14663

* refactor: 💡 Refactored tests and naming conventions

✅ Closes: https://hashicorp.atlassian.net/browse/ICU-14663

* refactor: 💡 Removed @model from delete

✅ Closes: https://hashicorp.atlassian.net/browse/ICU-14663

* test: 💍 add clicks to correct tests assertions

✅ Closes: https://hashicorp.atlassian.net/browse/ICU-14663

---------

Co-authored-by: Cameron Perera <cameron.perera@hashicorp.com>
2024-08-26 14:58:14 -05:00
WadiandCameron Perera c38ba294cc refactor: 💡 Update Manage Dropdown in auth-methods (#2460)
* refactor: 💡 Update Manage Dropdown in auth-methods

✅ Closes: https://hashicorp.atlassian.net/browse/ICU-14704

* refactor: 💡 Refactored tests

✅ Closes: https://hashicorp.atlassian.net/browse/ICU-14704

---------

Co-authored-by: Cameron Perera <cameron.perera@hashicorp.com>
2024-08-26 14:30:57 -05:00
Cameron Perera ce2649272f chore: 🤖 upgrade ember-qunit to v8.1.0 (#2462)
and ember-cli to 4.12.2 in addons/api
2024-08-26 14:13:45 -05:00
WadiandCameron Perera 3d60d047e3 refactor: 💡 Manage dropdown HDS refactoring for managed-groups (#2455)
* refactor: 💡 Manage dropdown HDS refactoring for managed-groups

Updated the manage dropdown to reflect HDS design

✅ Closes: https://hashicorp.atlassian.net/browse/ICU-14603

* refactor: 💡 Changed up naming convention for Manage dropdown

✅ Closes: https://hashicorp.atlassian.net/browse/ICU-14603

---------

Co-authored-by: Cameron Perera <cameron.perera@hashicorp.com>
2024-08-26 10:48:36 -05:00
WadiandCameron Perera a3082e97e6 refactor: 💡 Update manage dropdown for host-catalogs (#2456)
* refactor: 💡 Update manage dropdown for host-catalogs

✅ Closes: https://hashicorp.atlassian.net/browse/ICU-14664

* refactor: 💡 Refactored tests

✅ Closes: https://hashicorp.atlassian.net/browse/ICU-14664

* refactor: 💡 Refactored test

✅ Closes: https://hashicorp.atlassian.net/browse/ICU-14664

---------

Co-authored-by: Cameron Perera <cameron.perera@hashicorp.com>
2024-08-26 09:44:51 -05:00
dependabot[bot]andZhihe Li 333eebd731 chore(deps): bump micromatch in /ui/desktop/electron-app (#2461)
Bumps [micromatch](https://github.com/micromatch/micromatch) from 4.0.5 to 4.0.8.
- [Release notes](https://github.com/micromatch/micromatch/releases)
- [Changelog](https://github.com/micromatch/micromatch/blob/4.0.8/CHANGELOG.md)
- [Commits](https://github.com/micromatch/micromatch/compare/4.0.5...4.0.8)

---
updated-dependencies:
- dependency-name: micromatch
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Zhihe Li <zhihe.li@hashicorp.com>
2024-08-23 16:36:41 -04:00
Lisbet Alvarez 320af9f6f7 chore: 🤖 upgrade to ws v8.17.1 to remove vulnerability (#2451)
✅ Closes: https://hashicorp.atlassian.net/browse/ICU-14204
2024-08-23 13:25:10 -07:00
Cameron Perera af9b832d38 chore: 🤖 update ember-cli-mirage (#2458)
* chore: 🤖 update ember-cli-mirage

* chore: 🤖 move ember-cli-mirage to dependencies

* chore: 🤖 remove duplicate dependency
2024-08-23 14:40:42 -05:00
Wadi bea791b2e6 refactor: 💡 Update Manage dropdown in Credentials form (#2453)
✅ Closes: https://hashicorp.atlassian.net/browse/ICU-14665
2024-08-23 12:03:26 -04:00
Wadi e31ac72531 ICU-14870 Update Manage Dropdown for Projects form (#2457)
* refactor: 💡 HDS Manage Dropdown for Projects

✅ Closes: https://hashicorp.atlassian.net/browse/ICU-14870

* refactor: 💡 Fixing up tests

✅ Closes: https://hashicorp.atlassian.net/browse/ICU-14870

* refactor: 💡 Updated naming convention and consolidated

✅ Closes: https://hashicorp.atlassian.net/browse/ICU-14870
2024-08-23 11:53:26 -04:00
Michael Li 075d8c6d8f refact(e2e): Create HTTP methods and more page objects (#2448)
* refact(e2e): Create LoginPage

* refact(e2e): Create http methods

* refact(e2e): Create more methods
2024-08-23 10:17:10 -04:00
Lauren 56f42c3f5a docs: ✏️ replace broken links, add hyperlinks, language updates (#2445)
This PR updates the repo READMEs by replacing a broken link and pointing to correct tutorials page, adding hyperlinks to improve readability, and small language updates
2024-08-20 16:14:19 -04:00
Carlos Alcaide Corvo af7196215b chore: 🤖 Migrate xterm to @xterm (#2444) 2024-08-20 09:40:08 -07:00
dependabot[bot]andDharini Jeeva 80d2898e56 chore(deps): bump elliptic from 6.5.4 to 6.5.7 (#2443)
Bumps [elliptic](https://github.com/indutny/elliptic) from 6.5.4 to 6.5.7.
- [Commits](https://github.com/indutny/elliptic/compare/v6.5.4...v6.5.7)

---
updated-dependencies:
- dependency-name: elliptic
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Dharini Jeeva <dharini@hashicorp.com>
2024-08-20 09:09:14 -05:00
Carlos Alcaide Corvo f607e77274 Automate copyright headers addition (#2440)
* Refactor checking headers to automatically add them
2024-08-19 14:22:27 -07:00
Michael Li 007f5d8b46 refact(e2e): Split up boundary-cli helper methods (#2430)
* refact(e2e): Split up boundary-cli helper methods

* CR: Use ESM import

* CR: Move authenticated state to a non-shared file

* CR: Use mjs

* CR: Modify playwright config to .mjs
2024-08-19 16:00:16 -04:00
Lisbet Alvarez a9d110a1b6 refactor: 💡 remove route-action usage for session recordings (#2439)
* refactor: 💡 remove route-action usage for session recordings

✅ Closes: https://hashicorp.atlassian.net/browse/ICU-12620
2024-08-16 10:04:46 -07:00
Lisbet AlvarezandCameron Perera 79b06ee565 ICU-13883 add remove org modal (#2435)
* feat: 🎸 add remove org modal

✅ Closes: https://hashicorp.atlassian.net/browse/ICU-13883

---------

Co-authored-by: Cameron Perera <cameron.perera@hashicorp.com>
2024-08-15 16:04:46 -07:00
Lisbet Alvarez 0af81d9bc1 refactor: 💡 remove route action usage for scopes (#2385)
* refactor: 💡 remove route action usage for scopes

✅ Closes: https://hashicorp.atlassian.net/browse/ICU-13755
2024-08-15 10:46:00 -07:00
Cameron Perera 9e668e8467 Icu 14834 remove duplicate selectors and use common selectors instead (#2436)
* refactor: 💡 update SAVE_BTN usage

✅ Closes: https://hashicorp.atlassian.net/browse/ICU-14834

* refactor: 💡 update CANCEL_BTN usage

✅ Closes: https://hashicorp.atlassian.net/browse/ICU-14834

* refactor: 💡 update EDIT_BTN usage

✅ Closes: https://hashicorp.atlassian.net/browse/ICU-14834

* refactor: 💡 update FIELD_NAME & FIELD_NAME_VALUE usage

✅ Closes: https://hashicorp.atlassian.net/browse/ICU-14834
2024-08-15 09:24:21 -05:00
Wadi 69da1fa04c refactor: 💡 Updated Manage Dropdown in auth-methods accounts (#2432)
* refactor: 💡 Updated Manage Dropdown in auth-methods accounts

Updated Manage Dropdown in auth-methods account form to HDS

✅ Closes: https://hashicorp.atlassian.net/browse/ICU-14599

* refactor: 💡 Changed asssert statement in delete-test.js

Changed statement to reflect proper syntax and testing capability

✅ Closes: https://hashicorp.atlassian.net/browse/ICU-14599
2024-08-12 13:52:56 -04:00
Wadi 392792eb92 refactor: 💡 Updated Manage Dropdown in credential-library (#2434)
Updated Manage Dropdown present in credential-library to reflect new HDS
design

✅ Closes: https://hashicorp.atlassian.net/browse/ICU-14601
2024-08-12 13:41:08 -04:00
Wadi 9c018f131f refactor: 💡 Updated Manage Dropdown in host-sets to HDS design (#2433)
* refactor: 💡 Updated Manage Dropdown in host-sets to HDS design

Updated the manage dropdown in host-sets to reflect HDS design

✅ Closes: https://hashicorp.atlassian.net/browse/ICU-14600

* refactor: 💡 Specified selector in host-test.js

✅ Closes: https://hashicorp.atlassian.net/browse/ICU-14600
2024-08-12 13:25:43 -04:00
Cameron Perera 0542218537 Icu 14033 storage buckets read test (#2414)
* test: 💍 update storage-bucket read test selectors

✅ Closes: https://hashicorp.atlassian.net/browse/ICU-14033

* test: 💍 add common selectors in tests/helpers

✅ Closes: https://hashicorp.atlassian.net/browse/ICU-14033

* refactor: 💡 update selector name and value

✅ Closes: https://hashicorp.atlassian.net/browse/ICU-14033

* refactor: 💡 update selector name

✅ Closes: https://hashicorp.atlassian.net/browse/ICU-14033
2024-08-12 10:41:27 -05:00
Lisbet Alvarez 7ac904a31f ICU-14496 add discard unsaved changes modal to manage scopes (#2421)
* refactor: 💡 add discard unsaved changes modal

✅ Closes: https://hashicorp.atlassian.net/browse/ICU-14496
2024-08-08 10:46:39 -07:00
Lisbet Alvarez a7d9a7e348 fix: 🐛 targets not displaying even after they are cached (#2429)
* fix: 🐛 targets not displaying even after they are cached

* fix: 🐛 modify check in sessions route
2024-08-07 10:38:38 -07:00
Michael Li 0d0dadf398 chore(e2e): Fix eslint for Admin UI e2e tests (#2427)
* chore(e2e): Fix eslint for e2e tests

* chore(e2e): Fix license headers
2024-08-06 14:26:19 -04:00
Michael Li 45c16252a7 refact(e2e): Update Admin UI tests to use Page Objects (#2426)
* refact(e2e): Use page object methods

* refact(e2e): Create base page class
2024-08-06 13:15:00 -04:00
Wadi 9b3cbaa6b3 refactor: 💡 Updated Manage Dropdown to HDS in Targets Menu (#2418)
* refactor: 💡 Updated Manage Dropdown to HDS in Targets Menu

Updated the manage dropdown present in the targets scope to reflect HDS
design

✅ Closes: https://hashicorp.atlassian.net/browse/ICU-14597

* refactor: 💡 Updated to reflect changes

Added changes to reflect variable design

✅ Closes: https://hashicorp.atlassian.net/browse/ICU-14597

* refactor: 💡 Removed @deleted attribute

✅ Closes: https://hashicorp.atlassian.net/browse/ICU-14597
2024-08-05 13:04:02 -04:00
Wadi 89cfb14d6e refactor: 💡 Updated Manage Dropdown for hosts form (#2423)
* refactor: 💡 Updated Manage Dropdown for hosts form

Continuing refactoring upgrades for HDS managed dropdowns

✅ Closes: https://hashicorp.atlassian.net/browse/ICU-14602

* refactor: 💡 Removed disabled attribute from dropdown

✅ Closes: https://hashicorp.atlassian.net/browse/ICU-14602
2024-08-05 12:53:55 -04:00
Zhihe Li a68d7d103a feat: 🎸 Setup initial desktop E2E tests (#2416)
* feat: 🎸 Setup initial desktop E2E tests

✅ Closes: https://hashicorp.atlassian.net/browse/ICU-14061
2024-08-02 13:28:50 -04:00
hashicorp-tsccr[bot]andhashicorp-tsccr[bot] 4dc5e13f24 Result of tsccr-helper -log-level=info gha update -latest . (#2422)
Co-authored-by: hashicorp-tsccr[bot] <hashicorp-tsccr[bot]@users.noreply.github.com>
2024-08-01 10:13:24 -07:00
860 changed files with 29128 additions and 20524 deletions

No files matched your search

+16 -16
View File
@@ -11,15 +11,15 @@ jobs:
name: Install dependencies
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7
- uses: actions/cache@0c45773b623bea8c8e75f6c82b208c3cf94ea4f9 # v4.0.2
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
- uses: actions/cache@1bd1e32a3bdc45362d1e726936510720a7c30a57 # v4.2.0
id: node-modules-cache
with:
path: "**/node_modules"
key: node-modules-${{ hashFiles('**/yarn.lock') }}
restore-keys: |
node-modules-
- uses: actions/setup-node@60edb5dd545a775178f52524783378180af0d1f8 # v4.0.2
- uses: actions/setup-node@39370e3970a6d050c480ffad4ff0ed4d3fdee5af # v4.1.0
with:
node-version: 20
- run: yarn install
@@ -28,8 +28,8 @@ jobs:
needs: [dependencies]
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7
- uses: actions/cache@0c45773b623bea8c8e75f6c82b208c3cf94ea4f9 # v4.0.2
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
- uses: actions/cache@1bd1e32a3bdc45362d1e726936510720a7c30a57 # v4.2.0
id: node-modules-cache
with:
path: "**/node_modules"
@@ -37,17 +37,17 @@ jobs:
restore-keys: |
node-modules-
- name: Build
uses: actions/setup-node@60edb5dd545a775178f52524783378180af0d1f8 # v4.0.2
uses: actions/setup-node@39370e3970a6d050c480ffad4ff0ed4d3fdee5af # v4.1.0
with:
node-version: 20
- run: yarn run build:ui:admin:oss
- name: Upload artifact admin-ui
uses: actions/upload-artifact@65462800fd760344b1a7b4382951275a0abb4808 # v4.3.3
uses: actions/upload-artifact@6f51ac03b9356f520e9adb1b1b7802705f340c2b # v4.5.0
with:
name: admin-ui
path: ./ui/admin/dist/
- name: Upload artifact OSS admin UI
uses: actions/upload-artifact@65462800fd760344b1a7b4382951275a0abb4808 # v4.3.3
uses: actions/upload-artifact@6f51ac03b9356f520e9adb1b1b7802705f340c2b # v4.5.0
with:
name: admin-ui-oss
path: ./ui/admin/dist/
@@ -56,8 +56,8 @@ jobs:
needs: [dependencies]
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7
- uses: actions/cache@0c45773b623bea8c8e75f6c82b208c3cf94ea4f9 # v4.0.2
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
- uses: actions/cache@1bd1e32a3bdc45362d1e726936510720a7c30a57 # v4.2.0
id: node-modules-cache
with:
path: "**/node_modules"
@@ -65,12 +65,12 @@ jobs:
restore-keys: |
node-modules-
- name: Build
uses: actions/setup-node@60edb5dd545a775178f52524783378180af0d1f8 # v4.0.2
uses: actions/setup-node@39370e3970a6d050c480ffad4ff0ed4d3fdee5af # v4.1.0
with:
node-version: 20
- run: yarn run build:ui:admin:enterprise
- name: Upload artifact enterprise admin UI
uses: actions/upload-artifact@65462800fd760344b1a7b4382951275a0abb4808 # v4.3.3
uses: actions/upload-artifact@6f51ac03b9356f520e9adb1b1b7802705f340c2b # v4.5.0
with:
name: admin-ui-ent
path: ./ui/admin/dist/
@@ -79,8 +79,8 @@ jobs:
needs: [dependencies]
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7
- uses: actions/cache@0c45773b623bea8c8e75f6c82b208c3cf94ea4f9 # v4.0.2
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
- uses: actions/cache@1bd1e32a3bdc45362d1e726936510720a7c30a57 # v4.2.0
id: node-modules-cache
with:
path: "**/node_modules"
@@ -88,12 +88,12 @@ jobs:
restore-keys: |
node-modules-
- name: Build
uses: actions/setup-node@60edb5dd545a775178f52524783378180af0d1f8 # v4.0.2
uses: actions/setup-node@39370e3970a6d050c480ffad4ff0ed4d3fdee5af # v4.1.0
with:
node-version: 20
- run: yarn run build:ui:admin:hcp
- name: Upload artifact HCP admin UI
uses: actions/upload-artifact@65462800fd760344b1a7b4382951275a0abb4808 # v4.3.3
uses: actions/upload-artifact@6f51ac03b9356f520e9adb1b1b7802705f340c2b # v4.5.0
with:
name: admin-ui-hcp
path: ./ui/admin/dist/
@@ -1,34 +0,0 @@
name: "Trigger Build Artifacts for Testing"
on:
workflow_dispatch:
inputs:
branch:
description: Please use tag-like format n.n.n-someword (1.111.11-beta)
required: true
product_version:
required: true
type: string
description: The version number belonging to the oss binary to be used
commit:
required: true
type: string
description: The git SHA of the oss artifacts to be used
jobs:
trigger-gha-build-artifacts-for-testing:
runs-on: ubuntu-latest
steps:
- name: Release description
if: github.event_name == 'workflow_dispatch'
run: |
echo "Triggering Build Artifacts for Testing using BRANCH and TEST_TAG ${{ github.event.inputs.branch }}"
- name: Trigger Build Artifacts for Testing in boundary-ui-releases
run: |
export GITHUB_TOKEN="${{ secrets.ELEVATED_GITHUB_TOKEN }}"
gh workflow run build-artifacts-for-testing.yml \
--repo hashicorp/boundary-ui-releases \
--ref main \
-f TAG="${{ inputs.branch }}" \
-f PRODUCT_VERSION="${{ inputs.product_version }}" \
-f COMMIT="${{ inputs.commit }}" \
+3 -3
View File
@@ -30,11 +30,11 @@ jobs:
steps:
- name: Checkout repository
uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
# Initializes the CodeQL tools for scanning.
- name: Initialize CodeQL
uses: github/codeql-action/init@8f1a6fed33af5212fab8a999d004627ae8901d1b # codeql-bundle-v2.17.5
uses: github/codeql-action/init@3096afedf9873361b2b2f65e1445b13272c83eb8 # codeql-bundle-v2.20.0
with:
languages: ${{ matrix.language }}
# If you wish to specify custom queries, you can do so here or in a config file.
@@ -54,4 +54,4 @@ jobs:
# make release
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@8f1a6fed33af5212fab8a999d004627ae8901d1b # codeql-bundle-v2.17.5
uses: github/codeql-action/analyze@3096afedf9873361b2b2f65e1445b13272c83eb8 # codeql-bundle-v2.20.0
+9 -4
View File
@@ -1,10 +1,15 @@
name: Check Copyright Headers
name: Add Copyright Headers
on: pull_request
jobs:
copywrite:
runs-on: ubuntu-latest
permissions:
contents: write
steps:
- uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
- uses: hashicorp/setup-copywrite@32638da2d4e81d56a0764aa1547882fc4d209636 # v1.1.3
- name: Check Header Compliance
run: copywrite headers --plan
- name: Add missing Copyright Headers
run: copywrite headers
- uses: stefanzweifel/git-auto-commit-action@8621497c8c39c72f3e2a999a26b4ca1b5058a842 # v5.0.1
with:
commit_message: Add missing copyright headers
+12 -12
View File
@@ -6,15 +6,15 @@ jobs:
name: Install dependencies
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7
- uses: actions/cache@0c45773b623bea8c8e75f6c82b208c3cf94ea4f9 # v4.0.2
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
- uses: actions/cache@1bd1e32a3bdc45362d1e726936510720a7c30a57 # v4.2.0
id: node-modules-cache
with:
path: '**/node_modules'
key: node-modules-${{ hashFiles('**/yarn.lock') }}
restore-keys: |
node-modules-
- uses: actions/setup-node@60edb5dd545a775178f52524783378180af0d1f8 # v4.0.2
- uses: actions/setup-node@39370e3970a6d050c480ffad4ff0ed4d3fdee5af # v4.1.0
with:
node-version: 20
- run: yarn install
@@ -24,15 +24,15 @@ jobs:
needs: [dependencies]
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7
- uses: actions/cache@0c45773b623bea8c8e75f6c82b208c3cf94ea4f9 # v4.0.2
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
- uses: actions/cache@1bd1e32a3bdc45362d1e726936510720a7c30a57 # v4.2.0
id: node-modules-cache
with:
path: '**/node_modules'
key: node-modules-${{ hashFiles('**/yarn.lock') }}
restore-keys: |
node-modules-
- uses: actions/setup-node@60edb5dd545a775178f52524783378180af0d1f8 # v4.0.2
- uses: actions/setup-node@39370e3970a6d050c480ffad4ff0ed4d3fdee5af # v4.1.0
with:
node-version: 20
- run: yarn run compliance:licenses
@@ -43,15 +43,15 @@ jobs:
runs-on: ubuntu-latest
timeout-minutes: 5
steps:
- uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7
- uses: actions/cache@0c45773b623bea8c8e75f6c82b208c3cf94ea4f9 # v4.0.2
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
- uses: actions/cache@1bd1e32a3bdc45362d1e726936510720a7c30a57 # v4.2.0
id: node-modules-cache
with:
path: '**/node_modules'
key: node-modules-${{ hashFiles('**/yarn.lock') }}
restore-keys: |
node-modules-
- uses: actions/setup-node@60edb5dd545a775178f52524783378180af0d1f8 # v4.0.2
- uses: actions/setup-node@39370e3970a6d050c480ffad4ff0ed4d3fdee5af # v4.1.0
with:
node-version: 20
- run: yarn lint
@@ -62,13 +62,13 @@ jobs:
runs-on: ubuntu-latest
timeout-minutes: 15
steps:
- uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7
- uses: actions/cache@0c45773b623bea8c8e75f6c82b208c3cf94ea4f9 # v4.0.2
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
- uses: actions/cache@1bd1e32a3bdc45362d1e726936510720a7c30a57 # v4.2.0
id: node-modules-cache
with:
path: '**/node_modules'
key: node-modules-${{ hashFiles('**/yarn.lock') }}
- uses: actions/setup-node@60edb5dd545a775178f52524783378180af0d1f8 # v4.0.2
- uses: actions/setup-node@39370e3970a6d050c480ffad4ff0ed4d3fdee5af # v4.1.0
with:
node-version: 20
- run: yarn test
+1 -1
View File
@@ -7,7 +7,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
with:
token: ${{ secrets.ELEVATED_GITHUB_TOKEN }}
- run: |
@@ -1,25 +0,0 @@
name: "Trigger Test Boundary UI release"
on:
workflow_dispatch:
inputs:
branch:
description: Please use tag-like format n.n.n-someword (1.111.11-beta)
required: true
jobs:
trigger-gha-release:
runs-on: ubuntu-latest
steps:
- name: Release description
if: github.event_name == 'workflow_dispatch'
run: |
echo "Triggering Test release using BRANCH and TEST_TAG ${{ github.event.inputs.branch }}"
- name: Trigger Release workflow in boundary-ui-releases
run: |
export GITHUB_TOKEN="${{ secrets.ELEVATED_GITHUB_TOKEN }}"
gh workflow run release.yml \
--repo hashicorp/boundary-ui-releases \
--ref main \
-f TAG="${{ github.event.inputs.branch }}"
+4 -4
View File
@@ -1,4 +1,4 @@
name: "Trigger Boundary UI release"
name: "Trigger Boundary Desktop release"
on:
push:
@@ -9,14 +9,14 @@ jobs:
trigger-gha-release:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
- name: Release description
run: |
echo "Triggering release with a TAG ${GITHUB_REF#refs/tags/}"
- name: Trigger Release workflow in boundary-ui-releases
- name: Trigger Release workflow in boundary-desktop-releases
run: |
export GITHUB_TOKEN="${{ secrets.ELEVATED_GITHUB_TOKEN }}"
gh workflow run release.yml \
--repo hashicorp/boundary-ui-releases \
--repo hashicorp/boundary-desktop-releases \
--ref main \
-f TAG="${GITHUB_REF#refs/tags/}"
-3
View File
@@ -1,5 +1,2 @@
#!/usr/bin/env sh
. "$(dirname -- "$0")/_/husky.sh"
yarn compliance:licenses
npx lint-staged
-3
View File
@@ -1,6 +1,3 @@
#!/usr/bin/env sh
. "$(dirname -- "$0")/_/husky.sh"
COMMIT_MSG_FILE=$1
COMMIT_SOURCE=$2
SHA1=$3
+10 -9
View File
@@ -98,7 +98,7 @@ List of available project commands. `yarn run <command-name>`
| Command | Description |
|---------------------|---|
| build | Builds Admin UI. |
| build | Builds Admin UI for production. |
| test | Runs tests in CI mode. |
| lint | Runs ember-template-lint on all of the hbs, js, and sass files. |
| compliance:audit | Checks for issues using `yarn audit` with moderate and above criticality.|
@@ -119,9 +119,9 @@ of README.
### Building Admin UI for Production
See ui/admin/README.md Building for Production for more information on how to
build the Admin UI. Be sure to set build-related environment variables as
necessary for your target environment, as described in the Admin UI readme.
See [Admin UI README](ui/admin/README.md#building-for-production) for more information on how to
build the Admin UI for production. Be sure to set build-related environment variables as
necessary for your target environment, as described in the [Environment Variables](ui/admin/README.md#environment-variables) section of README.
To quickly produce a production build of Admin UI, run from this folder:
@@ -144,9 +144,9 @@ Assets are saved to `ui/admin/dist/`.
### Building Desktop UI for Production
See ui/desktop/README.md Building for Production for more information on how to
See [Desktop UI README](ui/desktop/README.md#building-for-production) for more information on how to
build the Desktop UI. Be sure to set build-related environment variables as
necessary for your target environment, as described in the Desktop UI readme.
necessary for your target environment, as described in the [Environment Variables](ui/desktop/README.md#environment-variables-prod) section of README.
To quickly produce a production build of Desktop UI, run from this folder:
@@ -174,8 +174,9 @@ EXE archived desktop UI is available at asset location under `zip` folder.
This describes how to connect local Boundary UI to your local instance of Boundary.
This assumes you already have up and running a Boundary dev instance in your local environment with a listener `127.0.0.1:9200` (default behaviour). [Learn how to start a local Boundary dev instance](https://learn.hashicorp.com/tutorials/boundary/getting-started-dev?in=boundary/getting-started#start-a-dev-environment).
#### For admin
This assumes you already have up and running a Boundary dev instance in your local environment with a listener `127.0.0.1:9200` (default behaviour). [Learn how to start a local Boundary dev instance](https://developer.hashicorp.com/boundary/tutorials/get-started-community/community-get-started-dev)
#### For Admin
This assumes you are within `boundary-ui/ui/admin`.
@@ -185,7 +186,7 @@ Following terminal instructions, open in your browser: `http://localhost:4200/`.
Once you open the UI you will see the login screen, authenticate using generated admin login name and password.
#### For desktop
#### For Desktop
This assumes you are within `boundary-ui/ui/desktop`.
@@ -7,6 +7,7 @@ import sinon from 'sinon';
import { typeOf } from '@ember/utils';
import { resourceNames } from 'api/handlers/cache-daemon-handler';
import { singularize } from 'ember-inflector';
import { underscore } from '@ember/string';
/**
* This test helper can be used to help setup your sinon stubs in your tests.
@@ -69,16 +70,18 @@ export default function setupStubs(hooks) {
.withArgs('searchCacheDaemon')
.onCall(i)
.returns({
[resourceName]: models.map((model) => {
// Use internal serializer to serialize the model correctly
// according to our mirage serializers
const modelData =
this.server.serializerOrRegistry.serialize(model);
[underscore(resourceNames[singularize(resourceName)])]: models.map(
(model) => {
// Use internal serializer to serialize the model correctly
// according to our mirage serializers
const modelData =
this.server.serializerOrRegistry.serialize(model);
// Serialize the data properly to standard JSON as that is what
// we're expecting from the cache daemon response
return JSON.parse(JSON.stringify(modelData));
}),
// Serialize the data properly to standard JSON as that is what
// we're expecting from the cache daemon response
return JSON.parse(JSON.stringify(modelData));
},
),
});
});
};
@@ -55,63 +55,224 @@ export default class GeneratedHostCatalogModel extends BaseModel {
})
plugin;
// AWS & Azure
// AWS, Azure & GCP
@attr('boolean', {
for: {
type: 'plugin',
name: ['aws', 'azure', 'gcp'],
},
isNestedAttribute: true,
description: '',
})
disable_credential_rotation;
// AWS and GCP specific
@attr('string', {
for: {
type: 'plugin',
name: ['aws', 'gcp'],
},
description:
'An expression used to filter the workers that have network access to a service that is hosting the external object store.',
})
worker_filter;
// AWS specific
@attr('string', {
for: {
type: 'plugin',
name: 'aws',
},
isNestedAttribute: true,
description: '',
})
region;
// AWS static credentials
@attr('string', {
for: {
type: 'plugin',
name: 'aws',
credentialType: 'static-credential',
},
isNestedSecret: true,
description: '',
})
access_key_id;
@attr('string', {
for: {
type: 'plugin',
name: 'aws',
credentialType: 'static-credential',
},
isNestedSecret: true,
description: '',
})
secret_access_key;
// AWS dynamic credentials
@attr('string', {
for: {
type: 'plugin',
name: 'aws',
credentialType: 'dynamic-credential',
},
isNestedAttribute: true,
description: 'The role ARN to use.',
})
role_arn;
@attr('string', {
for: {
type: 'plugin',
name: 'aws',
credentialType: 'dynamic-credential',
},
isNestedAttribute: true,
description: 'The role external ID to use.',
})
role_external_id;
@attr('string', {
for: {
type: 'plugin',
name: 'aws',
credentialType: 'dynamic-credential',
},
isNestedAttribute: true,
description: 'The role session to use.',
})
role_session_name;
@attr('object-as-array', {
for: {
type: 'plugin',
name: 'aws',
credentialType: 'dynamic-credential',
},
isNestedAttribute: true,
description: 'The role tags to use.',
})
role_tags;
// Azure specific
@attr('string', {
for: {
type: 'plugin',
name: 'azure',
},
isNestedAttribute: true,
description: '',
})
tenant_id;
@attr('string', {
for: {
type: 'plugin',
name: 'azure',
},
isNestedAttribute: true,
description: '',
})
client_id;
@attr('string', {
for: {
type: 'plugin',
name: 'azure',
},
isNestedAttribute: true,
description: '',
})
subscription_id;
@attr('string', {
for: {
type: 'plugin',
name: 'azure',
},
isNestedSecret: true,
description: '',
})
secret_id;
@attr('string', {
for: {
type: 'plugin',
name: 'azure',
},
isNestedSecret: true,
description: '',
})
secret_value;
// GCP specific
@attr('string', {
for: {
type: 'plugin',
name: 'gcp',
},
isNestedAttribute: true,
description: 'The project ID associated with the service account.',
})
project_id;
@attr('string', {
for: {
type: 'plugin',
name: 'gcp',
},
isNestedAttribute: true,
description: 'The deployment area within a region.',
})
zone;
@attr('string', {
for: {
type: 'plugin',
name: 'gcp',
},
isNestedAttribute: true,
description:
'The email address associated with the service account. The email address used to uniquely identify the service account. It is required for authentication and authorization.',
})
client_email;
@attr('string', {
for: {
type: 'plugin',
name: 'gcp',
},
isNestedAttribute: true,
description:
'The unique identifier for the service account that will be impersonated.',
})
target_service_account_id;
@attr('string', {
for: {
type: 'plugin',
name: 'gcp',
},
description:
'The ID of the private key used to sign the JWT and authentication.',
isNestedSecret: true,
})
private_key_id;
@attr('string', {
for: {
type: 'plugin',
name: 'gcp',
},
description:
'The private key used to sign the JWT and obtain a OAuth 2.0 access token.',
isNestedSecret: true,
})
private_key;
}
+17 -1
View File
@@ -63,6 +63,10 @@ export default class GeneratedHostSetModel extends BaseModel {
plugin;
@attr('number', {
for: {
type: 'plugin',
name: ['aws', 'azure', 'gcp'],
},
description:
"The number of seconds between the time boundary syncs the hosts in this set using this host set's plugin. If not provided a system determined default is used",
})
@@ -79,12 +83,20 @@ export default class GeneratedHostSetModel extends BaseModel {
host_ids;
@attr('string-array', {
for: {
type: 'plugin',
name: ['aws', 'azure', 'gcp'],
},
emptyArrayIfMissing: true,
})
preferred_endpoints;
// AWS specific
// AWS & GCP specific
@attr('string-array', {
for: {
type: 'plugin',
name: ['aws', 'gcp'],
},
isNestedAttribute: true,
emptyArrayIfMissing: true,
})
@@ -92,6 +104,10 @@ export default class GeneratedHostSetModel extends BaseModel {
// Azure specific, comes in from API as "filter". This is to avoid collisions with filter
@attr('string', {
for: {
type: 'plugin',
name: 'azure',
},
description: '',
isNestedAttribute: true,
})
@@ -8,6 +8,7 @@ import { inject as service } from '@ember/service';
import { getOwner, setOwner } from '@ember/application';
import { generateMQLExpression } from '../utils/mql-query';
import { paginateResults } from '../utils/paginate-results';
import { underscore } from '@ember/string';
/**
* Not all types are yet supported by the cache daemon so we'll
@@ -94,12 +95,14 @@ export default class CacheDaemonHandler {
const sessionData = this.session.data?.authenticated;
const auth_token_id = sessionData?.id;
const token = sessionData?.token;
const resourceName = resourceNames[type];
remainingQuery = {
...remainingQuery,
query: searchQuery,
auth_token_id,
token,
resource: resourceNames[type],
resource: resourceName,
};
let cacheDaemonResults = {};
@@ -130,7 +133,7 @@ export default class CacheDaemonHandler {
}
} else {
__electronLog?.error(
'Failed to search cache daemon; falling back to search controller',
`Failed to search cache daemon for ${resourceName}. Error:`,
e.message,
);
@@ -138,10 +141,7 @@ export default class CacheDaemonHandler {
}
}
// Currently returns with a singular top level field with resource name
// e.g. { targets: [...] } or { sessions: [..] }
// So this just unwraps to the array, or undefined
const [results] = Object.values(cacheDaemonResults);
const results = cacheDaemonResults[underscore(resourceName)];
const payload = { items: paginateResults(results, page, pageSize) };
const schema = store.modelFor(type);
@@ -167,7 +167,16 @@ export default class CacheDaemonHandler {
// This isn't conventional but is better than returning an ArrayProxy
// or EmberArray since the ember store query method asserts it has to be an array
// so we can't just return an object.
records.meta = { totalItems: results?.length ?? 0 };
// Also include whether the results are incomplete or is still refreshing
// as part of the response
records.meta = {
totalItems: results?.length ?? 0,
isLoadIncomplete: cacheDaemonResults.incomplete ?? false,
// Sometimes the refresh status returns an error status if it takes too long but it's still refreshing
isCacheRefreshing:
cacheDaemonResults.refresh_status !== 'not-refreshing',
};
return records;
}
default:
@@ -1,27 +0,0 @@
/**
* Copyright (c) HashiCorp, Inc.
* SPDX-License-Identifier: BUSL-1.1
*/
import { registerDeprecationHandler } from '@ember/debug';
const deprecationList = ['ember-data:deprecate-early-static'];
export function initialize() {
registerDeprecationHandler((message, options, next) => {
// TODO: Remove deprecation handling for `deprecate-early-static` warning
// once we upgrade to ember-cli-mirage v3.0.0 which fixes this issue.
// More info about this issue here: https://github.com/miragejs/ember-cli-mirage/issues/2441
if (options?.id && deprecationList.includes(options.id)) {
return;
}
if (options?.url) {
message += options.url;
}
next(message, options);
});
}
export default {
initialize,
};
+12 -3
View File
@@ -8,7 +8,16 @@ import GeneratedCredentialModel from '../generated/models/credential';
/**
* Supported Credential types.
*/
export const types = ['username_password', 'ssh_private_key', 'json'];
export const TYPE_CREDENTIAL_USERNAME_PASSWORD = 'username_password';
export const TYPE_CREDENTIAL_SSH_PRIVATE_KEY = 'ssh_private_key';
export const TYPE_CREDENTIAL_JSON = 'json';
export const TYPES_CREDENTIAL = Object.freeze([
TYPE_CREDENTIAL_USERNAME_PASSWORD,
TYPE_CREDENTIAL_SSH_PRIVATE_KEY,
TYPE_CREDENTIAL_JSON,
]);
export default class CredentialModel extends GeneratedCredentialModel {
// =attributes
@@ -28,7 +37,7 @@ export default class CredentialModel extends GeneratedCredentialModel {
* @type {boolean}
*/
get isJSON() {
return this.type === 'json';
return this.type === TYPE_CREDENTIAL_JSON;
}
/**
@@ -36,6 +45,6 @@ export default class CredentialModel extends GeneratedCredentialModel {
* @type {boolean}
*/
get isUnknown() {
return !types.includes(this.type);
return !TYPES_CREDENTIAL.includes(this.type);
}
}
+52 -2
View File
@@ -14,14 +14,33 @@ export const TYPES_HOST_CATALOG = Object.freeze([
export const TYPE_HOST_CATALOG_PLUGIN_AWS = 'aws';
export const TYPE_HOST_CATALOG_PLUGIN_AZURE = 'azure';
export const TYPE_HOST_CATALOG_PLUGIN_GCP = 'gcp';
export const TYPES_HOST_CATALOG_PLUGIN = [
TYPE_HOST_CATALOG_PLUGIN_AWS,
TYPE_HOST_CATALOG_PLUGIN_AZURE,
TYPE_HOST_CATALOG_PLUGIN_GCP,
];
export const TYPE_CREDENTIAL_STATIC = 'static-credential';
export const TYPE_CREDENTIAL_DYNAMIC = 'dynamic-credential';
export const TYPES_CREDENTIALS = Object.freeze([
TYPE_CREDENTIAL_STATIC,
TYPE_CREDENTIAL_DYNAMIC,
]);
export const DYNAMIC_CREDENTIAL_FIELDS = [
'role_arn',
'role_external_id',
'role_session_name',
'role_tags',
];
export const STATIC_CREDENTIAL_FIELDS = ['access_key_id, secret_access_key'];
export default class HostCatalogModel extends GeneratedHostCatalogModel {
// =attributes
#credentialType;
/**
* True if the host catalog is static.
* @type {boolean}
@@ -38,6 +57,29 @@ export default class HostCatalogModel extends GeneratedHostCatalogModel {
return this.type === 'plugin';
}
/**
* Gets a value from credentialType
* @type {string}
*/
get credentialType() {
if (!this.#credentialType) {
if (DYNAMIC_CREDENTIAL_FIELDS.some((field) => this[field])) {
this.#credentialType = TYPE_CREDENTIAL_DYNAMIC;
} else {
this.#credentialType = TYPE_CREDENTIAL_STATIC;
}
}
return this.#credentialType;
}
/**
* Sets a value to credentialType
* @type {string}
*/
set credentialType(type) {
this.#credentialType = type;
}
/**
* True if the host catalog is an unknown type.
* @type {boolean}
@@ -53,7 +95,7 @@ export default class HostCatalogModel extends GeneratedHostCatalogModel {
* @type {boolean}
*/
get isAWS() {
return this.compositeType === 'aws';
return this.compositeType === TYPE_HOST_CATALOG_PLUGIN_AWS;
}
/**
@@ -61,7 +103,15 @@ export default class HostCatalogModel extends GeneratedHostCatalogModel {
* @type {boolean}
*/
get isAzure() {
return this.compositeType === 'azure';
return this.compositeType === TYPE_HOST_CATALOG_PLUGIN_AZURE;
}
/**
* True if host catalog plugin type is GCP.
* @type {boolean}
*/
get isGCP() {
return this.compositeType === TYPE_HOST_CATALOG_PLUGIN_GCP;
}
/**
+16 -3
View File
@@ -4,7 +4,12 @@
*/
import GeneratedHostSetModel from '../generated/models/host-set';
import { TYPES_HOST_CATALOG_PLUGIN } from './host-catalog';
import {
TYPES_HOST_CATALOG_PLUGIN,
TYPE_HOST_CATALOG_PLUGIN_GCP,
TYPE_HOST_CATALOG_PLUGIN_AWS,
TYPE_HOST_CATALOG_PLUGIN_AZURE,
} from './host-catalog';
export default class HostSetModel extends GeneratedHostSetModel {
// =attributes
@@ -40,14 +45,22 @@ export default class HostSetModel extends GeneratedHostSetModel {
* @type {boolean}
*/
get isAWS() {
return this.compositeType === 'aws';
return this.compositeType === TYPE_HOST_CATALOG_PLUGIN_AWS;
}
/**
* Return if a host-set plugin is Azure or not.
*/
get isAzure() {
return this.compositeType === 'azure';
return this.compositeType === TYPE_HOST_CATALOG_PLUGIN_AZURE;
}
/**
* True if host catalog plugin type is GCP.
* @type {boolean}
*/
get isGCP() {
return this.compositeType === TYPE_HOST_CATALOG_PLUGIN_GCP;
}
/**
+43 -6
View File
@@ -8,6 +8,9 @@ import { equal } from '@ember/object/computed';
import { tracked } from '@glimmer/tracking';
import { A } from '@ember/array';
import { inject as service } from '@ember/service';
import { flattenObject } from '../utils/flatten-nested-object';
import { TYPES_CREDENTIAL_LIBRARY } from 'api/models/credential-library';
import { TYPE_CREDENTIAL_JSON } from 'api/models/credential';
export const STATUS_SESSION_ACTIVE = 'active';
export const STATUS_SESSION_PENDING = 'pending';
@@ -23,7 +26,7 @@ export const statusTypes = [
/**
*
*/
class SessionCredential {
export class SessionCredential {
// =classes
/**
@@ -34,12 +37,14 @@ class SessionCredential {
name;
description;
type;
credentialtype;
constructor(id, name, description, type) {
constructor(id, name, description, type, credentialtype) {
this.id = id;
this.name = name;
this.description = description;
this.type = type;
this.credentialType = credentialtype;
}
};
@@ -75,8 +80,10 @@ class SessionCredential {
get secrets() {
if (this.#payloadSecret?.decoded) {
const secretJSON = this.#payloadSecret.decoded;
return Object.keys(secretJSON).map(
(key) => new SessionCredential.SecretItem(key, secretJSON[key]),
return this.extractSecrets(
secretJSON,
this.source.type,
this.source.credentialType,
);
} else {
// decode from base64
@@ -85,11 +92,41 @@ class SessionCredential {
}
}
/**
* Extracts secrets from the payload secret JSON object.
* We only need to flatten the object if the type is vault or if its a json type credential.
* @param {object} secretJSON - The payload secret JSON object.
* @param {string} type - The credential source type.
* @param {string} credentialType - The credential type.
* @returns {SessionCredential.SecretItem[]} - The array of secret items.
*/
extractSecrets(secretJSON, type, credentialType) {
let source;
if (credentialType === TYPE_CREDENTIAL_JSON) {
source = flattenObject(secretJSON);
} else if (TYPES_CREDENTIAL_LIBRARY.includes(type) && secretJSON?.data) {
source = flattenObject(secretJSON.data);
} else {
source = secretJSON;
}
return Object.entries(source).map(
([key, value]) => new SessionCredential.SecretItem(key, value),
);
}
// =methods
constructor(cred) {
const { id, name, description, type } = cred.credential_source;
this.source = new SessionCredential.Source(id, name, description, type);
const { id, name, description, type, credential_type } =
cred.credential_source;
this.source = new SessionCredential.Source(
id,
name,
description,
type,
credential_type,
);
this.#payloadSecret = cred.secret;
this.rawCredential = cred;
}
+33 -12
View File
@@ -6,6 +6,7 @@
import RESTSerializer from '@ember-data/serializer/rest';
import { underscore } from '@ember/string';
import { get } from '@ember/object';
import { typeOf } from '@ember/utils';
/**
* Manages serialization/normalization of data to/from the API.
@@ -42,7 +43,7 @@ export default class ApplicationSerializer extends RESTSerializer {
*/
serializeAttribute(snapshot, json, key, attribute) {
const { type, options } = attribute;
const { type: recordType } = snapshot.record;
const { type: recordType, compositeType } = snapshot.record;
let value = super.serializeAttribute(...arguments);
// Remove secret attributes that are null or empty
if (options.isSecret) {
@@ -74,18 +75,38 @@ export default class ApplicationSerializer extends RESTSerializer {
delete json[key];
}
// If an attribute has a `for` option, it must match the
// record's `type`, else the attribute is excluded
// record's `type`, otherwise the attribute is excluded
// from serialization.
//note: This doesn't handle secrets yet, we can add support for them if needed.
if (
options?.for &&
options.for !== recordType &&
!options.for.includes(recordType)
) {
if (options.isNestedAttribute) {
delete json?.attributes?.[key];
} else {
delete json[key];
if (options?.for) {
// Check the typeof the `for` option to determine if it is a plugin or not
const isPlugin = options.for?.type === 'plugin';
// Helper function to handle deleting attribute and secret keys
const deleteKey = (json) => {
if (options.isNestedAttribute) {
delete json?.attributes?.[key];
} else if (options.isNestedSecret && json?.secrets?.[key]) {
delete json?.secrets?.[key];
if (Object.keys(json.secrets).length === 0) {
delete json.secrets;
}
} else {
delete json[key];
}
};
// For plugins, the `for` option is an object with a `name` key
// For non-plugins, the `for` option can be string or an array
if (
(isPlugin && !options.for?.name.includes(compositeType)) ||
(!isPlugin &&
!options.for?.includes(recordType) &&
typeOf(options.for) === 'array') ||
(!isPlugin &&
options.for !== recordType &&
typeOf(options.for) === 'string')
) {
deleteKey(json);
}
}
return value;
+28 -44
View File
@@ -4,61 +4,45 @@
*/
import ApplicationSerializer from './application';
const fieldsByType = {
aws: [
'disable_credential_rotation',
'region',
'access_key_id',
'secret_access_key',
],
azure: [
'disable_credential_rotation',
'tenant_id',
'client_id',
'subscription_id',
'secret_id',
'secret_value',
],
};
import { TYPE_CREDENTIAL_DYNAMIC } from '../models/host-catalog';
export default class HostCatalogSerializer extends ApplicationSerializer {
// =methods
serialize(snapshot) {
const { credentialType } = snapshot.record;
const serialized = super.serialize(...arguments);
switch (snapshot.record.compositeType) {
case 'static':
return this.serializeStatic(...arguments);
default:
return serialized;
// By default, disable credential rotation for dynamic credentials
if (credentialType === TYPE_CREDENTIAL_DYNAMIC) {
serialized.attributes.disable_credential_rotation = true;
}
return serialized;
}
serializeAttribute(snapshot, json, key, attribute) {
const value = super.serializeAttribute(...arguments);
const { isPlugin, compositeType } = snapshot.record;
const { compositeType, credentialType } = snapshot.record;
const { options } = attribute;
// Nested conditionals for readability
// This deletes any fields that don't belong to the record type
if (isPlugin && options.isNestedAttribute && json.attributes) {
// The key must be included in the fieldsByType list above
if (!fieldsByType[compositeType].includes(key))
delete json.attributes[key];
}
// This deletes any fields that don't belong to the record type
if (isPlugin && options.isNestedSecret && json.secrets) {
if (!fieldsByType[compositeType].includes(key)) delete json.secrets[key];
}
const isSamePluginName = options?.for?.name?.includes(compositeType);
// new one for isNestedSecret
// Remove attributes that are not applicable to the current credential type for the same plugin
// For example, 'aws' dynamic plugin has two credential types: 'static' and 'dynamic'
// API expects the fields to be 'null' for the fields that are not from the current credential type (that's why we are not using the application serializer for this, where we delete attrs)
// Empty secrets should be removed from the JSON
if (
isSamePluginName &&
options.for.credentialType &&
options.for.credentialType !== credentialType
) {
if (options.isNestedAttribute) {
json.attributes[key] = null;
} else if (options.isNestedSecret && json.secrets[key]) {
delete json.secrets[key];
if (Object.keys(json.secrets).length === 0) {
delete json.secrets;
}
} else {
delete json[key];
}
}
return value;
}
serializeStatic() {
const serialized = super.serialize(...arguments);
// Delete unnecessary fields for static host-catalog
delete serialized.attributes;
delete serialized.secrets;
return serialized;
}
}
+1 -13
View File
@@ -5,10 +5,6 @@
import ApplicationSerializer from './application';
const fieldByType = {
aws: ['preferred_endpoints', 'filters', 'sync_interval_seconds'],
azure: ['preferred_endpoints', 'filter_string', 'sync_interval_seconds'],
};
export default class HostSetSerializer extends ApplicationSerializer {
// =properties
@@ -63,16 +59,8 @@ export default class HostSetSerializer extends ApplicationSerializer {
return serialized;
}
serializeAttribute(snapshot, json, key, attribute) {
serializeAttribute(snapshot, json, key) {
const value = super.serializeAttribute(...arguments);
const { isPlugin, compositeType } = snapshot.record;
const { options } = attribute;
if (isPlugin && options.isNestedAttribute) {
if (!fieldByType[compositeType].includes(key)) {
delete json.attributes[key];
}
}
if (key === 'filter_string') {
const { filter_string } = json.attributes;
+5 -1
View File
@@ -29,6 +29,10 @@ export const modelIndexes = {
'&id, attributes.created_time, attributes.type, attributes.name, attributes.description, attributes.scope.scope_id, attributes.plugin.name',
'auth-method':
'&id, attributes.created_time, attributes.type, attributes.name, attributes.description, attributes.is_primary, attributes.scope.scope_id',
'session-recording':
'&id, attributes.created_time, attributes.type, attributes.state, attributes.start_time, attributes.end_time, attributes.duration, attributes.scope.scope_id, attributes.create_time_values.user.id, attributes.create_time_values.user.name, attributes.create_time_values.target.id, attributes.create_time_values.target.name, attributes.create_time_values.target.scope.id, attributes.create_time_values.target.scope.name',
alias:
'&id, attributes.created_time, attributes.type, attributes.value, attributes.name, attributes.description, attributes.destination_id, attributes.scope.scope_id',
};
export const formatDbName = (userId, clusterUrl) =>
@@ -109,7 +113,7 @@ export default class IndexedDbService extends Service {
}
this.#db = new Dexie(dbName);
this.#db.version(1).stores(modelIndexes);
this.#db.version(2).stores(modelIndexes);
}
/**
@@ -0,0 +1,27 @@
/**
* Copyright (c) HashiCorp, Inc.
* SPDX-License-Identifier: BUSL-1.1
*/
import { typeOf } from '@ember/utils';
/**
* Flattens a nested object into a single-level object.
* @param obj
* @param result
* @param parentKey
* @returns {Object}
*/
export const flattenObject = (obj, result = {}, parentKey = '') => {
for (const key in obj) {
// Check if the value is an object and it is not null
if (typeOf(obj[key]) === 'object' && obj[key] !== null) {
// Recursively flatten the object
flattenObject(obj[key], result, `${parentKey}${key}.`);
} else if (obj[key] !== null && obj[key] !== '') {
// Only add to result if the value is not null or an empty string
result[`${parentKey}${key}`] = obj[key];
}
}
return result;
};
@@ -1,6 +0,0 @@
/**
* Copyright (c) HashiCorp, Inc.
* SPDX-License-Identifier: BUSL-1.1
*/
export { default, initialize } from 'api/initializers/deprecations';
+5 -13
View File
@@ -25,7 +25,10 @@ const isTesting = environmentConfig.environment === 'test';
export default function (mirageConfig) {
let finalConfig = {
...mirageConfig,
models: { ...discoverEmberDataModels(), ...mirageConfig.models },
models: {
...discoverEmberDataModels(mirageConfig.store),
...mirageConfig.models,
},
serializers: applyEmberDataSerializers(mirageConfig.serializers),
routes,
};
@@ -775,18 +778,7 @@ function routes() {
});
// session recordings
this.get(
'/session-recordings',
(
{ sessionRecordings },
{ queryParams: { scope_id: scopeId, recursive } },
) => {
if (recursive && scopeId === 'global') {
return sessionRecordings.all();
}
return sessionRecordings.where({ scopeId });
},
);
this.get('/session-recordings');
this.get(
'/session-recordings/:idMethod',
async ({ sessionRecordings }, { params: { idMethod } }) => {
+46 -9
View File
@@ -8,11 +8,23 @@ import { trait } from 'miragejs';
import permissions from '../helpers/permissions';
import { faker } from '@faker-js/faker';
import generateId from '../helpers/id';
import {
TYPE_HOST_CATALOG_PLUGIN_AZURE,
TYPE_HOST_CATALOG_PLUGIN_GCP,
TYPE_HOST_CATALOG_PLUGIN_AWS,
TYPE_HOST_CATALOG_STATIC,
TYPE_HOST_CATALOG_DYNAMIC,
TYPES_HOST_CATALOG,
} from 'api/models/host-catalog';
const types = ['static', 'plugin'];
// Represents known plugin types, except "foobar" which models the possibility
// of receiving an _unknown_ type, which the UI must handle gracefully.
const pluginTypes = ['aws', 'azure', 'foobar'];
const pluginTypes = [
TYPE_HOST_CATALOG_PLUGIN_GCP,
TYPE_HOST_CATALOG_PLUGIN_AWS,
TYPE_HOST_CATALOG_PLUGIN_AZURE,
'foobar',
];
let pluginTypeCounter = 1;
@@ -20,7 +32,7 @@ export default factory.extend({
id: () => generateId('hc_'),
// Cycle through available types
type: (i) => types[i % types.length],
type: (i) => TYPES_HOST_CATALOG[i % TYPES_HOST_CATALOG.length],
authorized_actions: () =>
permissions.authorizedActionsFor('host-catalog') || [
@@ -30,7 +42,7 @@ export default factory.extend({
'delete',
],
authorized_collection_actions: function () {
const isStatic = this.type === 'static';
const isStatic = this.type === TYPE_HOST_CATALOG_STATIC;
return {
// only static catalogs allow host create at this time
hosts: isStatic ? ['create', 'list'] : ['list'],
@@ -38,8 +50,18 @@ export default factory.extend({
};
},
worker_filter: function () {
if (
this.type === TYPE_HOST_CATALOG_DYNAMIC &&
(this.plugin?.name === TYPE_HOST_CATALOG_PLUGIN_AWS ||
this.plugin?.name === TYPE_HOST_CATALOG_PLUGIN_GCP)
) {
return `"${faker.word.noun()}" in "${faker.system.directoryPath()}"`;
}
},
plugin: function (i) {
if (this.type === 'plugin') {
if (this.type === TYPE_HOST_CATALOG_DYNAMIC) {
return {
id: `plugin-id-${i}`,
name: pluginTypes[pluginTypeCounter++ % pluginTypes.length],
@@ -50,35 +72,50 @@ export default factory.extend({
attributes() {
switch (this.plugin?.name) {
case 'aws':
case TYPE_HOST_CATALOG_PLUGIN_AWS:
return {
disable_credential_rotation: faker.datatype.boolean(),
region: `us-${faker.location.cardinalDirection()}-${faker.number.int(
9,
)}`,
};
case 'azure':
case TYPE_HOST_CATALOG_PLUGIN_AZURE:
return {
disable_credential_rotation: faker.datatype.boolean(),
tenant_id: faker.string.uuid(),
client_id: faker.string.uuid(),
subscription_id: faker.string.uuid(),
};
case TYPE_HOST_CATALOG_PLUGIN_GCP:
return {
disable_credential_rotation: faker.datatype.boolean(),
project_id: faker.string.uuid(),
client_email: faker.internet.email(),
target_service_account_id: faker.string.uuid(),
zone: `us-${faker.location.cardinalDirection()}${faker.number.int(
9,
)}-${faker.string.fromCharacters('abc')}`,
};
}
},
secrets() {
switch (this.plugin?.name) {
case 'aws':
case TYPE_HOST_CATALOG_PLUGIN_AWS:
return {
access_key_id: faker.string.nanoid(),
secret_access_key: faker.string.nanoid(),
};
case 'azure':
case TYPE_HOST_CATALOG_PLUGIN_AZURE:
return {
secret_id: faker.string.nanoid(),
secret_value: faker.string.nanoid(),
};
case TYPE_HOST_CATALOG_PLUGIN_GCP:
return {
private_key: faker.string.nanoid(),
private_key_id: faker.string.nanoid(),
};
}
},
withChildren: trait({
+25 -16
View File
@@ -7,6 +7,22 @@ import factory from '../generated/factories/host-set';
import permissions from '../helpers/permissions';
import { faker } from '@faker-js/faker';
import generateId from '../helpers/id';
import {
TYPE_HOST_CATALOG_PLUGIN_AWS,
TYPE_HOST_CATALOG_PLUGIN_AZURE,
TYPE_HOST_CATALOG_PLUGIN_GCP,
} from 'api/models/host-catalog';
function generateFilters(prefix) {
const filtersAmount = faker.number.int({ min: 1, max: 5 });
let filters = [];
for (let i = 0; i < filtersAmount; ++i) {
filters.push(`${prefix}${faker.word.words(1)}=${faker.word.words(1)}`);
}
return {
filters,
};
}
export default factory.extend({
id: () => generateId('hs_'),
@@ -42,22 +58,15 @@ export default factory.extend({
},
attributes() {
// AWS specific
if (this.plugin?.name === 'aws') {
const filtersAmount = faker.number.int({ min: 1, max: 5 });
let filters = [];
for (let i = 0; i < filtersAmount; ++i) {
filters.push(`${faker.word.words(1)}=${faker.word.words(1)}`);
}
return {
filters,
};
}
// Azure specific
if (this.plugin?.name === 'azure') {
return {
filter: `${faker.database.column()}=${faker.database.collation()}`,
};
switch (this.plugin?.name) {
case TYPE_HOST_CATALOG_PLUGIN_AWS:
return generateFilters('tag:');
case TYPE_HOST_CATALOG_PLUGIN_AZURE:
return {
filter: `${faker.database.column()}=${faker.database.collation()}`,
};
case TYPE_HOST_CATALOG_PLUGIN_GCP:
return generateFilters('labels.');
}
},
});
+9 -5
View File
@@ -7,24 +7,28 @@ import factory from '../generated/factories/host';
import permissions from '../helpers/permissions';
import { faker } from '@faker-js/faker';
import generateId from '../helpers/id';
import {
TYPE_HOST_CATALOG_STATIC,
TYPE_HOST_CATALOG_DYNAMIC,
} from 'api/models/host-catalog';
export default factory.extend({
id: () => generateId('h_'),
name() {
if (this.type === 'static') return faker.word.words();
if (this.type === TYPE_HOST_CATALOG_STATIC) return faker.word.words();
},
type() {
return this.hostCatalog?.type || factory.attrs.type;
},
authorized_actions: function () {
const isStatic = this.type === 'static';
const isStatic = this.type === TYPE_HOST_CATALOG_STATIC;
const defaults = ['no-op', 'read'];
// Only static allows update/delete at this time.
if (isStatic) defaults.push('update', 'delete');
return permissions.authorizedActionsFor('host') || defaults;
},
plugin() {
if (this.type === 'plugin') {
if (this.type === TYPE_HOST_CATALOG_DYNAMIC) {
return this.hostCatalog.plugin;
}
},
@@ -38,12 +42,12 @@ export default factory.extend({
},
// Return external fields only for plugins
external_id() {
if (this.type === 'plugin') {
if (this.type === TYPE_HOST_CATALOG_DYNAMIC) {
return faker.string.uuid();
}
},
external_name(i) {
if (this.type === 'plugin') {
if (this.type === TYPE_HOST_CATALOG_DYNAMIC) {
return `${this.plugin.name} provided name ${i}`;
}
},
+1 -1
View File
@@ -15,7 +15,7 @@ export default factory.extend({
authorized_actions() {
const authorizedActions = ['no-op', 'read', 'update'];
// Storage policies can only be attatched to global and org scopes.
// Storage policies can only be attached to global and org scopes.
if (this.type === 'global' || this.type === 'org') {
authorizedActions.push('attach-storage-policy', 'detach-storage-policy');
}
-1
View File
@@ -4,7 +4,6 @@
*/
// import config from '../../config/environment';
// import { v1 } from 'ember-uuid';
import { Response } from 'miragejs';
// /**
+53
View File
@@ -83,6 +83,37 @@ export default function initializeMockIPC(server, config) {
raw: btoa('just-a-random-string'),
},
},
{
credential_source: {
id: 'clvlt_4cvscMTl0N',
name: 'Credential Library 0',
description: 'Source Description',
credential_store_id: 'csvlt_Q1HFGt7Jpm',
type: 'vault-generic',
},
secret: {
raw: 'eyJhcnJheSI6WyJvbmUiLCJ0d28iLCJ0aHJlZSIsIm9uZSIsInR3byIsInRocmVlIiwib25lIiwidHdvIiwidGhyZWUiLCJvbmUiLCJ0d28iLCJ0aHJlZSJdLCJuZXN0ZWQiOnsiYm9vbCI6dHJ1ZSwibG9uZyI6IjEyMjM1MzQ1NmFzZWRmYTQzd3J0ZjIzNGYyM2FzZGdmYXNkZnJnYXdzZWZhd3NlZnNkZjQiLCJzZWNlcmV0Ijoic28gbmVzdGVkIn0sInRlc3QiOiJwaHJhc2UifQ',
decoded: {
data: {
backslash: 'password\\withslash\\',
backslash1: 'password\\fwithslash\\f',
password: '123',
username: 'test',
email: {
address: 'test.com',
},
},
metadata: {
created_time: '2024-04-12T18:38:36.226715555Z',
custom_metadata: null,
deletion_time: '',
destroyed: false,
version: 8,
},
},
},
},
{
credential_source: {
id: 'credjson_7cKBbBEkC3',
@@ -98,6 +129,7 @@ export default function initializeMockIPC(server, config) {
nested_secret: {
session_token: 'ZXCVBNMLKJHGFDSAQWERTYUIOP0987654321',
complex_nest: {
blackslash: 'password\\withslash\\',
hash: 'qazxswedcvfrtgbnjhyujm.1234567890',
},
},
@@ -190,6 +222,27 @@ export default function initializeMockIPC(server, config) {
isClientAgentRunning() {
return false;
}
cacheDaemonStatus() {
return { version: 'Boundary v1.0.0' };
}
getCliVersion() {
return { versionNumber: '1.0.0' };
}
getDesktopVersion() {
return { desktopVersion: '1.0.0' };
}
getLogLevel() {
return 'info';
}
getLogPath() {
return '~/.config/Boundary/logs/desktop-client.log';
}
setLogLevel() {}
clientAgentStatus() {
return { version: '0.0.1-dev', status: 'running' };
}
pauseClientAgent() {}
resumeClientAgent() {}
}
/**
+14 -17
View File
@@ -24,37 +24,38 @@
},
"dependencies": {
"dexie": "^3.2.4",
"ember-auto-import": "^2.6.3",
"ember-auto-import": "^2.8.1",
"ember-can": "^4.2.0",
"ember-cli-babel": "^7.26.10",
"ember-cli-babel": "^8.2.0",
"ember-cli-htmlbars": "^6.2.0",
"ember-cli-mirage": "^2.4.0",
"ember-cli-mirage": "^3.0.3",
"miragejs": "^0.1.48",
"ember-data": "~4.12.0",
"ember-fetch": "^8.1.1",
"tracked-built-ins": "^3.1.1"
},
"devDependencies": {
"@babel/core": "^7.21.0",
"@babel/core": "^7.25.2",
"@babel/eslint-parser": "^7.21.3",
"@babel/plugin-proposal-decorators": "^7.21.0",
"@ember/optional-features": "^2.0.0",
"@ember/string": "^3.0.1",
"@ember/test-helpers": "^2.9.3",
"@ember/test-helpers": "^4.0.4",
"@embroider/test-setup": "^2.1.1",
"@faker-js/faker": "^8.0.2",
"@glimmer/component": "^1.1.2",
"@glimmer/tracking": "^1.1.2",
"broccoli-asset-rev": "^3.0.0",
"concurrently": "^8.0.1",
"concurrently": "^9.1.0",
"doctoc": "^2.2.0",
"ember-cli": "^4.12.1",
"ember-cli-dependency-checker": "^3.3.1",
"ember-cli": "^5.12.0",
"ember-cli-dependency-checker": "^3.3.2",
"ember-cli-inject-live-reload": "^2.1.0",
"ember-cli-sri": "^2.1.1",
"ember-cli-terser": "^4.0.2",
"ember-exam": "^8.0.0",
"ember-load-initializers": "^2.1.2",
"ember-page-title": "^7.0.0",
"ember-qunit": "^6.2.0",
"ember-qunit": "^8.1.0",
"ember-resolver": "^10.0.0",
"ember-source": "~4.12.0",
"ember-source-channel-url": "^3.0.0",
@@ -64,16 +65,12 @@
"eslint-plugin-ember": "^11.11.1",
"eslint-plugin-n": "^16.3.1",
"eslint-plugin-qunit": "^8.0.1",
"@faker-js/faker": "^8.0.2",
"js-bexpr": "hashicorp/js-bexpr#9b4a4b54d85eba67fdfc0990133d1518d890b1e1",
"loader.js": "^4.7.0",
"prettier": "^3.0.0",
"qunit": "^2.19.4",
"qunit-dom": "^2.0.0",
"webpack": "^5.78.0"
},
"peerDependencies": {
"ember-source": ">4.0.0"
"qunit": "^2.22.0",
"qunit-dom": "^3.2.1",
"webpack": "^5.94.0"
},
"engines": {
"node": "18.* || 20.*"
+1 -1
View File
@@ -28,7 +28,7 @@ function setupApplicationTest(hooks, options) {
// This is also a good place to call test setup functions coming
// from other addons:
//
// setupIntl(hooks); // ember-intl
// setupIntl(hooks, 'en-us'); // ember-intl
// setupMirage(hooks); // ember-cli-mirage
}
@@ -1,42 +0,0 @@
/**
* Copyright (c) HashiCorp, Inc.
* SPDX-License-Identifier: BUSL-1.1
*/
import Application from '@ember/application';
import config from 'dummy/config/environment';
import { initialize } from 'dummy/initializers/deprecations';
import { module, test } from 'qunit';
import Resolver from 'ember-resolver';
import { run } from '@ember/runloop';
module('Unit | Initializer | deprecations', function (hooks) {
hooks.beforeEach(function () {
this.TestApplication = class TestApplication extends Application {
modulePrefix = config.modulePrefix;
podModulePrefix = config.podModulePrefix;
Resolver = Resolver;
};
this.TestApplication.initializer({
name: 'initializer under test',
initialize,
});
this.application = this.TestApplication.create({
autoboot: false,
});
});
hooks.afterEach(function () {
run(this.application, 'destroy');
});
// TODO: Replace this with your real tests.
test('it works', async function (assert) {
await this.application.boot();
assert.ok(true);
});
});
@@ -81,6 +81,19 @@ module('Unit | Model | host catalog', function (hooks) {
assert.false(modelRandom.isAzure);
});
test('it has isGCP property and return the expected values', async function (assert) {
const store = this.owner.lookup('service:store');
const modelGCP = store.createRecord('host-catalog', {
type: 'plugin',
plugin: { name: 'gcp' },
});
const modelRandom = store.createRecord('host-catalog', {
plugin: { name: 'random' },
});
assert.true(modelGCP.isGCP);
assert.false(modelRandom.isGCP);
});
test('get compositeType returns expected values', async function (assert) {
const store = this.owner.lookup('service:store');
const modelA = store.createRecord('host-catalog', {
@@ -94,8 +107,13 @@ module('Unit | Model | host catalog', function (hooks) {
type: 'plugin',
plugin: { name: 'no-such-type' },
});
const modelD = store.createRecord('host-catalog', {
type: 'plugin',
plugin: { name: 'gcp' },
});
assert.strictEqual(modelA.compositeType, 'static');
assert.strictEqual(modelB.compositeType, 'aws');
assert.strictEqual(modelD.compositeType, 'gcp');
assert.strictEqual(modelC.compositeType, 'unknown');
});
@@ -107,8 +125,12 @@ module('Unit | Model | host catalog', function (hooks) {
const modelStatic = store.createRecord('host-catalog', {
compositeType: 'static',
});
const modelGCP = store.createRecord('host-catalog', {
compositeType: 'gcp',
});
assert.strictEqual(modelPlugin.type, 'plugin');
assert.strictEqual(modelPlugin.plugin.name, 'aws');
assert.strictEqual(modelStatic.type, 'static');
assert.strictEqual(modelGCP.plugin.name, 'gcp');
});
});
@@ -5,6 +5,8 @@
import { module, test } from 'qunit';
import { setupTest } from 'ember-qunit';
import { SessionCredential } from 'api/models/session';
import { TYPE_CREDENTIAL_LIBRARY_VAULT_GENERIC } from 'api/models/credential-library';
module('Unit | Model | session', function (hooks) {
setupTest(hooks);
@@ -16,6 +18,46 @@ module('Unit | Model | session', function (hooks) {
assert.notOk(model.isAvailable);
});
test('`extractSecrets` method should return an array of secret items', function (assert) {
const sessionCredential = new SessionCredential({
credential_source: {
id: '123',
name: 'Test Source',
description: 'Test Description',
type: 'Test Type',
},
});
const secrets = {
username: 'user',
password: 'pass',
};
const formattedSecretes = sessionCredential.extractSecrets(
secrets,
TYPE_CREDENTIAL_LIBRARY_VAULT_GENERIC,
);
assert.deepEqual(formattedSecretes, [
new SessionCredential.SecretItem('username', 'user'),
new SessionCredential.SecretItem('password', 'pass'),
]);
// check for nested data, empty values should be filtered out
const nestedSecrets = {
data: { username: 'user', password: '', email: 'test.com' },
};
const formattedNestedSecrets = sessionCredential.extractSecrets(
nestedSecrets,
TYPE_CREDENTIAL_LIBRARY_VAULT_GENERIC,
);
assert.deepEqual(formattedNestedSecrets, [
new SessionCredential.SecretItem('username', 'user'),
new SessionCredential.SecretItem('email', 'test.com'),
]);
});
test('it allows cancellation of an active session', function (assert) {
let store = this.owner.lookup('service:store');
let model = store.createRecord('session', {
@@ -6,6 +6,7 @@
import { module, test } from 'qunit';
import { setupTest } from 'ember-qunit';
import { TYPE_AUTH_METHOD_OIDC } from 'api/models/auth-method';
import { TYPE_HOST_CATALOG_PLUGIN_GCP } from 'api/models/host-catalog';
module('Unit | Serializer | application', function (hooks) {
setupTest(hooks);
@@ -133,7 +134,7 @@ module('Unit | Serializer | application', function (hooks) {
});
});
test('it serializes attributes with `for` option containing array or string correctly', function (assert) {
test('it serializes attributes with `for` option containing array or string correctly for non plugins', function (assert) {
let store = this.owner.lookup('service:store');
let record = store.createRecord('auth-method', {
type: TYPE_AUTH_METHOD_OIDC, //has both string and array `for` option
@@ -184,6 +185,54 @@ module('Unit | Serializer | application', function (hooks) {
});
});
test('it serializes attributes with `for` option containing array or string correctly for plugin types', function (assert) {
let store = this.owner.lookup('service:store');
let record = store.createRecord('host-catalog', {
compositeType: TYPE_HOST_CATALOG_PLUGIN_GCP,
name: 'GCP plugin',
description: 'this is a GCP plugin host-catalog',
disable_credential_rotation: true,
worker_filter: 'workerfilter',
access_key_id: 'foobars',
secret_access_key: 'testing',
secret_id: 'a1b2c3',
secret_value: 'a1b2c3',
role_arn: 'test',
role_external_id: 'test',
role_session_name: 'test',
role_tags: [
{ key: 'Project', value: 'Automation' },
{ key: 'foo', value: 'bar' },
],
project_id: 'project',
zone: 'zone',
client_email: 'email',
target_service_account_id: 'service-account',
private_key_id: 'key-id',
private_key: 'key',
});
let serializedRecord = record.serialize();
const expectedResult = {
name: 'GCP plugin',
description: 'this is a GCP plugin host-catalog',
type: 'plugin',
worker_filter: 'workerfilter',
attributes: {
disable_credential_rotation: true,
project_id: 'project',
zone: 'zone',
target_service_account_id: 'service-account',
client_email: 'email',
},
secrets: {
private_key_id: 'key-id',
private_key: 'key',
},
};
assert.deepEqual(serializedRecord, expectedResult);
});
test('it normalizes array records from an `items` root key', function (assert) {
const store = this.owner.lookup('service:store');
const serializer = store.serializerFor('user');
@@ -5,6 +5,12 @@
import { module, test } from 'qunit';
import { setupTest } from 'ember-qunit';
import {
TYPE_HOST_CATALOG_PLUGIN_AWS,
TYPE_CREDENTIAL_STATIC,
TYPE_CREDENTIAL_DYNAMIC,
TYPE_HOST_CATALOG_PLUGIN_GCP,
} from 'api/models/host-catalog';
module('Unit | Serializer | host catalog', function (hooks) {
setupTest(hooks);
@@ -27,17 +33,153 @@ module('Unit | Serializer | host catalog', function (hooks) {
name: 'static',
description: 'this is a static host-catalog',
type: 'static',
attributes: {},
};
assert.deepEqual(record.serialize(), expectedResult);
});
test('it serializes a new aws plugin as expected, ignoring azure fields', async function (assert) {
test('it serializes a new gcp plugin as expected', async function (assert) {
const store = this.owner.lookup('service:store');
const record = store.createRecord('host-catalog', {
compositeType: 'aws',
compositeType: TYPE_HOST_CATALOG_PLUGIN_GCP,
name: 'GCP',
description: 'this is a GCP plugin host-catalog',
disable_credential_rotation: true,
worker_filter: 'workerfilter',
access_key_id: 'foobars',
secret_access_key: 'testing',
secret_id: 'a1b2c3',
secret_value: 'a1b2c3',
role_arn: 'test',
role_external_id: 'test',
role_session_name: 'test',
role_tags: [
{ key: 'Project', value: 'Automation' },
{ key: 'foo', value: 'bar' },
],
project_id: 'project',
zone: 'zone',
client_email: 'email',
target_service_account_id: 'service-account',
private_key_id: 'key-id',
private_key: 'key',
});
const expectedResult = {
name: 'GCP',
description: 'this is a GCP plugin host-catalog',
type: 'plugin',
worker_filter: 'workerfilter',
attributes: {
disable_credential_rotation: true,
project_id: 'project',
zone: 'zone',
target_service_account_id: 'service-account',
client_email: 'email',
},
secrets: {
private_key_id: 'key-id',
private_key: 'key',
},
};
assert.deepEqual(record.serialize(), expectedResult);
});
test('it serializes a new aws static plugin as expected', async function (assert) {
const store = this.owner.lookup('service:store');
const record = store.createRecord('host-catalog', {
compositeType: TYPE_HOST_CATALOG_PLUGIN_AWS,
credentialType: TYPE_CREDENTIAL_STATIC,
name: 'AWS',
description: 'this is a Aws plugin host-catalog',
disable_credential_rotation: true,
worker_filter: 'workerfilter',
region: 'west',
access_key_id: 'foobars',
secret_access_key: 'testing',
secret_id: 'a1b2c3',
secret_value: 'a1b2c3',
role_arn: 'test',
role_external_id: 'test',
role_session_name: 'test',
role_tags: [
{ key: 'Project', value: 'Automation' },
{ key: 'foo', value: 'bar' },
],
});
const expectedResult = {
name: 'AWS',
description: 'this is a Aws plugin host-catalog',
type: 'plugin',
worker_filter: 'workerfilter',
attributes: {
disable_credential_rotation: true,
region: 'west',
role_arn: null,
role_external_id: null,
role_session_name: null,
role_tags: null,
},
secrets: {
access_key_id: 'foobars',
secret_access_key: 'testing',
},
};
assert.deepEqual(record.serialize(), expectedResult);
});
test('it serializes a new aws dynamic credential type plugin as expected', async function (assert) {
const store = this.owner.lookup('service:store');
const record = store.createRecord('host-catalog', {
compositeType: TYPE_HOST_CATALOG_PLUGIN_AWS,
name: 'AWS',
credentialType: TYPE_CREDENTIAL_DYNAMIC,
description: 'this is a Aws plugin host-catalog',
disable_credential_rotation: true,
worker_filter: 'workerfilter',
// these are static AWS fields and should be excluded
region: 'west',
access_key_id: 'foobars',
secret_access_key: 'testing',
// these are Azure fields and should be excluded
tenant_id: 'a1b2c3',
client_id: 'a1b2c3',
subscription_id: 'a1b2c3',
secret_id: 'a1b2c3',
secret_value: 'a1b2c3',
role_arn: 'test',
role_external_id: 'test',
role_session_name: 'test',
role_tags: [
{ key: 'Project', value: 'Automation' },
{ key: 'foo', value: 'bar' },
],
});
const expectedResult = {
name: 'AWS',
description: 'this is a Aws plugin host-catalog',
type: 'plugin',
worker_filter: 'workerfilter',
attributes: {
disable_credential_rotation: true,
region: 'west',
role_external_id: 'test',
role_session_name: 'test',
role_arn: 'test',
role_tags: { Project: 'Automation', foo: 'bar' },
},
};
assert.deepEqual(record.serialize(), expectedResult);
});
test('it serializes a new aws static credential type plugin as expected, ignoring azure and GCP fields', async function (assert) {
const store = this.owner.lookup('service:store');
const record = store.createRecord('host-catalog', {
compositeType: TYPE_HOST_CATALOG_PLUGIN_AWS,
name: 'AWS',
credentialType: TYPE_CREDENTIAL_STATIC,
description: 'this is a Aws plugin host-catalog',
disable_credential_rotation: true,
worker_filter: 'workerfilter',
// these are AWS fields and should be included
region: 'spain',
access_key_id: 'foobars',
@@ -48,14 +190,21 @@ module('Unit | Serializer | host catalog', function (hooks) {
subscription_id: 'a1b2c3',
secret_id: 'a1b2c3',
secret_value: 'a1b2c3',
project_id: 'project',
zone: 'zone',
});
const expectedResult = {
name: 'AWS',
description: 'this is a Aws plugin host-catalog',
type: 'plugin',
worker_filter: 'workerfilter',
attributes: {
disable_credential_rotation: true,
region: 'spain',
role_arn: null,
role_external_id: null,
role_session_name: null,
role_tags: null,
},
secrets: {
access_key_id: 'foobars',
@@ -65,7 +214,7 @@ module('Unit | Serializer | host catalog', function (hooks) {
assert.deepEqual(record.serialize(), expectedResult);
});
test('it serializes a new azure record as expected, ignoring aws fields', async function (assert) {
test('it serializes a new azure record as expected, ignoring aws and GCP fields', async function (assert) {
const store = this.owner.lookup('service:store');
const record = store.createRecord('host-catalog', {
compositeType: 'azure',
@@ -75,12 +224,15 @@ module('Unit | Serializer | host catalog', function (hooks) {
region: 'spain',
access_key_id: 'foobars',
secret_access_key: 'testing',
worker_filter: 'workerfilter',
// these are Azure fields and should be excluded
tenant_id: 'a1b2c3',
client_id: 'a1b2c3',
subscription_id: 'a1b2c3',
secret_id: 'a1b2c3',
secret_value: 'a1b2c3',
project_id: 'project',
zone: 'zone',
});
const expectedResult = {
name: 'Azure',
@@ -106,6 +258,7 @@ module('Unit | Serializer | host catalog', function (hooks) {
data: {
id: '1',
type: 'host-catalog',
credentialType: 'static',
attributes: {
type: 'plugin',
name: 'aws',
@@ -113,6 +266,7 @@ module('Unit | Serializer | host catalog', function (hooks) {
plugin: {
name: 'aws',
},
worker_filter: 'workerfilter',
region: 'andorra',
},
},
@@ -122,9 +276,14 @@ module('Unit | Serializer | host catalog', function (hooks) {
type: 'plugin',
name: 'aws',
description: 'test description',
worker_filter: 'workerfilter',
attributes: {
disable_credential_rotation: false,
region: 'andorra',
role_arn: null,
role_external_id: null,
role_session_name: null,
role_tags: null,
},
};
assert.deepEqual(record.serialize(), expectedResult);
@@ -164,7 +323,7 @@ module('Unit | Serializer | host catalog', function (hooks) {
assert.deepEqual(record.serialize(), expectedResult);
});
test('it normalizes an static host catalog as expected', function (assert) {
test('it normalizes a static host catalog as expected', function (assert) {
const store = this.owner.lookup('service:store');
const serializer = store.serializerFor('host-catalog');
const hostCatalog = store.createRecord('host-catalog').constructor;
@@ -193,6 +352,8 @@ module('Unit | Serializer | host catalog', function (hooks) {
secret_access_key: null,
secret_id: null,
secret_value: null,
private_key_id: null,
private_key: null,
},
relationships: {},
},
@@ -215,6 +376,7 @@ module('Unit | Serializer | host catalog', function (hooks) {
name: 'aws',
description: 'aws host catalog',
},
worker_filter: 'workerfilter',
attributes: {
disable_credential_rotation: false,
region: 'Illinois',
@@ -238,6 +400,7 @@ module('Unit | Serializer | host catalog', function (hooks) {
type: 'plugin',
description: 'Test description',
authorized_actions: ['no-op'],
worker_filter: 'workerfilter',
plugin: {
id: 'plugin-id-5',
name: 'aws',
@@ -249,6 +412,8 @@ module('Unit | Serializer | host catalog', function (hooks) {
secret_access_key: 'zq{2:IVc8@W^',
secret_id: null,
secret_value: null,
private_key_id: null,
private_key: null,
},
relationships: {},
},
@@ -309,6 +474,70 @@ module('Unit | Serializer | host catalog', function (hooks) {
subscription_id: 'subscription',
access_key_id: null,
secret_access_key: null,
private_key_id: null,
private_key: null,
},
relationships: {},
},
included: [],
});
});
test('it normalizes a GCP plugin type host catalog as expected', function (assert) {
const store = this.owner.lookup('service:store');
const serializer = store.serializerFor('host-catalog');
const hostCatalog = store.createRecord('host-catalog').constructor;
const payload = {
id: '1',
name: 'Host catalog test',
description: 'Test description',
authorized_actions: ['no-op', 'read', 'update', 'delete'],
type: 'plugin',
plugin: {
id: 'plugin-id-7',
name: 'gcp',
description: 'gcp host catalog',
},
attributes: {
disable_credential_rotation: true,
project_id: 'project_id',
zone: 'zone',
target_service_account_id: 'target_service_account_id',
},
secrets: {
private_key_id: '0xF3B0a6f8',
private_key: 'zq{2:IVc8@W^',
},
};
const normalized = serializer.normalizeSingleResponse(
store,
hostCatalog,
payload,
);
assert.deepEqual(normalized, {
data: {
id: '1',
type: 'host-catalog',
attributes: {
name: 'Host catalog test',
type: 'plugin',
description: 'Test description',
authorized_actions: ['no-op', 'read', 'update', 'delete'],
plugin: {
id: 'plugin-id-7',
name: 'gcp',
description: 'gcp host catalog',
},
disable_credential_rotation: true,
private_key_id: '0xF3B0a6f8',
private_key: 'zq{2:IVc8@W^',
project_id: 'project_id',
zone: 'zone',
target_service_account_id: 'target_service_account_id',
access_key_id: null,
secret_access_key: null,
secret_id: null,
secret_value: null,
},
relationships: {},
},
@@ -12,7 +12,6 @@ class SessionService extends Service {}
module('Unit | Service | indexed-db', function (hooks) {
setupTest(hooks);
// TODO: Replace this with your real tests.
test('it exists', function (assert) {
this.owner.register('service:session', SessionService);
@@ -9,7 +9,6 @@ import { setupTest } from 'dummy/tests/helpers';
module('Unit | Service | store', function (hooks) {
setupTest(hooks);
// TODO: Replace this with your real tests.
test('it exists', function (assert) {
let service = this.owner.lookup('service:store');
assert.ok(service);
@@ -0,0 +1,47 @@
/**
* Copyright (c) HashiCorp, Inc.
* SPDX-License-Identifier: BUSL-1.1
*/
import { flattenObject } from 'api/utils/flatten-nested-object';
import { module, test } from 'qunit';
module('Unit | Utility | flatten-nested-object', function () {
test('it flattens a nested object to single level object', function (assert) {
const input = {
a: 1,
b: { c: 2, d: 3, e: { f: { g: { h: 10 } } } },
};
const expected = {
a: 1,
'b.c': 2,
'b.d': 3,
'b.e.f.g.h': 10,
};
assert.deepEqual(flattenObject(input), expected);
});
test('removes keys with null/empty values', function (assert) {
const inputOne = {
a: null,
b: { c: 2 },
d: {
e: { f: { g: { h: '' } } },
},
i: 0,
j: false,
};
const inputTwo = {
d: { e: null },
};
const expectedResultOne = {
'b.c': 2,
i: 0,
j: false,
};
const expectedResultTwo = {};
assert.deepEqual(flattenObject(inputOne), expectedResultOne);
assert.deepEqual(flattenObject(inputTwo), expectedResultTwo);
});
});
@@ -11,6 +11,7 @@ import { setupIndexedDb } from 'api/test-support/helpers/indexed-db';
import { pluralize } from 'ember-inflector';
import { camelize } from '@ember/string';
import { TYPE_TARGET_TCP, TYPE_TARGET_SSH } from 'api/models/target';
import { faker } from '@faker-js/faker';
const seedIndexDb = async (resource, store, indexedDb, server) => {
const resourceData =
@@ -529,4 +530,80 @@ module('Unit | Utility | indexed-db-query', function (hooks) {
assert.strictEqual(result.length, 0);
});
test('it filters on date type fields and returns results', async function (assert) {
const pastDate = new Date('2024-09-19T10:00:00.000Z');
const createdTime = new Date('2024-09-23T10:00:00.000Z');
this.server.create('session-recording', {
created_time: createdTime,
});
await seedIndexDb('session-recording', store, indexedDb, this.server);
const query = { filters: { created_time: [{ gte: pastDate }] } };
const result = await queryIndexedDb(
indexedDb.db,
'session-recording',
query,
);
assert.strictEqual(result.length, 1);
});
test('it filters on date type fields and returns results - from and to', async function (assert) {
const from = new Date('2024-09-19T10:00:00.000Z');
const to = new Date('2024-09-25T10:00:00.000Z');
const createdTime = new Date('2024-09-23T10:00:00.000Z');
const createdTime2 = new Date('2024-09-28T10:00:00.000Z');
this.server.create('session-recording', {
created_time: createdTime,
});
this.server.create('session-recording', {
created_time: createdTime2,
});
await seedIndexDb('session-recording', store, indexedDb, this.server);
const query = {
filters: {
created_time: {
logicalOperator: 'and',
values: [{ gte: from }, { lte: to }],
},
},
};
const result = await queryIndexedDb(
indexedDb.db,
'session-recording',
query,
);
assert.strictEqual(result.length, 1);
assert.strictEqual(
result[0].attributes.created_time.toISOString(),
createdTime.toISOString(),
);
});
test('it filters on date type fields and returns no results', async function (assert) {
const createdTime = faker.date.between({
from: '2024-09-19T00:00:00.000Z',
to: '2024-09-20T00:00:00.000Z',
});
const pastDate = faker.date.between({
from: '2024-09-23T00:00:00.000Z',
to: '2024-09-24T00:00:00.000Z',
});
this.server.create('session-recording', {
created_time: createdTime,
});
await seedIndexDb('session-recording', store, indexedDb, this.server);
const query = { filters: { created_time: [{ gte: pastDate }] } };
const result = await queryIndexedDb(
indexedDb.db,
'session-recording',
query,
);
assert.strictEqual(result.length, 0);
});
});
+25 -12
View File
@@ -5,7 +5,7 @@
import SimpleAuthBaseAuthenticator from 'ember-simple-auth/authenticators/base';
import { resolve, reject } from 'rsvp';
import fetch from 'fetch';
import { waitForPromise } from '@ember/test-waiters';
/**
* Encapsulates common authenticator functionality.
@@ -58,10 +58,21 @@ export default class BaseAuthenticator extends SimpleAuthBaseAuthenticator {
*/
async validateToken(token, tokenID) {
const tokenValidationURL = this.buildTokenValidationEndpointURL(tokenID);
const response = await fetch(tokenValidationURL, {
method: 'get',
headers: { Authorization: `Bearer ${token}` },
});
// Note: waitForPromise is needed to provide the necessary integration with @ember/test-helpers
// visit https://www.npmjs.com/package/@ember/test-waiters for more info.
const response = await waitForPromise(
fetch(tokenValidationURL, {
method: 'get',
headers: { Authorization: `Bearer ${token}` },
}),
);
// Note: Always consume response body in order to avoid memory leaks
// visit https://undici.nodejs.org/#/?id=garbage-collection for more info.
// We do not use the undici package but the link informs us that garbage
// collection is undefined when response body is not consumed.
await response.json();
// 401 and 404 responses mean the token is invalid, whereas other types of
// error responses do not tell us about the validity of the token.
if (response.status === 401 || response.status === 404) return reject();
@@ -103,7 +114,7 @@ export default class BaseAuthenticator extends SimpleAuthBaseAuthenticator {
}
/**
* Posts to the `deauthEntpoint` on a best-effort basis and then returns.
* Posts to the `deauthEndpoint` on a best-effort basis and then returns.
* Deauthentication with the server is not guaranteed and request failures
* are ignored.
*
@@ -113,12 +124,14 @@ export default class BaseAuthenticator extends SimpleAuthBaseAuthenticator {
async invalidate(options) {
const { token } = options;
const deauthEndpointURL = this.buildDeauthEndpointURL(options);
await fetch(deauthEndpointURL, {
method: 'delete',
headers: { Authorization: `Bearer ${token}` },
}).catch(() => {
/* no op */
});
await waitForPromise(
fetch(deauthEndpointURL, {
method: 'delete',
headers: { Authorization: `Bearer ${token}` },
}).catch(() => {
/* no op */
}),
);
return super.invalidate(...arguments);
}
}
+13 -5
View File
@@ -6,10 +6,10 @@
import BaseAuthenticator from './base';
import { inject as service } from '@ember/service';
import { reject } from 'rsvp';
import fetch from 'fetch';
import { waitForPromise } from '@ember/test-waiters';
/**
* The OIDC base authenticator encapsulates the multistep OIDC flow.
* The OIDC base authenticator encapsulates the multi-step OIDC flow.
*
* 1. Start authentication flow: this step is actually a combination of two
* sub steps:
@@ -47,7 +47,9 @@ export default class OIDCAuthenticator extends BaseAuthenticator {
async startAuthentication(options) {
const url = this.buildAuthEndpointURL(options);
const body = JSON.stringify({ command: 'start' });
const response = await fetch(url, { method: 'post', body });
// Note: waitForPromise is needed to provide the necessary integration with @ember/test-helpers
// visit https://www.npmjs.com/package/@ember/test-waiters for more info.
const response = await waitForPromise(fetch(url, { method: 'post', body }));
const json = await response.json();
if (response.status < 400) {
// Store meta about the pending OIDC flow
@@ -94,14 +96,20 @@ export default class OIDCAuthenticator extends BaseAuthenticator {
},
});
// Fetch the endpoint and get the response JSON
const response = await fetch(url, { method: 'post', body });
const response = await waitForPromise(fetch(url, { method: 'post', body }));
// Note: Always consume response body in order to avoid memory leaks
// visit https://undici.nodejs.org/#/?id=garbage-collection for more info.
// We do not use the undici package but the link informs us that garbage
// collection is undefined when response body is not consumed.
const json = await response.json();
if (response.status === 202) {
// The token isn't ready yet, keep trying.
return false;
} else if (response.status < 400) {
// Response was successful, meaning a token was obtained.
// Authenticate with the session service using the response JSON.
const json = await response.json();
await this.session.authenticate('authenticator:oidc', json);
return true;
} else {
+6 -2
View File
@@ -5,7 +5,7 @@
import BaseAuthenticator from './base';
import { resolve, reject } from 'rsvp';
import fetch from 'fetch';
import { waitForPromise } from '@ember/test-waiters';
/**
*
@@ -66,7 +66,11 @@ export default class PasswordAuthenticator extends BaseAuthenticator {
attributes: { login_name, password },
});
const authEndpointURL = this.buildAuthEndpointURL(options);
const response = await fetch(authEndpointURL, { method: 'post', body });
// Note: waitForPromise is needed to provide the necessary integration with @ember/test-helpers
// visit https://www.npmjs.com/package/@ember/test-waiters for more info.
const response = await waitForPromise(
fetch(authEndpointURL, { method: 'post', body }),
);
const json = await response.json();
return response.status < 400
? resolve(this.normalizeData(json, login_name))
+14 -13
View File
@@ -21,35 +21,36 @@
"doc:toc": "doctoc README.md"
},
"dependencies": {
"ember-cli-babel": "^7.26.11",
"ember-auto-import": "2.8.1",
"ember-cli-babel": "^8.2.0",
"ember-cli-htmlbars": "^6.2.0",
"ember-fetch": "^8.1.1",
"ember-simple-auth": "^4.2.2"
"ember-simple-auth": "^6.1.0"
},
"devDependencies": {
"@babel/core": "^7.25.2",
"@babel/eslint-parser": "^7.21.3",
"@babel/plugin-proposal-decorators": "^7.21.0",
"@ember/optional-features": "^2.0.0",
"@ember/string": "^3.0.1",
"@ember/test-helpers": "^2.9.3",
"@ember/test-helpers": "^4.0.4",
"@ember/test-waiters": "^3.1.0",
"@embroider/test-setup": "^2.1.1",
"@glimmer/component": "^1.1.2",
"@glimmer/tracking": "^1.1.2",
"broccoli-asset-rev": "^3.0.0",
"concurrently": "^8.0.1",
"concurrently": "^9.1.0",
"doctoc": "^2.2.0",
"ember-auto-import": "^2.6.3",
"ember-cli": "^4.12.2",
"ember-cli-dependency-checker": "^3.3.1",
"ember-cli": "^5.12.0",
"ember-cli-dependency-checker": "^3.3.2",
"ember-cli-inject-live-reload": "^2.1.0",
"ember-cli-sri": "^2.1.1",
"ember-cli-terser": "^4.0.2",
"ember-cookies": "^0.5.2",
"ember-cookies": "^1.2.0",
"ember-disable-prototype-extensions": "^1.1.3",
"ember-export-application-global": "^2.0.1",
"ember-load-initializers": "^2.1.2",
"ember-page-title": "^7.0.0",
"ember-qunit": "^6.2.0",
"ember-qunit": "^8.1.0",
"ember-resolver": "^10.0.0",
"ember-source": "~4.12.0",
"ember-source-channel-url": "^3.0.0",
@@ -62,9 +63,9 @@
"loader.js": "^4.7.0",
"pretender": "^3.4.3",
"prettier": "^3.0.0",
"qunit": "^2.19.4",
"qunit-dom": "^2.0.0",
"webpack": "^5.78.0"
"qunit": "^2.22.0",
"qunit-dom": "^3.2.1",
"webpack": "^5.94.0"
},
"engines": {
"node": "18.* || 20.*"
+1 -1
View File
@@ -28,7 +28,7 @@ function setupApplicationTest(hooks, options) {
// This is also a good place to call test setup functions coming
// from other addons:
//
// setupIntl(hooks); // ember-intl
// setupIntl(hooks, 'en-us'); // ember-intl
// setupMirage(hooks); // ember-cli-mirage
}
@@ -52,7 +52,7 @@ module('Unit | Authenticator | base', function (hooks) {
const authenticator = this.owner.lookup('authenticator:base');
server.get(authenticator.buildTokenValidationEndpointURL(id), () => {
assert.ok(true, 'token validation was requested');
return [200];
return [200, {}, '{}'];
});
await authenticator.restore(mockData);
});
@@ -64,7 +64,7 @@ module('Unit | Authenticator | base', function (hooks) {
const authenticator = this.owner.lookup('authenticator:base');
server.get(authenticator.buildTokenValidationEndpointURL(id), () => {
assert.ok(true, 'token validation was requested');
return [401];
return [401, {}, '{}'];
});
try {
await authenticator.restore(mockData);
@@ -80,7 +80,7 @@ module('Unit | Authenticator | base', function (hooks) {
const authenticator = this.owner.lookup('authenticator:base');
server.get(authenticator.buildTokenValidationEndpointURL(id), () => {
assert.ok(true, 'token validation was requested');
return [404];
return [404, {}, '{}'];
});
try {
await authenticator.restore(mockData);
@@ -3,16 +3,21 @@
SPDX-License-Identifier: BUSL-1.1
}}
<Rose::Message
@title={{t (concat 'errors.' this.messageCode '.title')}}
@subtitle={{concat (t 'errors.generic.title') ' ' @status}}
@icon={{this.icon}}
as |message|
>
<message.description>
{{t (concat 'errors.' this.messageCode '.description')}}
</message.description>
{{#if this.helpRoute}}
<message.link @route={{this.helpRoute}}>{{t 'actions.help'}}</message.link>
<Hds::ApplicationState data-test-error-application-state as |A|>
<A.Header
@title={{t (concat 'errors.' this.messageCode '.title')}}
@icon={{this.icon}}
@errorCode={{@status}}
/>
<A.Body @text={{t (concat 'errors.' this.messageCode '.description')}} />
{{#if @docLink}}
<A.Footer as |F|>
<F.LinkStandalone
@icon='help'
@text={{t 'actions.help'}}
@href={{@docLink}}
@iconPosition='trailing'
/>
</A.Footer>
{{/if}}
</Rose::Message>
</Hds::ApplicationState>
@@ -3,8 +3,7 @@
* SPDX-License-Identifier: BUSL-1.1
*/
import MessageComponent from 'rose/components/rose/message';
import { computed } from '@ember/object';
import Component from '@glimmer/component';
/*
* Helpful error booleans are attached based on the error status code:
@@ -22,40 +21,29 @@ import { computed } from '@ember/object';
const statuses = ['401', '403', '404', '500'];
export default class ErrorMessageComponent extends MessageComponent {
export default class ErrorMessageComponent extends Component {
// =methods
/**
* Returns an icon for error status.
* @return {string}
*/
@computed('args.status')
get icon() {
switch (this.args.status) {
case '404':
return 'flight-icons/svg/help-16';
return 'help';
case '401':
case '403':
default:
return 'flight-icons/svg/alert-circle-16';
return 'alert-circle';
}
}
// TODO: Enable when help documentation can be linked in.
/**
* Returns an route string for help text in message.
* @return {string}
*/
// get helpRoute() {
// return 'index'
// }
/**
* Returns 'unknown' status code when provided error status
* isn't part of predefined statuses.
* @return {string}
*/
@computed('args.status')
get messageCode() {
let messageCode = this.args.status;
if (!statuses.includes(messageCode)) messageCode = 'unknown';
@@ -3,17 +3,10 @@
SPDX-License-Identifier: BUSL-1.1
}}
<Rose::Button
...attributes
@style='inline-link-action'
@iconLeft={{if
this.isLoading
'flight-icons/svg/loading-16'
'flight-icons/svg/reload-16'
}}
class={{if this.isLoading 'loading-button is-loading' 'loading-button'}}
<Hds::Button
@text={{t 'actions.refresh'}}
@color='secondary'
@icon={{if this.isLoading 'loading' 'reload'}}
@disabled={{this.isLoading}}
{{on 'click' this.toggleRefresh}}
>
{{yield}}
</Rose::Button>
/>
@@ -3,12 +3,17 @@
SPDX-License-Identifier: BUSL-1.1
}}
{{#if this.lastRefreshed}}
<Rose::Toolbar::Info>
{{relative-datetime-live this.lastRefreshed}}
</Rose::Toolbar::Info>
{{/if}}
<LoadingButton @onClick={{this.onClick}}>
{{t 'actions.refresh'}}
</LoadingButton>
<div class='toolbar-refresher'>
{{#if (has-block)}}
{{yield}}
{{else}}
{{#if this.lastRefreshed}}
<Hds::Text::Body @tag='p' @color='faint'>
{{relative-datetime-live this.lastRefreshed}}
</Hds::Text::Body>
{{/if}}
{{/if}}
<LoadingButton @onClick={{this.onClick}}>
{{t 'actions.refresh'}}
</LoadingButton>
</div>
@@ -15,7 +15,7 @@ export default class ToolbarRefresherComponent extends Component {
// =methods
/**
* Executes the click handler argument and trackes the time it completed.
* Executes the click handler argument and tracks the time it completed.
*/
@action
async onClick() {
@@ -5,7 +5,8 @@
import Helper from '@ember/component/helper';
import { inject as service } from '@ember/service';
import DurationUnitFormat from 'intl-unofficial-duration-unit-format';
import { DurationFormat } from '@formatjs/intl-durationformat';
import { secondsToDuration } from 'core/utils/seconds-to-duration';
export default class extends Helper {
// =services
@@ -19,12 +20,10 @@ export default class extends Helper {
*/
compute([durationInMs]) {
const durationInSeconds = durationInMs / 1000;
const durationFormat = new DurationUnitFormat(this.intl.primaryLocale, {
const durationFormat = new DurationFormat(this.intl.primaryLocale, {
style: 'narrow',
format: '{days} {hours} {minutes} {seconds}',
round: true,
});
return durationFormat.format(durationInSeconds);
return durationFormat.format(secondsToDuration(durationInSeconds));
}
}
-69
View File
@@ -1,69 +0,0 @@
/**
* Copyright (c) HashiCorp, Inc.
* SPDX-License-Identifier: BUSL-1.1
*/
import Helper from '@ember/component/helper';
import { inject as service } from '@ember/service';
import { join } from '@ember/runloop';
import { runInDebug, assert } from '@ember/debug';
import { A } from '@ember/array';
/**
* This helper is a modern update on ember-route-action-helper, which is
* now unmaintained.
*
* See https://github.com/DockYard/ember-route-action-helper
*/
export default class RouteActionHelper extends Helper {
// =services
@service router;
// =attributes
get routes() {
const { currentInfos, mapBy } = this.currentInfos;
return A(currentInfos).mapBy(mapBy).reverse();
}
get currentInfos() {
// eslint-disable-next-line ember/no-private-routing-service
const routerLib = this.router._router._routerMicrolib;
return {
currentInfos:
routerLib.currentRouteInfos || routerLib.currentHandlerInfos,
mapBy: (routerLib.currentRouteInfos && 'route') || 'handler',
};
}
// =methods
compute([actionName, ...outerArgs]) {
const { action, handler } = this.getRouteWithAction(actionName);
runInDebug(() => {
assert(
`
[boundary-core-helper-route-action]
Unable to find action ${actionName}
`,
handler,
);
});
return (...innerArgs) =>
join(handler, action, ...outerArgs.concat(innerArgs));
}
getRouteWithAction(actionName) {
let action;
const handler = A(this.routes).find((route) => {
const actions = route.actions || route._actions;
action = actions[actionName];
return typeof action === 'function';
});
return { action, handler };
}
}
+8 -8
View File
@@ -5,7 +5,8 @@
import Helper from '@ember/component/helper';
import { inject as service } from '@ember/service';
import DurationUnitFormat from 'intl-unofficial-duration-unit-format';
import { DurationFormat } from '@formatjs/intl-durationformat';
import { secondsToDuration } from 'core/utils/seconds-to-duration';
export default class extends Helper {
// =services
@@ -29,14 +30,13 @@ export default class extends Helper {
difference > 0 ? Math.floor(difference / 1000) : 0;
// Format the duration
const duration = new DurationUnitFormat(this.intl.primaryLocale, {
style: 'timer',
format: `{hours}:{minutes}:{seconds} ${this.intl.t(
'resources.session.remaining',
)}`,
const duration = new DurationFormat(this.intl.primaryLocale, {
style: 'digital',
});
const formattedTime = duration.format(
secondsToDuration(differenceInSeconds),
);
// Return the formatted duration
return duration.format(differenceInSeconds);
return `${formattedTime} ${this.intl.t('resources.session.remaining')}`;
}
}
+23 -18
View File
@@ -7,7 +7,6 @@
display: flex;
flex-wrap: wrap;
align-items: center;
margin-bottom: 1rem;
gap: 0.5rem;
.filter-tag {
@@ -27,33 +26,20 @@
margin-top: 3rem;
}
.hds-segmented-group {
> div,
table {
margin-bottom: 1rem;
}
.hds-segmented-group {
.hds-dropdown-toggle-button__text {
white-space: nowrap;
}
}
.hds-table {
margin-bottom: 1rem;
}
.search-filtering-toolbar {
display: flex;
// TODO: Remove these copied styles by migrating to HDS for the toolbar refresher component.
// The original styles assumed we were using the old toolbar component under a "rose-toolbar" class.
.rose-button-inline-link-action {
font-size: 0.8125rem;
line-height: 1.8461538462;
font-weight: 600;
color: var(--stark);
display: inline-block;
vertical-align: middle;
padding: 0.375rem 1rem;
}
> :last-child {
margin-left: auto;
}
@@ -67,3 +53,22 @@
color: var(--token-color-foreground-primary);
}
}
.toolbar-refresher {
display: flex;
align-items: center;
padding-left: 1rem;
gap: 1rem;
> .hds-text {
white-space: nowrap;
overflow: hidden;
}
}
// Utility classes
.container-inputs__margin-bottom {
input:not(:last-child) {
margin-bottom: 0.5rem;
}
}
@@ -0,0 +1,27 @@
/**
* Copyright (c) HashiCorp, Inc.
* SPDX-License-Identifier: BUSL-1.1
*/
/**
* Takes in the number of seconds and converts to an object with corresponding
* values for each time duration. For example:
* { weeks: 0, days: 0, hours: 22, minutes: 15, seconds: 11 }
* @param {number} value
* @returns {object}
*/
export const secondsToDuration = (value) => {
const second = 1;
const minute = second * 60;
const hour = minute * 60;
const day = hour * 24;
const week = day * 7;
const weeks = Math.max(Math.floor(value / week), 0);
const days = Math.max(Math.floor((value % week) / day), 0);
const hours = Math.max(Math.floor((value % day) / hour), 0);
const minutes = Math.max(Math.floor((value % hour) / minute), 0);
const seconds = Math.max(Math.floor((value % minute) / second), 0);
return { weeks, days, hours, minutes, seconds };
};
@@ -3,4 +3,4 @@
* SPDX-License-Identifier: BUSL-1.1
*/
export { default } from 'core/helpers/route-action';
export { default } from 'core/utils/seconds-to-duration';
+14 -17
View File
@@ -31,19 +31,20 @@
"doc:toc": "doctoc README.md"
},
"dependencies": {
"@formatjs/intl-durationformat": "^0.2.4",
"api": "*",
"auth": "*",
"ember-auto-import": "^2.6.3",
"ember-auto-import": "^2.8.1",
"ember-browser-services": "^4.0.3",
"ember-cli-babel": "^7.26.11",
"ember-cli-babel": "^8.2.0",
"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-intl": "^7.0.7",
"ember-loading": "^2.0.0",
"ember-truth-helpers": "^3.0.0",
"filesize": "^10.0.7",
"intl-unofficial-duration-unit-format": "^3.1.0",
"lodash": "^4.17.21",
"sass": "^1.69.5"
},
"devDependencies": {
@@ -51,23 +52,23 @@
"@babel/plugin-proposal-decorators": "^7.21.0",
"@ember/optional-features": "^2.0.0",
"@ember/string": "^3.0.1",
"@ember/test-helpers": "^2.9.3",
"@ember/test-helpers": "^4.0.4",
"@embroider/test-setup": "^2.1.1",
"@faker-js/faker": "^8.0.2",
"@glimmer/component": "^1.1.2",
"@glimmer/tracking": "^1.1.2",
"broccoli-asset-rev": "^3.0.0",
"concurrently": "^8.0.1",
"concurrently": "^9.1.0",
"doctoc": "^2.2.0",
"ember-cli": "^4.12.2",
"ember-cli-dependency-checker": "^3.3.1",
"ember-cli": "^5.12.0",
"ember-cli-dependency-checker": "^3.3.2",
"ember-cli-inject-live-reload": "^2.1.0",
"ember-cli-sri": "^2.1.1",
"ember-cli-terser": "^4.0.2",
"ember-inline-svg": "^1.0.1",
"ember-load-initializers": "^2.1.2",
"ember-page-title": "^7.0.0",
"ember-qunit": "^6.2.0",
"ember-qunit": "^8.1.0",
"ember-resolver": "^10.0.0",
"ember-source": "~4.12.0",
"ember-source-channel-url": "^3.0.0",
@@ -81,15 +82,11 @@
"js-bexpr": "hashicorp/js-bexpr#9b4a4b54d85eba67fdfc0990133d1518d890b1e1",
"loader.js": "^4.7.0",
"prettier": "^3.0.0",
"qunit": "^2.19.4",
"qunit-dom": "^2.0.0",
"qunit": "^2.22.0",
"qunit-dom": "^3.2.1",
"rose": "*",
"sinon": "^17.0.1",
"webpack": "^5.78.0"
},
"peerDependencies": {
"ember-source": "^4.0.0",
"lodash": "^4.17.21"
"sinon": "^19.0.2",
"webpack": "^5.94.0"
},
"engines": {
"node": "18.* || 20.*"
+1 -1
View File
@@ -28,7 +28,7 @@ function setupApplicationTest(hooks, options) {
// This is also a good place to call test setup functions coming
// from other addons:
//
// setupIntl(hooks); // ember-intl
// setupIntl(hooks, 'en-us'); // ember-intl
// setupMirage(hooks); // ember-cli-mirage
}
@@ -11,7 +11,7 @@ import { hbs } from 'ember-cli-htmlbars';
module('Integration | Component | dropdown/index', function (hooks) {
setupRenderingTest(hooks);
setupIntl(hooks);
setupIntl(hooks, 'en-us');
const firstItem = {
id: '1',
@@ -5,69 +5,73 @@
import { module, test } from 'qunit';
import { setupRenderingTest } from 'ember-qunit';
import { render, find } from '@ember/test-helpers';
import { render } from '@ember/test-helpers';
import { hbs } from 'ember-cli-htmlbars';
import { setupIntl } from 'ember-intl/test-support';
module('Integration | Component | error/message', function (hooks) {
setupRenderingTest(hooks);
setupIntl(hooks);
setupIntl(hooks, 'en-us');
const ERROR_MSG_TITLE =
'[data-test-error-application-state] .hds-application-state__title';
const ERROR_MSG_CODE =
'[data-test-error-application-state] .hds-application-state__error-code';
const ERROR_MSG_BODY =
'[data-test-error-application-state] .hds-application-state__body-text';
const ERROR_MSG_LINK =
'[data-test-error-application-state] .hds-link-standalone';
const ERROR_MSG_LINK_TEXT =
'[data-test-error-application-state] .hds-link-standalone__text';
test('it renders predefined message for known error status', async function (assert) {
await render(hbs`<Error::Message @status='401' />`);
assert.strictEqual(
find('.rose-message-title').textContent.trim(),
'You are not signed in',
);
assert.strictEqual(
find('.rose-message-subtitle').textContent.trim(),
'Error 401',
);
assert.strictEqual(
find('.rose-message-description').textContent.trim(),
'You are not signed in. Please sign in and try again later.',
);
assert.dom(ERROR_MSG_TITLE).hasText('You are not signed in');
assert.dom(ERROR_MSG_CODE).hasText('ERROR 401');
assert
.dom(ERROR_MSG_BODY)
.hasText('You are not signed in. Please sign in and try again later.');
await render(hbs`<Error::Message @status='403' />`);
assert.strictEqual(
find('.rose-message-title').textContent.trim(),
'You are not authorized',
);
assert.strictEqual(
find('.rose-message-subtitle').textContent.trim(),
'Error 403',
);
assert.strictEqual(
find('.rose-message-description').textContent.trim(),
'You must be granted permissions to view this data. Ask your administrator if you think you should have access.',
);
assert.dom(ERROR_MSG_TITLE).hasText('You are not authorized');
assert.dom(ERROR_MSG_CODE).hasText('ERROR 403');
assert
.dom(ERROR_MSG_BODY)
.hasText(
'You must be granted permissions to view this data. Ask your administrator if you think you should have access.',
);
await render(hbs`<Error::Message @status='404' />`);
assert.strictEqual(
find('.rose-message-title').textContent.trim(),
'Resource not found',
);
assert.strictEqual(
find('.rose-message-subtitle').textContent.trim(),
'Error 404',
);
assert.strictEqual(
find('.rose-message-description').textContent.trim(),
'We could not find the requested resource. You can ask your administrator or try again later.',
);
assert.dom(ERROR_MSG_TITLE).hasText('Resource not found');
assert.dom(ERROR_MSG_CODE).hasText('ERROR 404');
assert
.dom(ERROR_MSG_BODY)
.hasText(
'We could not find the requested resource. You can ask your administrator or try again later.',
);
});
test('it renders default error for unknown error status', async function (assert) {
await render(hbs`<Error::Message @status='599' />`);
assert.strictEqual(
find('.rose-message-title').textContent.trim(),
'Something went wrong',
);
assert.strictEqual(
find('.rose-message-subtitle').textContent.trim(),
'Error 599',
);
assert.strictEqual(
find('.rose-message-description').textContent.trim(),
"We're not sure what happened. Please contact your administrator or try again later.",
assert.dom(ERROR_MSG_TITLE).hasText('Something went wrong');
assert.dom(ERROR_MSG_CODE).hasText('ERROR 599');
assert
.dom(ERROR_MSG_BODY)
.hasText(
"We're not sure what happened. Please contact your administrator or try again later.",
);
});
test('it renders help link with provided doc url', async function (assert) {
await render(
hbs`<Error::Message @status='599' @docLink='https://support' />`,
);
assert.dom(ERROR_MSG_LINK_TEXT).hasText('Need help');
assert.dom(ERROR_MSG_LINK).hasAttribute('href', 'https://support');
});
});
@@ -11,7 +11,7 @@ import { hbs } from 'ember-cli-htmlbars';
module('Integration | Component | filter-tags/index', function (hooks) {
setupRenderingTest(hooks);
setupIntl(hooks);
setupIntl(hooks, 'en-us');
test('it renders', async function (assert) {
this.set('filter', {
@@ -16,7 +16,7 @@ import {
module('Integration | Component | form | authenticate', function (hooks) {
setupRenderingTest(hooks);
setupIntl(hooks);
setupIntl(hooks, 'en-us');
test('it shows login name and password when LDAP is selected from the list', async function (assert) {
const store = this.owner.lookup('service:store');
@@ -7,19 +7,22 @@ import { module, test } from 'qunit';
import { setupRenderingTest } from 'ember-qunit';
import { render, find, click } from '@ember/test-helpers';
import { hbs } from 'ember-cli-htmlbars';
import { setupIntl } from 'ember-intl/test-support';
module('Integration | Component | loading-button', function (hooks) {
setupRenderingTest(hooks);
setupIntl(hooks, 'en-us');
test('it renders', async function (assert) {
await render(hbs`<LoadingButton />`);
assert.ok(find('.loading-button'));
assert.ok(find('.hds-button'));
});
test('it executes a function on refresh button click', async function (assert) {
assert.expect(2);
this.onClick = () => assert.ok(true, 'refresh was clicked');
await render(hbs`<LoadingButton @onClick={{this.onClick}} />`);
assert.ok(find('.loading-button'));
assert.ok(find('.hds-button'));
await click('button');
});
});
@@ -15,7 +15,7 @@ module('Integration | Component | session-status', function (hooks) {
const store = this.owner.lookup('service:store');
this.model = store.createRecord('session', { status: 'active' });
await render(hbs`<SessionStatus @model={{this.model}} />`);
assert.ok(find('.flight-icon-check'));
assert.ok(find('.hds-icon-check'));
assert.ok(find('.hds-badge--color-success'));
assert.ok(find('.hds-badge--type-filled'));
});
@@ -24,7 +24,7 @@ module('Integration | Component | session-status', function (hooks) {
const store = this.owner.lookup('service:store');
this.model = store.createRecord('session', { status: 'canceling' });
await render(hbs`<SessionStatus @model={{this.model}} />`);
assert.ok(find('.flight-icon-alert-triangle'));
assert.ok(find('.hds-icon-alert-triangle'));
assert.ok(find('.hds-badge--color-warning'));
assert.ok(find('.hds-badge--type-filled'));
});
@@ -33,7 +33,7 @@ module('Integration | Component | session-status', function (hooks) {
const store = this.owner.lookup('service:store');
this.model = store.createRecord('session', { status: 'terminated' });
await render(hbs`<SessionStatus @model={{this.model}} />`);
assert.ok(find('.flight-icon-x'));
assert.ok(find('.hds-icon-x'));
assert.ok(find('.hds-badge--color-critical'));
assert.ok(find('.hds-badge--type-filled'));
});
@@ -42,7 +42,7 @@ module('Integration | Component | session-status', function (hooks) {
const store = this.owner.lookup('service:store');
this.model = store.createRecord('session', { status: 'pending' });
await render(hbs`<SessionStatus @model={{this.model}} />`);
assert.ok(find('.flight-icon-delay'));
assert.ok(find('.hds-icon-delay'));
assert.ok(find('.hds-badge--color-neutral'));
assert.ok(find('.hds-badge--type-filled'));
});
@@ -51,7 +51,7 @@ module('Integration | Component | session-status', function (hooks) {
const store = this.owner.lookup('service:store');
this.model = store.createRecord('session', { status: 'any string' });
await render(hbs`<SessionStatus @model={{this.model}} />`);
assert.notOk(find('.flight-icon'));
assert.notOk(find('.hds-icon'));
assert.ok(find('.hds-badge--color-neutral'));
assert.ok(find('.hds-badge--type-outlined'));
});
@@ -11,7 +11,7 @@ import { setupIntl } from 'ember-intl/test-support';
module('Integration | Helper | format-day-year', function (hooks) {
setupRenderingTest(hooks);
setupIntl(hooks);
setupIntl(hooks, 'en-us');
test('it renders correctly when it is 1 year', async function (assert) {
this.set('inputValue', 365);
@@ -11,7 +11,7 @@ import { setupIntl } from 'ember-intl/test-support';
module('Integration | Helper | format-time-duration', function (hooks) {
setupRenderingTest(hooks);
setupIntl(hooks);
setupIntl(hooks, 'en-us');
test('It renders in human-readable duration strings given different durations in milliseconds', async function (assert) {
// Set mock input (in milliseconds) durations
@@ -11,7 +11,7 @@ import { setupIntl } from 'ember-intl/test-support';
module('Integration | Helper | relative-datetime-live', function (hooks) {
setupRenderingTest(hooks);
setupIntl(hooks);
setupIntl(hooks, 'en-us');
let now;
@@ -11,7 +11,7 @@ import { setupIntl } from 'ember-intl/test-support';
module('Integration | Helper | reverse-indexed-display-name', function (hooks) {
setupRenderingTest(hooks);
setupIntl(hooks);
setupIntl(hooks, 'en-us');
test('it renders the resource name with its position in parent array reversed', async function (assert) {
this.set('array', ['Boundary', 'is', 'cool!']);
@@ -11,11 +11,9 @@ import { setupIntl } from 'ember-intl/test-support';
module('Integration | Helper | time-remaining', function (hooks) {
setupRenderingTest(hooks);
setupIntl(hooks);
test('it calculates the correct time remaining', async function (assert) {
assert.expect(1);
setupIntl(hooks, 'en-us');
test('it calculates the correct time remainin with less than 24 hours', async function (assert) {
this.set('expirationTime', new Date(Date.now() + 1000 * 60 * 60 * 24));
await render(hbs`{{time-remaining this.expirationTime}}`);
@@ -23,9 +21,29 @@ module('Integration | Helper | time-remaining', function (hooks) {
assert.strictEqual(this.element.textContent.trim(), '23:59:59 remaining');
});
test('it handles negative time remaining', async function (assert) {
assert.expect(1);
test('it calculates the correct time remaining with more than 24 hours', async function (assert) {
this.set('expirationTime', new Date(Date.now() + 1001 * 60 * 60 * 24));
await render(hbs`{{time-remaining this.expirationTime}}`);
assert.strictEqual(
this.element.textContent.trim(),
'1 day, 0:01:26 remaining',
);
});
test('it calculates the correct time remaining with more than a week', async function (assert) {
this.set('expirationTime', new Date(Date.now() + 1001 * 60 * 60 * 24 * 8));
await render(hbs`{{time-remaining this.expirationTime}}`);
assert.strictEqual(
this.element.textContent.trim(),
'1 wk, 1 day, 0:11:31 remaining',
);
});
test('it handles negative time remaining', async function (assert) {
this.set('expirationTime', new Date(Date.now() - 1000 * 60 * 60 * 24));
await render(hbs`{{time-remaining this.expirationTime}}`);
@@ -22,7 +22,7 @@ const listWithOneItem = [{ key: 1, value: 'boundary' }];
const limit = 3;
module('Integration | Helper | truncate-list', function (hooks) {
setupRenderingTest(hooks);
setupIntl(hooks);
setupIntl(hooks, 'en-us');
test('it renders correctly when there is list with more than the limit specificed', async function (assert) {
this.set('inputValue', list);
@@ -30,7 +30,6 @@ module('Unit | Initializer | deprecations', function (hooks) {
run(this.application, 'destroy');
});
// TODO: Replace this with your real tests.
test('it works', async function (assert) {
await this.application.boot();
@@ -9,7 +9,6 @@ import { setupTest } from 'ember-qunit';
module('Unit | Service | clock-tick', function (hooks) {
setupTest(hooks);
// TODO: Replace this with your real tests.
test('it exists', function (assert) {
let service = this.owner.lookup('service:clock-tick');
assert.ok(service);
@@ -0,0 +1,79 @@
/**
* Copyright (c) HashiCorp, Inc.
* SPDX-License-Identifier: BUSL-1.1
*/
import { secondsToDuration } from 'core/utils/seconds-to-duration';
import { module, test } from 'qunit';
module('Unit | Utility | seconds-to-duration', function () {
test('it handles 0 correctly', function (assert) {
const result = secondsToDuration(0);
assert.strictEqual(result.seconds, 0);
assert.strictEqual(result.minutes, 0);
assert.strictEqual(result.hours, 0);
assert.strictEqual(result.days, 0);
assert.strictEqual(result.weeks, 0);
});
test('it converts seconds correctly', function (assert) {
const result = secondsToDuration(45);
assert.strictEqual(result.seconds, 45);
assert.strictEqual(result.minutes, 0);
assert.strictEqual(result.hours, 0);
assert.strictEqual(result.days, 0);
assert.strictEqual(result.weeks, 0);
});
test('it converts minutes correctly', function (assert) {
const result = secondsToDuration(100);
assert.strictEqual(result.seconds, 40);
assert.strictEqual(result.minutes, 1);
assert.strictEqual(result.hours, 0);
assert.strictEqual(result.days, 0);
assert.strictEqual(result.weeks, 0);
});
test('it converts hours correctly', function (assert) {
const result = secondsToDuration(5000);
assert.strictEqual(result.seconds, 20);
assert.strictEqual(result.minutes, 23);
assert.strictEqual(result.hours, 1);
assert.strictEqual(result.days, 0);
assert.strictEqual(result.weeks, 0);
});
test('it converts days correctly', function (assert) {
const result = secondsToDuration(500000);
assert.strictEqual(result.seconds, 20);
assert.strictEqual(result.minutes, 53);
assert.strictEqual(result.hours, 18);
assert.strictEqual(result.days, 5);
assert.strictEqual(result.weeks, 0);
});
test('it converts weeks correctly', function (assert) {
const result = secondsToDuration(800000);
assert.strictEqual(result.seconds, 20);
assert.strictEqual(result.minutes, 13);
assert.strictEqual(result.hours, 6);
assert.strictEqual(result.days, 2);
assert.strictEqual(result.weeks, 1);
});
test('it handles negative values', function (assert) {
const result = secondsToDuration(-800000);
assert.strictEqual(result.seconds, 0);
assert.strictEqual(result.minutes, 0);
assert.strictEqual(result.hours, 0);
assert.strictEqual(result.days, 0);
assert.strictEqual(result.weeks, 0);
});
});
+7 -2
View File
@@ -8,7 +8,6 @@ delete: Delete
remove: Remove
discard: Discard
disconnect: Disconnect
dismiss: Dismiss
save: Save
submit: Submit
manage: Manage
@@ -16,12 +15,14 @@ confirm: Confirm
done: Done
ok: OK
deny: Deny
help: Need help?
help: Need help
next: Next
back: Back
view: View
retry: Retry
play: Play
pause: Pause
resume: Resume
get-topic-help: Get help for this topic
copy-to-clipboard: Copy to Clipboard
copy-error-detail-to-clipboard: Copy error detail to clipboard
@@ -60,3 +61,7 @@ yes: Yes
no: No
narrow-results: Narrow results
overflow-options: Overflow Options
show-errors: Show Errors
hide-errors: Hide Errors
edit-worker-filter: Edit Worker Filter
add-worker-filter: Add Worker Filter
+53
View File
@@ -44,6 +44,8 @@ titles:
not-set: Not set
year: '{numberOfYears, plural, =1 {# year} other {# years}}'
days: '{days, plural, =1 {# day} other {# days}}'
workers: Workers
no-worker-filter: No worker filter added
descriptions:
empty-set: There are no items to display yet. You may be able to add items or try back later.
cluster-url-initialization: To get started, please enter your cluster URL
@@ -105,3 +107,54 @@ unsupported-controller:
releases-page: Go to releases page
change-cluster-url: Change cluster URL
error: Unable to download supported version of desktop app. You’ll need to download version 1.7.1 from the releases page
settings:
application: Application
cli: CLI
cache-daemon: Cache Daemon
client-agent:
title: Boundary Client Agent
description: Required to use Transparent Sessions
client: Client
version: Version
color-theme: Color Theme
provider: Provider
hcp: HashiCorp Cloud Platform
self-managed: Self-managed
server:
title: Server
description: Boundary connects you to targets using this server managed by your organization.
logs:
title: Logs
logging-level: Logging level
log-location: Log location
levels:
error: Error
warn: Warn
info: Info
debug: Debug
alerts:
cache-daemon: There may be a problem with the cache daemon
client-agent: There may be a problem with the client agent
worker-filter-generator:
title: Filter generator
description: Choose what you want to format into a filter.
link: Learn more about formatting a worker filter.
toggle:
title: Show filter generator
description: The generator will automatically generate a pre-formatted filter for you. You can copy the result to the editor above.
input-values:
title: Input values
description: Next, input what you want to format.
formatted-result:
title: Formatted result
description: Copy and paste this into the editor above.
label: Generated result
tag:
label: Tag
helper: Format a worker tag
name:
label: Name
helper: Format a worker name
operator:
matches: matches (regex)
contains: contains
+8 -2
View File
@@ -18,6 +18,8 @@ description:
type:
label: Type
help: The type of the resource, to help differentiate schemas
plugin_type:
label: plugin_type
login_name:
label: Login Name
help: The account login name
@@ -134,6 +136,8 @@ key:
label: Key
value:
label: Value
operator:
label: Operator
callback_url:
label: Callback URL
help: The URL to which the third-party provider sends the authentication response. Paste this into the provider configuration.
@@ -148,10 +152,10 @@ subscription_id:
help: The subscription ID for the subscription with read access.
access_key_id:
label: Access Key ID
help: The access key ID generated by AWS for the IAM user to use with this host catalog.
help: The access key ID generated by AWS for the IAM user to use with this AWS Host Catalog.
secret_access_key:
label: Secret Access Key
help: The secret access key generated by AWS for the IAM user to use with this host catalog.
help: The secret access key generated by AWS for the IAM user to use with this AWS Host Catalog.
secret:
label: Client Secret Value
help: The client secret value generated by Azure for Boundary to use for authentication.
@@ -179,3 +183,5 @@ created:
other_fields:
label: Other Fields
help: This information is provided by the server and cannot be edited in Boundary
worker_filter:
label: Worker Filter
+70 -21
View File
@@ -211,20 +211,54 @@ host-catalog:
delete: Delete Host Catalog
help:
static: Provide a list of hosts and host sets with static addresses
plugin: Automate discovery of target hosts and services on Azure or AWS
plugin: Automate discovery of target hosts and services on Azure, AWS, or GCP
role_arn: The ARN (Amazon Resource Name) used by this instance.
disable_credential_rotation: Credential rotation is automatically disabled when you use dynamic credentials.
types:
static: Static
unknown: Plugin
aws: AWS
azure: Azure
plugin: Dynamic
gcp: GCP
credential:
label: Credential type
help: Select the credential type that you want to use.
static-credential:
edit: Static Credentials
label: Use an access key (Static Credentials)
help: Use an access key that you have generated in AWS to use with this AWS Host Catalog.
dynamic-credential:
edit: Dynamic Credentials
label: Use Assume Role (Dynamic Credentials)
help: Specify a role used to generate credentials to use with this AWS Host Catalog.
form:
aws_region:
label: AWS Region
help: AWS region of the hosts to be added to the catalog.
help: AWS region of the hosts to be added to this AWS Host Catalog.
azure_client_id:
label: Client/Application ID
help: The client (application) ID of an Azure service principal that Boundary will use to authenticate and discover hosts from Azure.
worker_filter:
help: Insert a worker filter in order to route requests to the correct worker.
project_id:
label: Project ID
help: Project ID of the instances you want to add to this GCP Host Catalog.
zone:
label: Zone
help: Zone of the instances you want to add to this GCP Host Catalog.
client_email:
label: Client Email
help: The email address used to uniquely identify the service account.
target_service_account_id:
label: Target Service Account ID
help: The unique identifier for the service account that will be impersonated. This is only used when authenticating with service account impersonation.
private_key_id:
label: Private Key ID
help: The unique identifier of private key.
private_key:
label: Private Key
help: The private key used to obtain a OAuth 2.0 access token. Key must be PEM encoded.
host-set:
title: Host Set
title_plural: Host Sets
@@ -241,9 +275,11 @@ host-set:
filter:
label: Filter
aws:
help: Create a filter to select resources using values such as tag name or tag value. The AWS filter format is tag:<tag-name>=<tag-value>. For example:tag:application=production
help: 'Create a filter to select resources using values such as tag name or tag value. The AWS filter format is tag:<tag-name>=<tag-value>. For example: tag:application=production'
azure:
help: Create a filter to select resources using values such as tag name or tag value. The Azure filter format is:tagName eq ‘<tag-name>’ and tagValue eq ‘<tag-value>'. For example:tagName eq 'application' and tagValue eq 'production'
gcp:
help: 'Create a filter to select resources using values such as label name or label value. The GCP filter format is labels.<label-name>=<label-value>. For example: labels.application=production'
preferred_endpoints:
label: Preferred Endpoints
help: Preferred address at which the host should be accessed when multiple options are present, in cidr:<valid IPv4/6 CIDR> or dns:<globbed name> format.
@@ -357,6 +393,12 @@ session-recording:
duration: '{time} duration'
questions:
delete: Are you sure you want to delete this recording?
filters:
time:
title: Time
last-twenty-four-hours: Last 24 hours
last-three-days: Last 3 days
last-seven-days: Last 7 days
connection:
title: Connection
title_index: Connection {index}
@@ -384,9 +426,9 @@ session-recording:
messages:
none:
title: Channel Playback
missing:
title: We can't play back this channel because the file is missing
description: This likely means the connected storage bucket is misconfigured or the file was deleted.
error:
title: Playback error
description: This may mean the connected storage bucket is misconfigured, the file was deleted, or integrity validation failed.
link: Retrieving lost session recordings
not-supported:
title: Playback is not supported for this channel
@@ -439,6 +481,7 @@ storage-bucket:
plugin-types:
aws: Amazon S3
minio: MinIO
unknown: Unknown
form:
scope:
label: Scope
@@ -447,7 +490,6 @@ storage-bucket:
help_org: This storage bucket will be available for use with targets within this org.
provider:
label: Provider
help: Boundary currently only supports Amazon S3 storage.
endpoint_url:
label: Endpoint URL
help: Cannot be changed later.
@@ -459,7 +501,7 @@ storage-bucket:
help: The base path where session recordings will be stored.
role_arn:
label: Role ARN
help: The ARN (Assume Role Name) used by this instance that the worker runs on.
help: The ARN (Amazon Resource Name) used by this instance that the worker runs on.
role_external_id:
label: Role external ID
help: Used to provide access to this account if you have this configured.
@@ -479,8 +521,7 @@ storage-bucket:
label: Secret access key
help: The secret access key generated by your storage provider for the IAM user to use with this storage bucket. We will not show this data after it is saved, but you can replace it.
worker_filter:
label: Worker filter
help: Filter for Boundary workers that have network access to your storage. Boolean expression.
help: Filters to the worker(s) that can handle requests for this storage bucket.
disable_credential_rotation:
label: Disable credential rotation
help: Disabling credential rotation could allow entities outside of Boundary to know the client secret in use.
@@ -615,6 +656,10 @@ role:
help: Customize which scopes are associated with this role.
view-projects: '{selected}/{total} total projects'
apply: Apply changes to org
remove-org-and-projects: Remove org and projects
remove-org-only: Remove just the org
remove-orgs-and-projects: Remove orgs and projects
remove-orgs-only: Remove just the orgs
form:
this:
label: Add this scope
@@ -627,6 +672,12 @@ role:
descendants:
label: Add all descendants
help: Add all of the orgs and the projects in the orgs that are underneath this scope.
remove-org:
title: Remove this org?
description: You're about to remove {orgDisplayName}. Do you want to remove the projects under {orgDisplayName} as well? Or do you just want to remove {orgDisplayName} from this project?
remove-all-orgs:
title: Remove all selected orgs?
description: You're about to remove all the selected orgs. Do you want to remove the projects under these orgs as well? Or do you just want to remove just the orgs?
target:
title: Target
title_plural: Targets
@@ -689,7 +740,7 @@ target:
help: The local proxy port on which to listen by default when a session is started on a client.
sidebar:
label: Session Recording
help: Record SSH sessions on this target and save them to an Amazon S3 bucket.
help: Record SSH sessions on this target and save them to a storage bucket.
link: Session Recording settings
questions:
delete-host-sources:
@@ -750,11 +801,9 @@ target:
title: Add Injected Application Credential Sources
description: Select injected Application credential sources to assign to this target.
workers:
title: Workers
description: You can customize how your workers route traffic to this target by setting up a filter that matches specific worker tags. If your target is in a private network, we recommend setting up an egress filter to specify a worker inside the network so that Boundary can access the host. Ingress and egress filters are allowed to select the same worker.
messages:
none:
title: No worker filter added
description: You haven't added an {type} worker filter yet.
diagram:
client: Client
@@ -780,13 +829,10 @@ target:
title: Edit Ingress Worker Filter
description: Specify workers Boundary should use to start the route to this target.
worker-filter:
title: Worker filter
description: The worker filter format for this target.
accordion-label:
egress-workers: Egress workers
ingress-workers: Ingress workers
actions:
edit-worker-filter: Edit worker filter
credential-store:
title: Credential Store
title_plural: Credential Stores
@@ -796,6 +842,13 @@ credential-store:
title: Welcome to Credential Stores
titles:
new: New Credential Store
worker-filter:
description: A filter used to control which PKI workers can handle Vault requests, allowing the use of private Vault instances with Boundary.
messages:
none:
description: You haven't added a worker filter yet.
edit:
description: Specify workers that have access to the credential store.
actions:
delete: Delete Credential Store
types:
@@ -833,9 +886,6 @@ credential-store:
help: A PEM-encoded private key matching the client certificate from Client Certificate.
client_certificate_key_hmac:
label: Client Certificate Key HMAC
worker_filter:
label: Worker Filter
help: A filter used to control which PKI workers can handle Vault requests, allowing the use of private Vault instances with Boundary.
credential-library:
title: Credential Library
title_plural: Credential Libraries
@@ -873,7 +923,7 @@ credential-library:
help: The body of the HTTP request the library sends to Vault when requesting credentials. Only allowed when HTTP method is set to POST.
username:
label: Username
help: The username to use when making an SSH connection. This can be templated to use the requesting user's name. This will be included in the valid_principles when making the request to Vault.
help: The username to use when making an SSH connection. This can be templated to use the requesting user's name. This will be included in the valid_principals when making the request to Vault.
key_type:
label: Key Type
help: Specifies the desired key type to use when generating a private key.
@@ -969,7 +1019,6 @@ managed-group:
help: The list of groups that this Managed Group belongs to.
worker:
title: Worker
title_plural: Workers
titles:
new: New PKI Worker
description: Workers are the server components that perform the session handling.
@@ -14,7 +14,18 @@ active-public: Public
recording: Recording
completed: Completed
failed: Failed
installed: Installed
not-running: Not Running
running: Running
paused: Paused
authenticated: Authenticated
unauthenticated: Unauthenticated
loading:
title: Loading all items...
description: All of your {resource} are still loading. Please wait while we finish loading everything on screen.
generic-description: All of your resources are still loading. Please wait while we finish loading everything on screen.
incomplete-loading:
limit: Loaded the first {resultCount} results. Please narrow down your search or filters if the result you're looking for is not shown.
refreshing:
description: Updating cache...
tooltip: Some items may not appear until the cache is finished updating
+1 -5
View File
@@ -10,11 +10,7 @@ module.exports = {
extends: ['recommended', 'ember-template-lint-plugin-prettier:recommended'],
overrides: [
{
files: [
'addon/components/rose/anonymous/index.hbs',
'addon/components/rose/table/row/cell/index.hbs',
'addon/components/rose/anonymous/index.hbs',
],
files: ['addon/components/rose/anonymous/index.hbs'],
rules: {
'no-yield-only': false,
},
@@ -21,7 +21,6 @@
}}
{{yield
(hash
radioGroup=(component 'rose/form/radio/group' disabled=this.disabled)
checkbox=(component 'rose/form/checkbox' disabled=this.disabled)
checkboxGroup=(component
'rose/form/checkbox/group' disabled=this.disabled
@@ -1,17 +0,0 @@
{{!
Copyright (c) HashiCorp, Inc.
SPDX-License-Identifier: BUSL-1.1
}}
{{yield
(hash
radio=(component
'rose/form/radio/radio'
name=@name
selectedValue=@selectedValue
disabled=@disabled
changed=@changed
inline=@inline
)
)
}}
@@ -1,43 +0,0 @@
{{!
Copyright (c) HashiCorp, Inc.
SPDX-License-Identifier: BUSL-1.1
}}
<div class='{{this.className}} {{if @error " error"}} {{if @inline "inline"}}'>
<RadioButton
...attributes
@radioClass='rose-form-radio-field'
@radioId={{this.id}}
type='radio'
disabled={{@disabled}}
@name={{@name}}
@value={{@value}}
@groupValue={{@selectedValue}}
@disabled={{@disabled}}
@changed={{@changed}}
/>
<label class='rose-form-radio-label' for={{this.id}}>
{{#if @icon}}
<Rose::Icon @name={{@icon}} @size='medium' />
{{/if}}
{{@label}}
<span class='radio-card-overlay'></span>
{{#if @helperText}}
<Rose::Form::HelperText
@id='helper-text-{{this.id}}'
@error={{@error}}
@link={{@link}}
@linkText={{@linkText}}
>
{{@helperText}}
</Rose::Form::HelperText>
{{/if}}
</label>
{{yield}}
</div>
@@ -1,13 +0,0 @@
/**
* Copyright (c) HashiCorp, Inc.
* SPDX-License-Identifier: BUSL-1.1
*/
import Component from '@glimmer/component';
import { generateComponentID } from '../../../../../utilities/component-auto-id';
export default class RoseFormRadioRadioComponent extends Component {
// =attributes
className = 'rose-form-radio';
id = generateComponentID();
}
@@ -1,32 +0,0 @@
{{!
Copyright (c) HashiCorp, Inc.
SPDX-License-Identifier: BUSL-1.1
}}
<LinkTo
class='rose-link-button
{{if @style (concat "rose-button-" @style)}}
{{if @iconOnly "has-icon-only"}}
{{if @iconLeft "has-icon-left"}}
{{if @iconRight "has-icon-right"}}'
@route={{@route}}
...attributes
>
<span class='rose-button-wrapper'>
{{#if @iconLeft}}
<Rose::Icon @name={{@iconLeft}} @size='medium' />
{{/if}}
<span class='rose-button-body'>
{{yield}}
</span>
{{#if @iconOnly}}
<Rose::Icon @name={{@iconOnly}} @size='medium' />
{{/if}}
{{#if @iconRight}}
<Rose::Icon @name={{@iconRight}} @size='medium' />
{{/if}}
</span>
</LinkTo>
@@ -1,33 +0,0 @@
{{!
Copyright (c) HashiCorp, Inc.
SPDX-License-Identifier: BUSL-1.1
}}
<article ...attributes class='rose-message'>
{{#if @title}}
<header class='rose-message-header'>
{{#if @icon}}
<Rose::Icon @name={{@icon}} />
{{/if}}
<h2 class='rose-message-title'>{{@title}}</h2>
{{#if @subtitle}}
<h3 class='rose-message-subtitle'>{{@subtitle}}</h3>
{{/if}}
</header>
{{/if}}
<section class='rose-message-body'>
{{yield
(hash
description=(component
'rose/anonymous' tagName='p' class='rose-message-description'
)
link=(component 'link-to')
)
}}
</section>
</article>
@@ -1,8 +0,0 @@
/**
* Copyright (c) HashiCorp, Inc.
* SPDX-License-Identifier: BUSL-1.1
*/
import Component from '@glimmer/component';
export default class RoseMessageComponent extends Component {}
@@ -5,7 +5,7 @@
<li class='rose-metadata-list-item {{(concat "hds-foreground-" @color)}}'>
{{#if @icon}}
<FlightIcon @name={{@icon}} />
<Hds::Icon @name={{@icon}} />
{{/if}}
{{yield}}
</li>
@@ -1,41 +0,0 @@
{{!
Copyright (c) HashiCorp, Inc.
SPDX-License-Identifier: BUSL-1.1
}}
<section
...attributes
class='rose-notification is-{{@style}}{{if @dismiss " is-dismissible"}}'
role='alert'
aria-live={{if @dismiss 'assertive'}}
aria-atomic='true'
>
<header class='rose-notification-header'>
<Rose::Icon
class='rose-notification-icon'
@name={{this.icon}}
@size='medium'
/>
{{@heading}}
</header>
<div class='rose-notification-body'>
{{yield}}
</div>
{{#if @dismiss}}
<button
type='button'
class='rose-notification-dismiss'
title={{@dismissText}}
{{on 'click' @dismiss}}
>
<Rose::Icon @name='flight-icons/svg/x-16' @size='medium' />
<span class='rose-notification-dismiss-text'>
{{@dismissText}}
</span>
</button>
{{/if}}
</section>
@@ -1,32 +0,0 @@
/**
* Copyright (c) HashiCorp, Inc.
* SPDX-License-Identifier: BUSL-1.1
*/
import Component from '@glimmer/component';
import { computed } from '@ember/object';
export default class RoseNotificationComponent extends Component {
/**
* Returns an icon name based on the notification style.
* @type {string}
*/
@computed('style')
get icon() {
let icon = 'flight-icons/svg/info-16';
switch (this.style) {
case 'error':
icon = 'flight-icons/svg/x-square-16';
break;
case 'success':
icon = 'flight-icons/svg/check-circle-16';
break;
case 'warning':
icon = 'flight-icons/svg/alert-triangle-16';
break;
}
return icon;
}
}
@@ -1,6 +0,0 @@
{{!
Copyright (c) HashiCorp, Inc.
SPDX-License-Identifier: BUSL-1.1
}}
<hr class='rose-separator' />
@@ -1,27 +0,0 @@
{{!
Copyright (c) HashiCorp, Inc.
SPDX-License-Identifier: BUSL-1.1
}}
<table
...attributes
class='rose-table {{if @style (concat "rose-table-" @style)}}'
>
{{#if @caption}}
<caption>{{@caption}}</caption>
{{/if}}
{{yield
(hash
header=(component
'rose/table/section' tagName='thead' classNames='rose-table-header'
)
body=(component
'rose/table/section' tagName='tbody' classNames='rose-table-body'
)
footer=(component
'rose/table/section' tagName='tfoot' classNames='rose-table-footer'
)
)
}}
</table>
@@ -1,6 +0,0 @@
{{!
Copyright (c) HashiCorp, Inc.
SPDX-License-Identifier: BUSL-1.1
}}
{{yield}}
@@ -1,33 +0,0 @@
/**
* Copyright (c) HashiCorp, Inc.
* SPDX-License-Identifier: BUSL-1.1
*/
import Component from '@ember/component';
import layout from './index';
import { computed } from '@ember/object';
export default Component.extend({
layout,
tagName: 'td',
classNameBindings: ['cellTypeStyle', 'cellShrink', 'cellAlignmentStyle'],
cellTypeStyle: computed(function () {
return this.tagName.match('th')
? `rose-table-header-cell`
: 'rose-table-cell';
}),
cellShrink: computed(function () {
if (this.shrink) {
return 'rose-table-cell-shrink';
}
}),
cellAlignmentStyle: computed(function () {
if (this.alignRight) {
return 'align-right';
}
if (this.alignCenter) {
return 'align-center';
}
}),
});
@@ -1,18 +0,0 @@
{{!
Copyright (c) HashiCorp, Inc.
SPDX-License-Identifier: BUSL-1.1
}}
<tr
...attributes
class='rose-table-row
{{if @hidden (concat "rose-table-row-visually-hidden")}}
{{if @style (concat "rose-table-row-" @style)}}'
>
{{yield
(hash
cell=(component 'rose/table/row/cell')
headerCell=(component 'rose/table/row/cell' tagName='th')
)
}}
</tr>
@@ -1,16 +0,0 @@
/**
* Copyright (c) HashiCorp, Inc.
* SPDX-License-Identifier: BUSL-1.1
*/
import Component from '@ember/component';
import layout from './index';
/**
* A table row component that uses tr table element and
* configures a table cell element.
*/
export default Component.extend({
layout,
tagName: '',
});
Loaded 100 of 860 files, more files were not shown because too many files have changed in this diff. Show more