Compare commits

..
295 Commits
Author SHA1 Message Date
Carlos Alcaide Corvo 2d1e15a7bb Update changelog and cli version (#2280)
* Update changelog and cli version
2024-04-30 10:21:25 -07:00
Lisbet Alvarez dd92321b81 fix: 🐛 update label & description (#2279) 2024-04-29 11:52:45 -07:00
Lisbet Alvarez dce45031cb fix: 🐛 recording storage path not being set (#2276) 2024-04-26 15:49:29 -07:00
Zhihe Li 2666ec8244 fix: 🐛 Fix account password not being properly set (#2275) 2024-04-26 13:40:30 -04:00
Michael Li 3674d07762 test(e2e): Address flake (#2274)
Observed a flake when the Recording ID also contained an `OK`, causing a conflict with finding this OK button.
2024-04-25 13:52:26 -04:00
Zhihe Li dccf06cb0c fix: 🐛 Fix error when deleting auth method (#2273)
✅ Closes: https://hashicorp.atlassian.net/browse/ICU-13624
2024-04-25 11:48:55 -04:00
Carlos Alcaide CorvoandZhihe Li c64e8a2993 Fix storage bucket empty state message (#2272)
* Fix text

* Update addons/core/translations/resources/en-us.yaml

Co-authored-by: Zhihe Li <zhihe.li@hashicorp.com>

---------

Co-authored-by: Zhihe Li <zhihe.li@hashicorp.com>
2024-04-24 15:08:04 -07:00
Lisbet Alvarez 5ae490c28c fix: 🐛 small updates to cred-library, cred-store & host-catalog (#2271) 2024-04-24 11:16:06 -07:00
Dharini Jeeva bedcdee048 fix: 🐛 permissions (#2269)
* fix: 🐛 permissions
2024-04-24 11:04:11 -07:00
Michael Li bd394d9517 fix: Update LDAP address example (#2270) 2024-04-24 12:22:04 -04:00
Lisbet Alvarez a6bdc4fa24 fix: 🐛 action errors on auth-method refresh (#2268) 2024-04-23 16:37:01 -07:00
Zhihe Li 3e9a06a5b5 fix: 🐛 Fix adding host set error in targets (#2267) 2024-04-23 10:49:33 -04:00
Zhihe Li 19908768a4 fix: 🐛 Fix HDS labels and helpers in host sets (#2266)
* fix: 🐛 Fix HDS labels and helpers in host sets
2024-04-22 20:56:26 -04:00
Dharini Jeeva 4274a045f7 fix: 🐛 add details (#2265) 2024-04-22 13:00:00 -07:00
Lisbet Alvarez 1270458430 fix: 🐛 add missing pagination component to cred stores (#2264)
* fix: 🐛 add missing pagination component to cred stores

* test: 💍 fix cred store acceptance tests
2024-04-22 12:43:39 -07:00
Dharini Jeeva 4c342061d3 fix: 🐛 aliasing bugs (#2257)
* fix: 🐛 aliasing bugs
2024-04-22 12:16:00 -07:00
Dharini Jeeva 5ce83d9239 fix: 🐛 title (#2263) 2024-04-22 10:57:40 -07:00
Lisbet Alvarez 148f2db941 refactor: 💡 remove route-action usage for auth-methods (#2178)
* refactor: 💡 remove route-action usage for auth-methods

✅ Closes: https://hashicorp.atlassian.net/browse/ICU-12603
2024-04-22 10:33:06 -07:00
hashicorp-copywrite[bot] f65f483611 [COMPLIANCE] Add Copyright and License Headers (#2262)
Co-authored-by: hashicorp-copywrite[bot] <110428419+hashicorp-copywrite[bot]@users.noreply.github.com>
2024-04-22 11:47:53 -05:00
Lisbet Alvarez cc9003a118 fix: 🐛 required & optional labels in oidc auth-methods form (#2261) 2024-04-22 09:05:29 -07:00
Michael Li 20f8c99013 test(e2e): Fixes for 0.16.0 (#2258) 2024-04-22 10:39:53 -04:00
Dharini Jeeva 536ebc1c0f chore: 🤖 add doc links for aliases (#2260) 2024-04-19 13:37:51 -07:00
Zhihe Li 79a932bebb feat: 🎸 Add aliases to list view (#2256)
✅ Closes: https://hashicorp.atlassian.net/browse/ICU-13487
2024-04-19 16:18:32 -04:00
Carlos Alcaide Corvo f246c24a08 Add field validation for scope within Storage bucket creation (#2259) 2024-04-19 11:42:24 -07:00
Michael Li d31cfca138 chore(e2e): Update playwright to 1.43 (#2254)
When running the Admin UI e2e tests against 0.16.0, there were some issues with trying to click on a link on the new pagination tables (links were not seen as visible). For some reason, updating the playwright version fixed this.
2024-04-18 11:49:46 -04:00
Carlos Alcaide Corvo 298e804500 Fix an afterModel check to avoid reloading the page when the queryParam gets updated (#2255) 2024-04-18 08:03:13 -07:00
Dharini Jeeva f9cd1c331f feat: 🎸 show associated aliases in target detail page (#2249)
* feat: 🎸 show associated aliases in target detail page
2024-04-17 12:39:34 -07:00
Dharini Jeeva a0fa66a14d fix: 🐛 plural title (#2252) 2024-04-17 12:26:58 -07:00
Dharini Jeeva 086d9da028 fix: 🐛 place modal outside table (#2251) 2024-04-17 11:40:23 -07:00
Cameron Perera 9b20b150eb fix: 🐛 transition aborted error when deleting group (#2250) 2024-04-17 11:13:58 -05:00
Zhihe Li 6bbddc56b1 fix: 🐛 Fix windows being unable to search client daemon (#2245)
When using the client daemon to search on windows, we use
the CLI instead of the unix socket for our requests.
Unfortunately that means we spawn a separate process to
retrive the results and one idiosyncracy of this is that
`spawnSync` buffers its outputs which means we were hitting
the default max buffer size. `spawn` doesn't have this
issue because it streams its outputs and we didn't previously
use `spawnSync` for any command that produced large amounts
of output.

✅ Closes: https://hashicorp.atlassian.net/browse/ICU-13466
2024-04-17 07:40:09 -07:00
Carlos Alcaide Corvo 0870a8f623 MinIO support for Admin UI (#2248)
Add support for MinIO creation form and list
2024-04-16 14:17:23 -07:00
Cameron Perera 98c16ad422 fix: 🐛 add missing scope_id from credential sources for targets (#2247) 2024-04-16 11:31:54 -05:00
Zhihe LiandCameron Perera 9156c8612e fix: 🐛 Add back scope_id as part of request query parameter (#2246)
Co-authored-by: Cameron Perera <cameron.perera@hashicorp.com>
2024-04-16 11:15:16 -05:00
Lisbet Alvarez a43756895d fix: 🐛 auth-methods deleted items are showing on table view (#2244)
* fix: 🐛 auth-methods deleted items are showing on table view
2024-04-15 16:30:43 -07:00
Lisbet Alvarez adc50a939f refactor: 💡 remove uneeded rose cards component (#2243)
✅ Closes: https://hashicorp.atlassian.net/browse/ICU-13321
2024-04-15 10:37:26 -07:00
hashicorp-copywrite[bot] 37cbb74c76 [COMPLIANCE] Add Copyright and License Headers (#2242)
Co-authored-by: hashicorp-copywrite[bot] <110428419+hashicorp-copywrite[bot]@users.noreply.github.com>
2024-04-15 11:51:03 -05:00
Dharini Jeeva 80b633a063 Alias clear modal (#2239)
* fix: 🐛 permissions to create aliases within targets
2024-04-15 09:15:38 -07:00
Dharini Jeeva bd65c91ff9 chore: 🤖 alias target route (#2228) 2024-04-12 16:36:17 -07:00
Lisbet Alvarez c550faddb4 Icu 13218 update indexed db parser unit tests to test for filtering on boolean fields (#2238)
* test: 💍 unit tests for bool fields
* chore: 🤖 add deprecation handling

✅ Closes: https://hashicorp.atlassian.net/browse/ICU-13218
2024-04-12 16:22:27 -07:00
Cameron Perera 5e7c25a1fa refactor: 💡 update groups and workers "new" button to HDS (#2236) 2024-04-12 14:55:34 -04:00
ded8bdadd1 Icu 12592 add filtering pagination support for auth methods (#2209)
* feat: 🎸 add filtering & pagination to auth methods

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

---------

Co-authored-by: Zhihe Li <zhihe.li@hashicorp.com>
Co-authored-by: Cameron Perera <cameron.perera@hashicorp.com>
2024-04-12 14:55:34 -04:00
Cameron Perera 13da35c06b Icu 13357 create loading screen for admin UI list routes (#2231)
* test: 💍 fix failing tests

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

* feat: 🎸 add generic loading indicator for admin ui

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

* feat: 🎸 add custom loading logic for search and filtering

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

* chore: 🤖 fix lint error

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

* refactor: 💡 remove commented helper for sessions list

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

* style: 💄 update loading indicator margin to relative unit

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

* refactor: 💡 remove unneeded custom loading action

✅ Closes: https://hashicorp.atlassian.net/browse/ICU-13357
2024-04-12 14:55:34 -04:00
Lisbet Alvarez d52957d87b fix: 🐛 breadcrumbs on scopes route not showing since model move (#2235) 2024-04-12 14:55:34 -04:00
Zhihe Liandcameronperera 33d359e692 Fix tests from rebase (#2233)
* fix: 🐛 Fix tests broken by rebase onto main

---------

Co-authored-by: cameronperera <cameron.perera@hashicorp.com>
2024-04-12 14:55:34 -04:00
Cameron Perera 626bdc2c92 Icu 13374 add permission checks for filtering resources in sessions and targets (#2226)
* refactor: 💡 hide active sessions filter if no list permissions

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

* test: 💍 add active sessions filter permissions test

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

* refactor: 💡 add permissions check for targets and users

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

* refactor: 💡 address PR feedback

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

* refactor: 💡 move user permission check to a helper func

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

* refactor: 💡 move permissions logic to user and target helper

✅ Closes: https://hashicorp.atlassian.net/browse/ICU-13374
2024-04-12 14:55:34 -04:00
Lisbet Alvarez edba33bbda Icu 13359 refactor query requests for resources added to indexed db (#2224)
* refactor: 💡 update query requests for resources in indexedDB

✅ Closes: https://hashicorp.atlassian.net/browse/ICU-13359
2024-04-12 14:55:34 -04:00
Zhihe Li 5d32d987bc feat: 🎸 Update how we store tokens in indexed-db (#2223)
Added logic to make the list tokens stored in indexed DB more granular.
I get a hash of the query parameters that will get sent to the controller
and use that as the id for the token. This also means extra logic for when
a token is invalid as we will need to delete all tokens of the same
resource type.
2024-04-12 14:55:34 -04:00
Lisbet Alvarez 6c59baa413 refactor: 💡 reduce network requests & call indexedDB directly (#2217)
* refactor: 💡 reduce network requests & call indexedDB directly

✅ Closes: https://hashicorp.atlassian.net/browse/ICU-13251
2024-04-12 14:55:34 -04:00
Cameron Perera c2c0b38187 fix: 🐛 move query inside list permission check (#2222)
✅ Closes: https://hashicorp.atlassian.net/browse/ICU-13356
2024-04-12 14:55:34 -04:00
Lisbet Alvarez 1d7892230c Icu 13302 add filtering pagination support for scopes (#2216)
* feat: 🎸 add filtering and pagination to scopes

✅ Closes: https://hashicorp.atlassian.net/browse/ICU-13302
2024-04-12 14:55:34 -04:00
Cameron Perera ece9c9b0c8 refactor: 💡 add include_terminated param to sessions query (#2219)
✅ Closes: https://hashicorp.atlassian.net/browse/ICU-13130
2024-04-12 14:55:34 -04:00
Lisbet Alvarez 9a43c74e60 refactor: 💡 add active sessions column to targets table (#2196)
* refactor: 💡 add active sessions column to targets table

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

* test: 💍 add test case

✅ Closes: https://hashicorp.atlassian.net/browse/ICU-13085
2024-04-12 14:55:33 -04:00
Cameron Perera eb4ec5f6de refactor: 💡 update Dropdown component to have name & toggleText (#2218)
* refactor: 💡 update Dropdown component to have name & toggleText

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

* test: 💍 remove hds class selector

✅ Closes: https://hashicorp.atlassian.net/browse/ICU-13336
2024-04-12 14:55:33 -04:00
Zhihe Li a39b208b48 Icu 12781 add filtering pagination support for host catalogs (#2213)
* feat: 🎸 Add searching for host catalogs

✅ Closes: https://hashicorp.atlassian.net/browse/ICU-12781
2024-04-12 14:55:33 -04:00
Lisbet AlvarezandZhihe Li 22353e7df6 Icu 12782 add filtering pagination support for credential stores (#2212)
* feat: 🎸 add filtering & pagination support for credential-store

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

---------

Co-authored-by: Zhihe Li <zhihe.li@hashicorp.com>
2024-04-12 14:55:33 -04:00
Cameron Perera 713ffd8d1b fix: 🐛 add parentScope.id to refresh action for sessions (#2215)
* fix: 🐛 add parentScope.id to refresh action for sessions

* refactor: 💡 remove scope_id from users and targets query
2024-04-12 14:55:33 -04:00
Cameron Perera 6e75439652 Icu 12587 add filtering pagination support for sessions (#2194)
* feat: 🎸 add pagination and filtering to sessions page

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

* refactor: 💡 fix handling of null values in indexed-db-query

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

* refactor: 💡 add method signatures where missing

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

* refactor: 💡 address PR feedback

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

* fix: 🐛 add override for table header color when sortable

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

* refactor: 💡 remove poller and add manual refresh action

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

* refactor: 💡 remove force_refresh from sessions route queries

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

* refactor: 💡 add user getter to session model

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

* refactor: 💡 remove logicalOperator value from queries

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

* refactor: 💡 move action to controller from router

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

* refactor: 💡 remove cleanValues from indexed-db-query

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

* refactor: 💡 remove potential null values for user/target ids

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

* refactor: 💡 add async/await back to cancelSession

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

* refactor: 💡 update sessions route

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

* refactor: 💡 use translation string for Sessions

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

* test: 💍 fix controller test

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

* refactor: 💡 add scope_id to filters for query

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

* refactor: 💡 remove scope_id and recursive in sessions query

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

* refactor: 💡 how user query to use global and org scope

✅ Closes: https://hashicorp.atlassian.net/browse/ICU-12587
2024-04-12 14:55:33 -04:00
Cameron PereraandZhihe Li be96daa499 Icu 12591 add filtering pagination support for groups (#2205)
* refactor: 💡 move model hook to groups/index

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

* feat: 🎸 add pagination to groups list view

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

* feat: 🎸 add searching to groups

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

* fix: 🐛 update scopeId to scope_id

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

* test: 💍 clean up test refactor

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

* refactor: 💡 update how groupsExisit is set

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

* refactor: 💡 update mirage config for groups

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

* test: 💍 fix failing groups create tests

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

* refactor: 💡 add groups mirage config back

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

* refactor: 💡 use translation string for Groups

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

* refactor: 💡 update how groups are queried

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

* Update ui/admin/tests/acceptance/groups/list-test.js

Co-authored-by: Zhihe Li <zhihe.li@hashicorp.com>

* refactor: 💡 update groups translation to title_plural

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

---------

Co-authored-by: Zhihe Li <zhihe.li@hashicorp.com>
2024-04-12 14:55:33 -04:00
Zhihe Li 9f11e8a25d fix: 🐛 Fix setting up indexed db when user logins first time (#2211) 2024-04-12 14:55:33 -04:00
Lisbet Alvarez 8be4e93a3c Icu 12590 add filtering pagination support for roles (#2204)
* feat: 🎸 add search & pagination for roles

✅ Closes: https://hashicorp.atlassian.net/browse/ICU-12590
2024-04-12 14:55:33 -04:00
Lisbet Alvarez a78522e09a feat: 🎸 add search & pagination support for users (#2195)
✅ Closes: https://hashicorp.atlassian.net/browse/ICU-12589
2024-04-12 14:55:33 -04:00
Zhihe LiandLisbet Alvarez a26662eca5 feat: 🎸 Add filtering/pagination for admin ui targets (#2072)
* feat: 🎸 Add filtering/pagination for admin ui targets

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

* test: 💍 add acceptance test cases

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

* test: 💍 cleanup tests and add controller tests

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

---------

Co-authored-by: Lisbet Alvarez <lisbet.alvarez@hashicorp.com>
2024-04-12 14:55:33 -04:00
Zhihe LiandLisbet Alvarez d72fa0d6e3 feat: 🎸 Add indexedDb parser (#2068)
* feat: 🎸 Add indexedDb parser

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

---------

Co-authored-by: Lisbet Alvarez <lisbet.alvarez@hashicorp.com>
2024-04-12 14:55:33 -04:00
Zhihe Li bd5e3da1f4 feat: 🎸 Initial setup of IndexedDB (#2064)
* feat: 🎸 Initial setup of IndexedDB

* fix: 🐛 Rethrow errors up from indexed db handler
2024-04-12 14:55:33 -04:00
Dharini Jeeva f74f4d4a20 Target aliases list view (#2225)
target aliases list view
2024-04-11 14:18:38 -07:00
dependabot[bot]andZhihe Li 9bd45164bf chore(deps): bump tar from 6.1.11 to 6.2.1 in /ui/desktop/electron-app (#2230)
Bumps [tar](https://github.com/isaacs/node-tar) from 6.1.11 to 6.2.1.
- [Release notes](https://github.com/isaacs/node-tar/releases)
- [Changelog](https://github.com/isaacs/node-tar/blob/main/CHANGELOG.md)
- [Commits](https://github.com/isaacs/node-tar/compare/v6.1.11...v6.2.1)

---
updated-dependencies:
- dependency-name: tar
  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-04-11 14:05:30 -04:00
dependabot[bot] 363879c3c3 chore(deps): bump tar from 6.1.15 to 6.2.1 (#2232)
Bumps [tar](https://github.com/isaacs/node-tar) from 6.1.15 to 6.2.1.
- [Release notes](https://github.com/isaacs/node-tar/releases)
- [Changelog](https://github.com/isaacs/node-tar/blob/main/CHANGELOG.md)
- [Commits](https://github.com/isaacs/node-tar/compare/v6.1.15...v6.2.1)

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

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-04-11 13:41:15 -04:00
Lisbet Alvarez 0b4fd6765e fix: 🐛 modal bubbling up when user has not updated model (#2227)
✅ Closes: https://hashicorp.atlassian.net/browse/ICU-13106
2024-04-09 12:05:15 -07:00
Dharini Jeeva c8839d6db1 Icu 12933 updates to target model to support aliasing (#2214)
* feat: 🎸 target aliases association API, form creation
2024-04-05 16:35:23 -07:00
Johan Brandhorst-SatzkornandZhihe Li ac5110d94a feat: 🎸 authenticate to ferry on authentication (#2203)
* feat: 🎸 authenticate to ferry on authentication

Replace the 'boundary daemon add-token' command with a simple
'boundary auth-tokens read -id <token_id>', relying on the boundary
CLI to do the work of sending the token to the client and Ferry
daemons.

* refactor: 💡 Use CLI to add tokens to daemons for all platforms

---------

Co-authored-by: Zhihe Li <zhihe.li@hashicorp.com>
2024-04-03 12:41:13 -04:00
hashicorp-tsccr[bot]andhashicorp-tsccr[bot] 78bcc103c2 Result of tsccr-helper -log-level=info gha update -latest . (#2210)
Co-authored-by: hashicorp-tsccr[bot] <hashicorp-tsccr[bot]@users.noreply.github.com>
2024-04-02 10:21:39 -07:00
dependabot[bot]andZhihe Li fe0cffdf0b chore(deps): bump express from 4.18.2 to 4.19.2 (#2208)
Bumps [express](https://github.com/expressjs/express) from 4.18.2 to 4.19.2.
- [Release notes](https://github.com/expressjs/express/releases)
- [Changelog](https://github.com/expressjs/express/blob/master/History.md)
- [Commits](https://github.com/expressjs/express/compare/4.18.2...4.19.2)

---
updated-dependencies:
- dependency-name: express
  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-03-28 17:45:02 -04:00
Michael Li 79f4c2bc5d test(e2e): Update credential library form behavior (#2207)
* test(e2e): Update credential library form behavior

* fix(e2e):  Fix some locators due to form updates
2024-03-28 15:05:57 -04:00
Devon AndersonandZhihe Li 9843310dfb Icu 12860 retain values in form fields in credential library when switching types (#2169)
✅ Closes: https://hashicorp.atlassian.net/browse/ICU-12860

---------

Co-authored-by: Zhihe Li <zhihe.li@hashicorp.com>
2024-03-27 15:18:58 -04:00
Dharini Jeeva db75b2e292 chore: 🤖 aliases list view (#2197)
* chore: 🤖 aliases list view
2024-03-25 16:54:15 -07:00
Cameron Perera ac1d98bbec fix: 🐛 show change cluster url when no auth methods (#2201)
✅ Closes: https://hashicorp.atlassian.net/browse/ICU-13133
2024-03-25 14:24:53 -05:00
Cameron Perera 0c6744581d fix: 🐛 remove recursive param from list scopes endpoint (#2199)
✅ Closes: https://hashicorp.atlassian.net/browse/ICU-12543
2024-03-25 13:47:07 -05:00
hashicorp-copywrite[bot] fb345f045e [COMPLIANCE] Add Copyright and License Headers (#2202)
Co-authored-by: hashicorp-copywrite[bot] <110428419+hashicorp-copywrite[bot]@users.noreply.github.com>
2024-03-25 10:31:51 -07:00
Michael Li b1085def48 test(e2e): Add check for playing back session recording (#2198) 2024-03-25 12:13:27 -04:00
Michael Li 499b0fde31 refact(e2e): Convert to match "create" helper convention (#2200) 2024-03-22 16:22:34 -04:00
dependabot[bot]andCameron Perera bbf9c95267 chore(deps): bump follow-redirects from 1.15.4 to 1.15.6 (#2187)
Bumps [follow-redirects](https://github.com/follow-redirects/follow-redirects) from 1.15.4 to 1.15.6.
- [Release notes](https://github.com/follow-redirects/follow-redirects/releases)
- [Commits](https://github.com/follow-redirects/follow-redirects/compare/v1.15.4...v1.15.6)

---
updated-dependencies:
- dependency-name: follow-redirects
  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: Cameron Perera <cameron.perera@hashicorp.com>
2024-03-22 11:07:56 -05:00
Dharini Jeeva 2dbcc1c0af Alias create (#2193)
* feat: 🎸 create alias
2024-03-21 09:50:51 -07:00
Michael Li 6d88206491 refact(e2e): Update create helper methods (#2191) 2024-03-20 09:38:59 -04:00
de20df445c [COMPLIANCE] Add Copyright and License Headers (#2188)
Co-authored-by: hashicorp-copywrite[bot] <110428419+hashicorp-copywrite[bot]@users.noreply.github.com>
Co-authored-by: Carlos Alcaide Corvo <ccorvo@hashicorp.com>
Co-authored-by: Cameron Perera <cameron.perera@hashicorp.com>
2024-03-19 21:56:39 -05:00
Michael Li 45ad7a8f3b fix(e2e): Address flake in log in/log out test (#2189) 2024-03-19 16:52:30 -04:00
798cfc6828 chore: 🤖 Update desktop client changelog (#2183)
Co-authored-by: Cameron Perera <cameron.perera@hashicorp.com>
Co-authored-by: Lisbet Alvarez <107949262+lisbet-alvarez@users.noreply.github.com>
2024-03-19 12:23:50 -07:00
Lisbet Alvarez d93986c4e2 refactor: 💡 remove route-action usage from credential-stores (#2172)
* refactor: 💡 remove route-action usage from credential-stores

✅ Closes: https://hashicorp.atlassian.net/browse/ICU-12604
2024-03-18 16:34:37 -07:00
Michael Li 879c196887 refact(e2e): Move env outside of helper methods (#2186)
* refact(e2e): Move env outside of UI helper methods

* refact(e2e): Move env outside of CLI helpers
2024-03-18 15:53:39 -04:00
Lisbet Alvarez 98170ed01e refactor: 💡 Remove route-action usage for managed-groups (#2168)
* refactor: 💡 Remove route-action usage for managed-groups

✅ Closes: https://hashicorp.atlassian.net/browse/ICU-12619
2024-03-18 10:34:54 -07:00
Dharini Jeeva 47a218cf8f chore: Add routes for aliases (#2185)
alias resource routes
2024-03-15 14:48:32 -07:00
Dharini Jeeva 879a58dcb8 feat: 🎸 mirage support and initial route for aliases (#2181)
* feat: 🎸 mirage support and initial route for aliases
2024-03-15 14:24:20 -07:00
Stan RyzhovandMichael Li f100190ac1 test: 💍 Add storage policies e2e-test (#2175)
* test: 💍 Add storage policies e2e-test

✅ Closes: ICU-12883

* chore: Adjust required env for e2e-tests

✅ Closes: ICU-12883

* CR: Refactor helper method to pass in env

---------

Co-authored-by: Michael Li <michael.li@hashicorp.com>
2024-03-15 11:55:13 -04:00
Lisbet Alvarez 0902e42cb0 refactor: 💡 remove route-action usage for groups (#2176)
* refactor: 💡 remove route-action usage for groups

✅ Closes: https://hashicorp.atlassian.net/browse/ICU-12605
2024-03-14 13:28:43 -07:00
Michael Li 6b0958e4d8 test(e2e): Admin UI test fixes (#2182) 2024-03-14 14:17:54 -04:00
Cameron Perera 82ea70f44b fix: 🐛 update destination path for autoUpdater workflow (#2179)
✅ Closes: https://hashicorp.atlassian.net/browse/ICU-12878
2024-03-13 10:46:22 -05:00
hashicorp-copywrite[bot] 0bb72040db [COMPLIANCE] Add Copyright and License Headers (#2177)
Co-authored-by: hashicorp-copywrite[bot] <110428419+hashicorp-copywrite[bot]@users.noreply.github.com>
2024-03-11 11:51:45 -05:00
Michael Li 9d9a38510b test(e2e): Add test for SSH certification injection (#2170) 2024-03-07 17:05:45 -05:00
Lisbet Alvarez a54aecee07 refactor: 💡 remove route-action usage in accounts (#2134)
* refactor: 💡 remove route-action usage in accounts

✅ Closes: https://hashicorp.atlassian.net/browse/ICU-12616
2024-03-07 09:24:28 -08:00
Devon Anderson 7dab184bb9 chore: 🤖 Migrate form.input to Hds:TExtInput::Field (#2149)
* chore: 🤖 Migrate `form.input` to `Hds:TExtInput::Field`

Migrate `form/account/oidc` and `form/account/password` forms to use
`Hds::TextInput::Field` instead of `form.input`

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

* refactor: 💡 argument clean up

argument clean up

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

* refactor: 💡 switch to `readonly` arument instead of `disabled`

switch to `readonly` arument instead of `disabled`

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

* refactor: 💡 fix incorrect attributes

fix incorrect attributes

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

* refactor: 💡 fix failing test

fix failing test

✅ Closes: https://hashicorp.atlassian.net/browse/ICU-12457
2024-03-07 10:12:33 -05:00
Lisbet Alvarez f068ac0b0c refactor: 💡 remove usage of route-action for app route (#2135)
✅ Closes: https://hashicorp.atlassian.net/browse/ICU-12615
2024-03-04 10:13:59 -08:00
Michael Li d07c33ca41 test(e2e): Add test for SSH Credential Injection with Vault SSH Private Key (#2166) 2024-03-01 13:35:47 -05:00
hashicorp-tsccr[bot]andhashicorp-tsccr[bot] f073de774d Result of tsccr-helper -log-level=info gha update -latest . (#2167)
Co-authored-by: hashicorp-tsccr[bot] <hashicorp-tsccr[bot]@users.noreply.github.com>
2024-03-01 09:48:29 -08:00
Michael Li 1040a05880 test(e2e): Add LDAP Admin UI e2e test (#2164) 2024-02-29 16:51:32 -05:00
Lisbet Alvarez 002f64d676 update cli version and update changelog (#2165)
* docs: ✏️ update cli version and update changelog
2024-02-28 10:31:34 -08:00
Devon Anderson c09efbae10 chore: 🤖 Migrate form.inut to Hds::TextInput::Field (#2151)
* chore: 🤖 Migrate `form.inut` to `Hds::TextInput::Field`

Migrate `form/create-worker-led` form to use `Hds:Text::InputField`
instead of `form.input`

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

* refactor: 💡 Added `optional` and `requred` arguments for fields

Added `optional` and `require` arguments for all needed fields.

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

* refactor: 💡 fix failing test

fix failing test

✅ Closes: https://hashicorp.atlassian.net/browse/ICU-12477
2024-02-28 13:02:02 -05:00
Devon Anderson 060f995f94 chore: 🤖 Migrate form.input to Hds::TextInput::Field (#2143)
* chore: 🤖 Migrate `form.input` to `Hds::TextInput::Field`

Migrate `form/credential` forms for for `json`, `ssh_private_key`,
`username_password`, and `form/credential-store` forms for `static` and
`vault` to use `Hds::TextInput::Field` instead of `form.input`.

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

* refactor: 💡 fix broken test

fix broken test

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

* refactor: 💡 fix broken test

fix broken test

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

* refactor: 💡 added `@hasVisibilityToggle` back and clean up test

Added `@hasVisibilityToggle` back and clean up test by use `data-test-*`
attributes for error messaging

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

* refactor: 💡 set `@hasVisiblityToggle` to default

set `@hasVisiblityToggle` to default

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

* refactor: 💡 field argument clean up

field argument cleanup

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

* refactor: 💡 switch `disabled` argument to `readonly`

switch `disabled` argument to `readonly`

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

* refactor: 💡 clean up attribute order

clean up field attribute order

✅ Closes: https://hashicorp.atlassian.net/browse/ICU-12461
2024-02-28 12:21:37 -05:00
Devon Anderson f1c5c99664 chore: 🤖 Migrate form.input to Hds::TextInput::Field (#2147)
* chore: 🤖 Migrate `form.input` to `Hds::TextInput::Field`

Migrate `form/host-set/aws`, `form/host-set/azure` and
`form/host-set/static` forms to use `Hds::TextInputField` instead of
`form.input`

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

* Update index.hbs

removed `@isOptional` field.

* Update index.hbs

removed `@isOptional` argument

* refactor: 💡 fix lint errors

fix lint

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

* refactor: 💡 field argument cleanup

field argument cleanup

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

* refactor: 💡 switch `disabled` argument to `readonly`

switch `disabled` argument to `readonly`

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

* refactor: 💡 order of attributes

change order of attributes

✅ Closes: https://hashicorp.atlassian.net/browse/ICU-12469
2024-02-28 10:18:22 -05:00
af5fb8e814 chore(deps): bump es5-ext from 0.10.53 to 0.10.63 (#2162)
Bumps [es5-ext](https://github.com/medikoo/es5-ext) from 0.10.53 to 0.10.63.
- [Release notes](https://github.com/medikoo/es5-ext/releases)
- [Changelog](https://github.com/medikoo/es5-ext/blob/main/CHANGELOG.md)
- [Commits](https://github.com/medikoo/es5-ext/compare/v0.10.53...v0.10.63)

---
updated-dependencies:
- dependency-name: es5-ext
  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>
Co-authored-by: Zhihe Li <zhihe.li@hashicorp.com>
2024-02-27 16:49:29 -05:00
Devon Anderson cf5334556f chore: 🤖 Migrate form.input to Hds::TextInput:Field (#2150)
* chore: 🤖 Migrate `form.input` to `Hds::TextInput:Field`

Migrate  `form/manage-groups/oidc`, `form/user` and `form/worker` forms
to use `Hds::TextInput::Field` instead of `form.input`

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

* refactor: 💡 argument clean up

argument clean up

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

* refactor: 💡 refactor InfoField arguments for `readonly`

Refactor InfoField component's arguments for `readonly` instead of
`disabled`

✅ Closes: https://hashicorp.atlassian.net/browse/ICU-12473
2024-02-27 14:57:54 -05:00
Dharini Jeeva 5c6c9bb69f fix: 🐛 move config processing to mirage serializer (#2163) 2024-02-27 11:25:51 -08:00
Devon Anderson 26a77edbc7 chore: 🤖 Migrate form.inpu to use Hds::TextInput::Field` (#2145)
* chore: 🤖 Migrate `form.inpu` to use Hds::TextInput::Field`

Migrate `form/group`, `form/host-static`, `form/host-catalog/aws` and
`form/host-catalog/azure` forms to use `Hds::TextInputField instead of
`form.input`

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

* refactor: 💡 use `data-test` attributes for testing

use `data-test` attributes for testing error messaging.

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

* refactor: 💡 field argument cleanup

field argument cleanup

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

* refactor: 💡 switch `disabled` argument to `readonly`

switch `disabled` argument to `readonly`

✅ Closes: https://hashicorp.atlassian.net/browse/ICU-12466
2024-02-27 13:52:50 -05:00
Dharini Jeeva 3fc865d226 Fix credential library mocks (#2161)
* fix: 🐛 vault cred library mocks
2024-02-27 09:41:28 -08:00
Devon Anderson 47d7ceccf7 chore: Migrate form.input to use Hds text input field (#2154)
* chore: 🤖 Migrate `form.input` to use `Hds` form input field

Migrate `form.input` for `clusterurl.hbs` to use
`Hds::Form::TextInput::Field`

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

* refactor: 💡 removed unused `data-test` attribute

removed unused `data-test` attribute

✅ Closes: https://hashicorp.atlassian.net/browse/ICU-12478
2024-02-27 09:31:48 -05:00
Dharini Jeeva 38df28be55 fix: 🐛 change delete to detach Storage policy from a scope (#2160)
* fix: 🐛 change delete to detach Storage policy from a scope
2024-02-26 12:50:38 -08:00
Dharini Jeeva 6d7c86a08c fix: 🐛 spelling (#2159)
✅ Closes: https://hashicorp.atlassian.net/browse/ICU-12813
2024-02-26 11:18:34 -08:00
Michael Li 58a31b880b test(e2e): Add enterprise tests for creating TCP/SSH targets (#2158) 2024-02-26 12:59:34 -05:00
Dharini Jeeva 453ab7911d doc: var name (#2140)
* fix: 🐛 var name
2024-02-23 15:52:08 -08:00
Dharini Jeeva 93c8d481fd Icu 12567 add new field credential mapping overrides (#2156)
* chore: 🤖 add credential type select list
2024-02-23 10:07:52 -08:00
Carlos Alcaide Corvo 956f6fd04d refactor: 💡 Adopt HDS copy snippet Desktop UI (#2146)
* refactor: 💡 Adopt HDS copy snippet Desktop UI

Adopt HDS copy snippet and delete usage of Copyable custom component
2024-02-22 13:56:56 -08:00
dependabot[bot]andZhihe Li 912be13744 chore(deps): bump ip from 1.1.8 to 1.1.9 in /ui/desktop/electron-app (#2155)
Bumps [ip](https://github.com/indutny/node-ip) from 1.1.8 to 1.1.9.
- [Commits](https://github.com/indutny/node-ip/compare/v1.1.8...v1.1.9)

---
updated-dependencies:
- dependency-name: ip
  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-02-22 15:28:18 -05:00
dependabot[bot]andZhihe Li fc1b91c8f9 chore(deps): bump ip from 1.1.5 to 1.1.9 (#2153)
Bumps [ip](https://github.com/indutny/node-ip) from 1.1.5 to 1.1.9.
- [Commits](https://github.com/indutny/node-ip/compare/v1.1.5...v1.1.9)

---
updated-dependencies:
- dependency-name: ip
  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-02-22 15:10:54 -05:00
Devon Anderson 8e40b01caf refactor: 💡 Quick fix for client_secret attributes (#2157)
`client_secret` attribute needed to be `@type` instead of `type`
2024-02-22 14:52:31 -05:00
Devon Anderson 20181c978f refactor: 💡 Migrate form.input to Hds::TextInput::Field (#2142)
* refactor: 💡 Migrate `form.input` to `Hds::TextInput::Field`

Migrate the use of `form.input` to `Hds::TextInput::Field` for OIDC and
Password auth-method form

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

* Update index.hbs

move `name` attribute to top of attribute list for readers

* refactor: 💡 fix `step` and `min` arguments

fix `step` and `min` arguments

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

* refactor: 💡 clean up order of arguments and add `data-test` att

clean up order of arguments and add `data-test` attributes

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

* refactor: 💡 Add `@isOptional` attribute to all needed fields

Add `@isOptiona` attributes to all needed fields

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

* Update index.hbs

add `@hasVisibilityToggle`

* refactor: 💡 fix lint

fix lint

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

* refactor: 💡 quick attribute refactor

quick attribute refactor

✅ Closes: https://hashicorp.atlassian.net/browse/ICU-12459
2024-02-22 13:22:18 -05:00
Lisbet Alvarez db78f1ae4d docs: ✏️ update enos readme (#2139)
* docs: ✏️ update enos readme

* docs: ✏️ update cmd

* docs: ✏️ update wording

* docs: ✏️ add link

* docs: ✏️ use diff slack channel
2024-02-20 17:57:21 -08:00
Dharini Jeeva 592bb15022 chore: 🤖 add credential type select list (#2144)
* chore: 🤖 add credential type select list
2024-02-16 15:57:14 -08:00
Carlos Alcaide Corvo f002e14673 [Admin UI] Adopt HDS::Copy::Snippet (#2141)
* refactor: 💡 Adopt HDS copy snippet

Adopt HDS copy snippet and delete usage of Copyable custom component
within Admin UI.
2024-02-16 02:19:43 -08:00
Devon Anderson a1b455e5eb refactor: 💡 Migrate last form.fieldset over to use Hds (#2138)
* refactor: 💡 Migrate last `form.fieldset` over to use Hds

Migrate last `form.fieldset` over to use `Hds::FormFieldset`

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

* refactor: 💡 removed `fieldset` from `RadioCard`

Removed unneeded `fieldset` from `RadioCard`

✅ Closes: https://hashicorp.atlassian.net/browse/ICU-9427
2024-02-15 09:51:39 -05:00
Dharini Jeeva 786e6130cd feat: 🎸 allow session recording deletion (#2132)
* feat: 🎸 allow session recording deletion
2024-02-13 13:26:23 -08:00
hashicorp-copywrite[bot] 4db8b8e1e7 [COMPLIANCE] Add Copyright and License Headers (#2137)
Co-authored-by: hashicorp-copywrite[bot] <110428419+hashicorp-copywrite[bot]@users.noreply.github.com>
2024-02-12 16:31:46 -05:00
Lisbet Alvarez 4be8d10323 Icu 12557 refresh not working as intended on windows (#2133)
* fix: 🐛 add flag

* refactor: 💡 add true val

✅ Closes: https://hashicorp.atlassian.net/browse/ICU-12557
2024-02-09 11:58:41 -08:00
Devon Anderson c79a1fca79 chore: 🤖 Create select field render for the Form::Field::ListWrapper (#2112)
* chore: 🤖 Create `select` field render for the `Form::Field::ListWrapper`
component

Create a `select` field render for the `Form::Field::ListWrapper`
component.

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

* refactor: 💡 Added additional test

Added additional testing around removing and adding an option, and
refactored for better usability

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

* refactor: 💡 Refactored getter to check for option and model arg

Refactore getter to check for options and model args.

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

* refactor: 💡 Use select field with `signing_algorithms`

Use select field with `signing_algorithms`

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

* refactor: 💡 fix test

fix test

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

* refactor: 💡 fix failing test

fix failing test

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

* refactor: 💡 fix update auth-method test

fix update auth-method test

✅ Closes: https://hashicorp.atlassian.net/browse/ICU-12271
2024-02-09 08:42:15 -05:00
Cameron Perera d2d332b7d1 refactor: 💡 only show scopes with auth methods at authenticate (#2129)
* refactor: 💡 only show scopes with auth methods at authenticate

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

* test: 💍 verify scopes with no auth methods are hidden

when authenticating

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

* refactor: 💡 update logic for fetching scopes and auth methods

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

* refactor: 💡 PR feedback changes

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

* refactor: 💡 added unless block back to template

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

* refactor: 💡 update admin authenticate route and template

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

* test: 💍 add test for orgs with no auth methods admin ui

✅ Closes: https://hashicorp.atlassian.net/browse/ICU-2355
2024-02-08 10:01:20 -06:00
022ac0fffe Result of tsccr-helper -log-level=info gha update -latest . (#2126)
Co-authored-by: hashicorp-tsccr[bot] <hashicorp-tsccr[bot]@users.noreply.github.com>
Co-authored-by: Zhihe Li <zhihe.li@hashicorp.com>
Co-authored-by: Lisbet Alvarez <107949262+lisbet-alvarez@users.noreply.github.com>
2024-02-07 16:42:38 -08:00
Cameron Perera f3622fb92b feat: 🎸 remove Type of Worker from worker details page (#2131)
* feat: 🎸 remove Type of Worker from worker details page

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

* refactor: 💡 remove unused translation

✅ Closes: https://hashicorp.atlassian.net/browse/ICU-12409
2024-02-06 14:48:28 -06:00
Zhihe Li f8b5dcd824 fix: 🐛 Add error notification if adding token to daemon fails (#2127)
✅ Closes: https://hashicorp.atlassian.net/browse/ICU-12488
2024-02-05 14:21:13 -05:00
Alex 056008e13e chore: 🤖 replace Rose::CodeEditor with Hds::CodeBlock on new worker page (#2128)
* chore: 🤖 replace `Rose::CodeEditor` with `Hds::CodeBlock` for new workers
2024-02-05 09:50:08 -08:00
Alex ea03d6e488 chore: 🤖 update HDS to 3.5.0 (#2116)
* chore: update to 3.4.1

`@hashicorp/design-system-components` to `3.4.1`
 - `@hashicorp/ember-flight-icons` to `4.0.5`

* chore: update to 3.5.0
2024-01-31 15:49:02 -05:00
Zhihe Li 06cc64e6af fix: 🐛 Add refresh button back (#2124) 2024-01-30 19:54:34 -05:00
Lisbet Alvarez 4d3c993b0f refactor: 💡 move token call to be inside try-catch (#2123) 2024-01-30 16:01:00 -08:00
Cameron Perera cb972cfc8a refactor: 💡 update how we determine is pagination is supported (#2122) 2024-01-30 17:41:57 -06:00
Lisbet Alvarez 13f1c5cc23 docs: ✏️ remove bug fix from changelog (#2121) 2024-01-30 08:45:22 -08:00
Cameron Perera f366f0a858 fix: 🐛 update id to ids for target onboarding creation (#2120)
✅ Closes: https://hashicorp.atlassian.net/browse/ICU-12412
2024-01-30 09:13:20 -06:00
Cameron Perera 08d9801829 refactor: 💡 add -addr flag to add-token command (#2118)
* refactor: 💡 add -addr flag to add-token command

* style: 💄 remove old comment
2024-01-29 14:44:50 -06:00
Lisbet Alvarez 3f17435507 fix: 🐛 fix transition aborted error on storage bucket creation (#2119)
✅ Closes: https://hashicorp.atlassian.net/browse/ICU-12402
2024-01-29 12:00:07 -08:00
Lisbet Alvarez b63ddadf45 chore: 🤖 update changelog and version for v2.0.0 (#2117)
* chore: 🤖 update changelog and version for v2.0.0

* chore: 🤖 add pr link
2024-01-26 15:43:57 -08:00
Zhihe LiandCameron Perera 3721f63edf fix: 🐛 Fix client daemon usage on windows (#2115)
* fix: 🐛 Fix client daemon usage on windows

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

* refactor: 💡 Fix error handling

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

---------

Co-authored-by: Cameron Perera <cameron.perera@hashicorp.com>
2024-01-26 16:57:15 -06:00
Dharini Jeeva 8f34d83c15 Redirect on reapply error (#2114)
* chore: 🤖 redirect to list on reapply error
2024-01-26 10:13:16 -08:00
Cameron Perera def6959ee7 feat: 🎸 user can update clusterURL when controller unsupported (#2113)
* feat: 🎸 user can update clusterURL when controller unsupported

* test: 💍 add cluster url tests
2024-01-26 11:33:40 -06:00
Michael Li e76cc2eeeb test(admin/e2e): Fix yarn scripts (#2111) 2024-01-25 15:49:09 -05:00
Lisbet Alvarez 9a47a3ac5a Icu 12179 add doc links for storage policies (#2107)
* chore: 🤖 add doclinks for storage policies

✅ Closes: https://hashicorp.atlassian.net/browse/ICU-12179
2024-01-24 16:18:39 -08:00
Dharini Jeeva 2e1cba641c chore: 🤖 translation check and label (#2110) 2024-01-24 15:21:51 -08:00
Cameron Perera 842a84296a refactor: 💡 remove icon from sessions table for session id (#2108) 2024-01-24 16:12:07 -06:00
Cameron PereraandZhihe Li b86ce41e68 fix: 🐛 use filter query param to filter by org scope id (#2103)
* fix: 🐛 use filter query param to filter by org scope id

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

* refactor: 💡 remove duplicate call for scopes.scope model

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

* refactor: 💡 add filter to allTargets and sessions query

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

* refactor: 💡 reset query params for targets and sessions

on org scope change

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

* refactor: 💡 remove open/close parens from filter string

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

* refactor: 💡 Update logic on when to reset query parameters

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

* refactor: 💡 filter sessions query by parent scope isOrg

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

* refactor: 💡 update to & from transition references

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

* refactor: 💡 update to & from transition references for sessions

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

---------

Co-authored-by: Zhihe Li <zhihe.li@hashicorp.com>
2024-01-24 10:18:28 -06:00
Zhihe Li 5f9a66e421 fix: 🐛 Handle when requests to client daemon are returning 403 (#2105) 2024-01-23 16:31:21 -05:00
Dharini Jeeva 24fdd926f1 chore: 🤖 toggle translation based on state (#2106) 2024-01-23 12:13:50 -08:00
Dharini Jeeva db50bfc9df fix: 🐛 delete and retain_until should be readonly and Scope level policies (#2104)
* fix: 🐛 delete and retain_until should be readonly

* fix: 🐛 global scope should have policies from self and orgs
2024-01-23 11:31:43 -08:00
Zhihe Li 3f4beaada8 feat: 🎸 Add warning when upgrading to 2.0 for desktop client (#2101) 2024-01-22 19:06:01 -05:00
Lisbet Alvarez 5a9cbdd913 refactor: 💡 change filter name (#2102) 2024-01-22 14:07:11 -08:00
hashicorp-copywrite[bot] 314c1b36f4 [COMPLIANCE] Add Copyright and License Headers (#2100)
Co-authored-by: hashicorp-copywrite[bot] <110428419+hashicorp-copywrite[bot]@users.noreply.github.com>
2024-01-22 12:12:44 -05:00
Zhihe Li f71fc3a0a4 fix: 🐛 Fix errors not getting propagated up from client daemon (#2099) 2024-01-19 18:13:33 -05:00
Dharini Jeeva 5a74220f38 fix: 🐛 policy UI bug fix (#2098)
* fix: 🐛 policy UI bug fix
2024-01-19 14:06:51 -08:00
Cameron Perera 3f2fc63b5b fix: 🐛 remove client daemon params and pass remaining params (#2097)
✅ Closes: https://hashicorp.atlassian.net/browse/ICU-12301
2024-01-19 11:44:01 -06:00
Zhihe Li c0793cd254 test: 💍 Add tests for MQL expression generator (#2096) 2024-01-18 11:39:29 -05:00
Dharini JeevaandLisbet Alvarez fb9a080d2e feat: reapply storage policies to session recording (#2095)
* refactor: 💡 add global settings link

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

* fix: 🐛 route

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

* fix: 🐛 comment

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

* feat: 🎸 add reapply sp to session recording page

* fix: 🐛 normalize

* feat: 🎸 upates

* fix: 🐛 logs

* fix: 🐛 comment

* test: 💍 add tests

* fix: 🐛 normalizer, style

* fix: 🐛 normalize

* fix: 🐛 normalizw

* fix: 🐛 normalize

* test: 💍 add tests for serializer n normalizer

* fix: 🐛 name

* fix: 🐛 do not delete, send null

* fix: 🐛 return

---------

Co-authored-by: Lisbet Alvarez <lisbet.alvarez@hashicorp.com>
2024-01-17 14:37:54 -05:00
Lisbet Alvarez 9e0467cbf0 refactor: 💡 add global settings link (#2093)
refactor: 💡 add global settings link (#2093)
2024-01-17 08:37:09 -08:00
Devon Anderson c48fdb2017 refactor: 💡 Migrate worker detail view table to Hds::Table (#2081)
* refactor: 💡 Migrate `worker` detail view table to `Hds::Table`

Migrate `worker` detail view for `config_tags` table to `Hds::Table`

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

* refactor: 💡 fix lint errors

fix lint errors

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

* refactor: 💡 quick clean up of specificity for worker detail
view

Quick refactor and clean up of specificity for worker detail view

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

* refactor: 💡 include styles in `.list-wrapper-field` selector

Include styles in `.list-wrapper-field` selector

✅ Closes: https://hashicorp.atlassian.net/browse/ICU-11720
2024-01-17 09:34:08 -05:00
hashicorp-copywrite[bot]andCarlos Alcaide Corvo 60c5e25902 [COMPLIANCE] Add Copyright and License Headers (#2094)
Co-authored-by: hashicorp-copywrite[bot] <110428419+hashicorp-copywrite[bot]@users.noreply.github.com>
Co-authored-by: Carlos Alcaide Corvo <ccorvo@hashicorp.com>
2024-01-16 11:14:56 -08:00
Cameron Perera 1488bdf95e Icu 12027 let the user know if the dc isnt compatible with the controller and link them to the previous version (#2073)
* chore: 🤖 allow use of hashicorp release endpoints in desktop

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

* refactor: 💡 use page_size to bypass pagination in query adapter

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

* refactor: 💡 add list_token mirage scopes list response

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

* feat: 🎸 add logic for unsupported controllers

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

* refactor: 💡 add comment to application adapter change

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

* refactor: 💡 rename scopes controller method

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

* refactor: 💡 remove scopes controller

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

* refactor: 💡 use beforeModel and setupController hook for scopes

along with converting scopes model back to original state

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

* refactor: 💡 remove styling to hide modal dismiss button

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

* refactor: 💡 update comment for opening external links

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

* refactor: 💡 revert model hook changes for scopes

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

* test: 💍 remove target connect test from scopes acceptance tests

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

* test: 💍 add tests for unsupported controller logic

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

* test: 💍 update modal test to waitFor elements to render

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

* refactor: 💡 remove use of set and get from scopes router

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

* refactor: 💡 default isPaginationSupported to false

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

* test: 💍 remove unsupported controller tests

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

* test: 💍 add tests back but skip them

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

* test: 💍 fix failing tests

✅ Closes: https://hashicorp.atlassian.net/browse/ICU-12027
2024-01-16 10:17:47 -05:00
Lisbet AlvarezandZhihe Li 9e6d647949 Icu 12137 add additional session sorting and add default filters (#2084)
* chore: 🤖 add additional session sorting and add default filters

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

* test: 💍 fix test

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

* Update ui/desktop/app/controllers/scopes/scope/projects/sessions/index.js

Co-authored-by: Zhihe Li <zhihe.li@hashicorp.com>

---------

Co-authored-by: Zhihe Li <zhihe.li@hashicorp.com>
2024-01-16 10:17:46 -05:00
Zhihe Li 2e36d3c3e2 feat: 🎸 Add fallback if client daemon is down or errors (#2085)
* feat: 🎸 Add fallback if client daemon is down or errors
* test: 💍 Add tests for client daemon being down

✅ Closes: https://hashicorp.atlassian.net/browse/ICU-12026
2024-01-16 10:17:46 -05:00
Cameron Perera 9046c01238 feat: 🎸 target list will update according to org scope selected (#2083)
* feat: 🎸 target list will update according to org scope selected

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

* refactor: 💡 add comment to resetController logic

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

* feat: 🎸 filter sessions by org selected at global level

✅ Closes: https://hashicorp.atlassian.net/browse/ICU-12205
2024-01-16 10:17:46 -05:00
Zhihe Li ba0c7d5683 feat: 🎸 Add loading indicators for initial loads of resources (#2074)
* feat: 🎸 Add loading indicators for initial loads of resources

* refactor: 💡 Use HDS application state component

✅ Closes: https://hashicorp.atlassian.net/browse/ICU-12025
2024-01-16 10:17:46 -05:00
Zhihe Li 16a054519f fix: 🐛 Fix display of no results from type filter (#2075) 2024-01-16 10:17:46 -05:00
Lisbet Alvarez a1fbfdc1ad Icu 11804 filter targets by type (#2063)
* feat: 🎸 filter targets by type

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

* refactor: 💡 remove console.log

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

* docs: ✏️ fix comment typo

✅ Closes: https://hashicorp.atlassian.net/browse/ICU-11804
2024-01-16 10:17:46 -05:00
Lisbet Alvarez 21122f1f29 Icu-12125 cap the number of items rendered in dropdown component (#2060)
* perf: ⚡️ cap the number of items rendered in dropdown component

✅ Closes: https://hashicorp.atlassian.net/browse/ICU-12125
2024-01-16 10:17:46 -05:00
Cameron Perera a899ad0b74 refactor: 💡 uncomment on click handler for dropdown component (#2061)
* refactor: 💡 uncomment on click handler for dropdown component

* test: 💍 fix test
2024-01-16 10:17:46 -05:00
Lisbet Alvarez c7483e5602 feat: 🎸 filter sessions by status & scope (#2058)
* feat: 🎸 filter sessions by status

✅ Closes: https://hashicorp.atlassian.net/browse/ICU-12067
2024-01-16 10:17:46 -05:00
Cameron Perera 7fa2541ddb Icu 12069 clear current filters component for scopes filter (#2051)
* feat: 🎸 add filters applied tags under search/filter bar

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

* feat: 🎸 create Rose::FilterTags component

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

* refactor: 💡 use Rose::FilterTags component in targets list

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

* refactor: 💡 update FilterTags to handle multiple queryParams

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

* test: 💍 update dropdown component tests -  applyFilter

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

* feat: 🎸 create filter-tags component in core

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

* chore: 🤖 update core addon to export styles

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

* refactor: 💡 remove filter-tags component from rose addon

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

* chore: 🤖 update sass package version

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

* feat: 🎸 use FilterTags component in targets list screen

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

* refactor: 💡 reduce component complexity

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

* chore: 🤖 add sinon to core

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

* refactor: 💡 update how FilterTags displays filters

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

* refactor: 💡 trucate long tag names

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

* refactor: 💡 wrap FilterTags component in if this.filters

to fix issue of static text displaying before the dynamic tags

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

* refactor: 💡 address feedback

✅ Closes: https://hashicorp.atlassian.net/browse/ICU-12069
2024-01-16 10:17:46 -05:00
Lisbet AlvarezandZhihe Li 05553643a6 feat: 🎸 filter sessions by target (#2053)
* feat: 🎸 filter sessions by target

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

* docs: ✏️ add missing comment

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

* refactor: 💡 make action reusable

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

* refactor: 💡 remove unnecessary block

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

* refactor: 💡 fix tests, add hds app state

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

* perf: ⚡️ set limit of targets rendered in dropdown

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

* fix: 🐛 change from displayName to name

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

* Update addons/core/addon/components/dropdown/index.hbs

Co-authored-by: Zhihe Li <zhihe.li@hashicorp.com>

* refactor: 💡 remove # from if statement and remove .slice

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

---------

Co-authored-by: Zhihe Li <zhihe.li@hashicorp.com>
2024-01-16 10:17:46 -05:00
Zhihe Li 47cf7995d3 feat: 🎸 Add active session filter (#2052)
* feat: 🎸 Add active session filter

* fix: 🐛 Fix tests and verify client daemon calls are correct

✅ Closes: https://hashicorp.atlassian.net/browse/ICU-11803
2024-01-16 10:17:46 -05:00
Lisbet AlvarezandZhihe Li c06d18940d Icu 11916 add flyout for session in prgoress field (#2042)
* feat: 🎸 sessions flyout for targets list view

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

---------

Co-authored-by: Zhihe Li <zhihe.li@hashicorp.com>
2024-01-16 10:17:46 -05:00
Zhihe Li 1122735b87 fix: 🐛 Fix returning mirage data from client daemon mock (#2050) 2024-01-16 10:17:46 -05:00
Cameron Perera 9fec047506 Icu 12060 move rose filterable dropdown to core (#2048)
* feat: 🎸 generate new dropdown component in core

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

* feat: 🎸 add template and class code to new dropdown component

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

* chore: 🤖 add lodash package to core addon

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

* test: 💍 add tests for core/dropdown component

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

* refactor: 💡 use new core/dropdown in targets list screen

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

* refactor: 💡 remove rose/filterabledropdown

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

* feat: 🎸 add maxHeight to core/dropdown component

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

* style: 💄 fix lint errors in dropdown/index-tests

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

* refactor: 💡 update height to match designs

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

* chore: 🤖 remove lodash from ui/admin

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

* chore: 🤖 remove lodash from ui/desktop

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

* chore: 🤖 move lodash to devDep in core

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

* chore: 🤖 add lodash as core dependency

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

* test: 💍 use waitUntil & findAll instead of setTimeout

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

* chore: 🤖 add lodash as peerDependency for core

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

* refactor: 💡 update waitUntil with suggestion from PR

✅ Closes: https://hashicorp.atlassian.net/browse/ICU-12060
2024-01-16 10:17:46 -05:00
Zhihe Li 916b261cdf refactor: 💡 Optimize the retrieval of targets for scopes filter (#2047) 2024-01-16 10:17:46 -05:00
Zhihe Li 15da4ea69f fix: 🐛 Fix failing tests from rebase onto main (#2045) 2024-01-16 10:17:46 -05:00
Lisbet Alvarez f801f595f7 Icu 11915 add session in progress field to the table and populate it (#2028)
* initial support for sessions in targets list view
2024-01-16 10:17:46 -05:00
Cameron Perera 7af8e71a2d Icu 11802 filter targets by project scope (#2022)
* feat: 🎸 add ability to filter targets by scope

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

* refactor: 💡 update model hook signature comment

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

* refactor: 💡 remove await from cancel session route transition

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

* refactor: 💡 add comments to new controller methods

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

* refactor: 💡 add options to query for all targets

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

* refactor: 💡 handle ESC key press for dropdown

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

* feat: 🎸 add searching within scope dropdown list

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

* refactor: 💡 set pushToStore to false for all target query

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

* refactor: 💡 handle scopes not having names

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

* refactor: 💡 move fetch allTargets to controller

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

* refactor: 💡 fix rebase conflicts

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

* test: 💍 fix test

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

* refactor: 💡 update allTargets query to have empty query

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

* refactor: 💡 change let to const

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

* refactor: 💡 add replace: true to scopes query param

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

* refactor: 💡 add allTargets fetch back to model hook

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

* refactor: 💡 change on search to on input to trigger action

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

* test: 💍 fix test by adding more target returns to stub

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

* feat: 🎸 create filterable-dropdown rose component

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

* feat: 🎸 finish Rose::FilterableDropdown component

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

* feat: 🎸 use FilterableDropdown in targets table

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

* refactor: 🤖 move methods comment

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

* refactor: 💡 render Rose::FilterableDropdown correctly in test

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

* test: 💍 remove generated comments from tests

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

* refactor: 💡 improve readability of itemOptions getter

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

* refactor: 💡 change block parameters to uppercase

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

* test: 💍 skip generated tests until adding more

✅ Closes: https://hashicorp.atlassian.net/browse/ICU-11802
2024-01-16 10:17:46 -05:00
Zhihe Li 15d815c271 feat: 🎸 Add pagination component to targets (#2023)
* feat: 🎸 Add pagination component to targets
* test: 💍 Fix tests and add helper for client daemon search
* refactor: 💡 Update the returns from client daemon

✅ Closes: https://hashicorp.atlassian.net/browse/ICU-11905
2024-01-16 10:17:45 -05:00
Zhihe Li dfd484dbca fix: 🐛 Add support for not equals in MQL expression parsing (#2029) 2024-01-16 10:17:45 -05:00
Zhihe Li 50e4a2adbc feat: 🎸 Do not stop client daemon if it was already started (#2021)
✅ Closes: https://hashicorp.atlassian.net/browse/ICU-11932
2024-01-16 10:17:45 -05:00
Zhihe Li 7bc2ccb5ae refactor: 💡 Use a native class for the client daemon handler (#2026) 2024-01-16 10:17:45 -05:00
Zhihe Li 3f11019ef0 feat: 🎸 Add pagination support to client daemon handler (#2016)
✅ Closes: https://hashicorp.atlassian.net/browse/ICU-11743
2024-01-16 10:17:45 -05:00
Zhihe Li 1135f88cb7 feat: 🎸 Add debouncing for the search bar (#2008)
✅ Closes: https://hashicorp.atlassian.net/browse/ICU-11851
2024-01-16 10:17:45 -05:00
221ab1f7bd Icu 11748 add free search for targets (#1995)
* refactor: 💡 fix how we access socket_address from status call

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

* feat: 🎸 add free search capability to targets list

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

* test: 💍 update test asserts to look for hds appl state title

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

* refactor: 💡 remove filtering for yes, no, & narrow-results

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

* refactor: 💡 add aria-label to dropdown search input

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

* refactor: 💡 add to handleInput signature comment

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

* refactor: 💡 move buildQuery to client daemon handler

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

* refactor: 💡 Add new parser for MQL expressions

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

* refactor: 💡 use queryParams for searching

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

* fix: 🐛 Fix some MQL expressions not being properly filtered

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

* style: 💄 update handleSearchInput comment signature

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

* Update addons/api/addon/utils/mqlQuery.js

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

---------

Co-authored-by: Zhihe Li <zhihe.li@hashicorp.com>
Co-authored-by: Lisbet Alvarez <107949262+lisbet-alvarez@users.noreply.github.com>
2024-01-16 10:17:45 -05:00
Zhihe Li 4bf1a88764 feat: 🎸 Add handler to make search requests to client daemon (#1989)
✅ Closes: https://hashicorp.atlassian.net/browse/ICU-11691
2024-01-16 10:17:45 -05:00
Zhihe Li b8b970ce4d feat: 🎸 Add initial setup for client daemon integration (#1987)
✅ Closes: https://hashicorp.atlassian.net/browse/ICU-11702
2024-01-16 10:17:45 -05:00
dharini 25c6ed6100 chore: 🤖 fieldname update 2024-01-16 10:17:45 -05:00
Lisbet AlvarezandZhihe Li 550dee9ae0 Icu 11861 add sorting to session recording (#2005)
* refactor: 💡 add sorting to session recordings & sessions

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

* Update ui/admin/app/routes/scopes/scope/session-recordings.js

Co-authored-by: Zhihe Li <zhihe.li@hashicorp.com>

---------

Co-authored-by: Zhihe Li <zhihe.li@hashicorp.com>
2024-01-16 10:17:45 -05:00
Lisbet Alvarez 776c46f129 refactor: 💡 replace store.findAll with store.query (#2002)
✅ Closes: https://hashicorp.atlassian.net/browse/ICU-11825
2024-01-16 10:17:45 -05:00
Lisbet Alvarez 6ae3067dd9 refactor: 💡 remove unnecessary sorting due to pagination change (#1996)
✅ Closes: https://hashicorp.atlassian.net/browse/ICU-11787
2024-01-16 10:17:45 -05:00
Dharini Jeeva 459029530b chore: 🤖 Add support for pagination in query method (#1991)
* chore: 🤖 Add support for pagination in query method
2024-01-16 10:17:45 -05:00
Zhihe Li 7dbd581a37 feat: 🎸 Add setup for api handlers 2024-01-16 10:17:45 -05:00
Devon Anderson 9bbd914a3a refactor: 💡 Added middle alignment to all Hds::Tables (#2088)
Added middle alignment using `@valign='middle'` to all `Hds::Tables`

✅ Closes: https://hashicorp.atlassian.net/browse/ICU-12168
2024-01-15 10:23:32 -05:00
Dharini Jeeva 276713697a chore: 🤖 move overridable next to select (#2092)
* chore: 🤖 move overridable next to select

* fix: 🐛 lint
2024-01-12 17:20:30 -08:00
Dharini Jeeva ba786d2172 policy association form (#2089)
* feat: 🎸 add storage policy api and mirage
2024-01-12 15:01:16 -08:00
Dharini Jeeva ee4e19ace7 Add more options retain (#2090)
* chore: 🤖 add more options to rentention policy

* fix: 🐛 log

* fix: 🐛 exclude days
2024-01-12 14:33:36 -08:00
Dharini Jeeva eefb9eba4f feat: 🎸 scope policy association api changes (#2086)
scope policy association API changes
2024-01-12 11:29:19 -08:00
Dharini Jeeva 1cb3b708a2 feat: 🎸 create storage policy (#2079)
* feat: 🎸 add storage policy
2024-01-12 11:07:18 -08:00
Devon Anderson 8ad4e93ff7 refactor: 💡 Migrate workers-tags over to use Hds::Table (#2070)
* refactor: 💡 Migrate `workers-tags` over to use `Hds::Table`

Migrate `workers-tags` in `worker-create` form to use `Hds::Table`
instead of `Rose::Table`

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

* refactor: 💡 Use `Form::Field::List::Wrapper` for table

Use `Form::Field::List::Wrapper` for table implementation.

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

* refactor: 💡 Refactored how `worker_tags` is used in `table`

Cleaned up how `worker_tags` is used in the `Form::Field::ListWrapper`
component

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

* refactor: 💡 removed `console.log`

removed console.log

✅ Closes: https://hashicorp.atlassian.net/browse/ICU-11722
2024-01-11 17:23:24 -05:00
Devon Anderson 9241b7dd0e refactor: 💡 Migrate hostslist within host-set to Hds::Table (#2049)
* refactor: 💡 Migrate `hosts`list within host-set to `Hds::Table`

Migrate `hosts` list within host-set to `Hds::Table` from `Rose::Table`

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

* Update index.hbs

Not using `data-test` attribute for testing

* Update index.hbs

removed unused `data-test` selector

* refactor: 💡 quick lint error fix

Fix lint error in `hosts/index.hbs`

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

* refactor: 💡 refactor test to use `data-test` selector

Refactored hosts-test to use `data-test` selectors for grabbing
`Hds::Dropdown` toggle and interactive instead of long nested selector.

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

* Update index.hbs

spelling fix

* Update hosts-test.js

fixed spelling errors

* refactor: 💡 fix lint errors

Fix lint errors

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

* refactor: 💡 Use `Hds::Code::Snippet`

Migrate from `Copyable` component to use `Hds::Code::Snippet`

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

* refactor: 💡 refactor incorrect use of `Hds::Code::Snippet`

Refactor the incorrect usage of `Hds::Code::Snippet`

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

* refactor: 💡 refactor header of `Hds::Table`

Refactor conditional header of `Hds::Table`

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

* refactor: 💡 Refactored conditional header translations

Refactored conditional header translations to live in controller file
for `scopes/scope/host-catalogs/host-catalog/host-sets/host-set/hosts`

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

* refactor: 💡 Move conditional check for header labels into `js`

Move conditional logic for checking header lables into `controller` file

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

* refactor: 💡 Quick refactor for columns getter

Quick refactor to clean up getter that conditionally renders column
header label based on `isStatic` boolean

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

* refactor: 💡 Refactor `host-sets/host-set/hosts` tablee

Refactor `host-sets/host-set/hosts` table to adhere more to codebase

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

* refactor: 💡 rearrange attributes order for table

Rearrange attributes order for `Hds::Table` to keep inline with codebase
patterns.

✅ Closes: https://hashicorp.atlassian.net/browse/ICU-11728
2024-01-11 16:49:47 -05:00
0beec7b8fe [COMPLIANCE] Add Copyright and License Headers (#2077)
* [COMPLIANCE] Add Copyright and License Headers

* style: 💄 fix linting error

---------

Co-authored-by: hashicorp-copywrite[bot] <110428419+hashicorp-copywrite[bot]@users.noreply.github.com>
Co-authored-by: Zhihe Li <zhihe.li@hashicorp.com>
Co-authored-by: Lisbet Alvarez <lisbet.alvarez@hashicorp.com>
2024-01-10 16:49:12 -08:00
dependabot[bot] 9bcaa6dc68 chore(deps): bump follow-redirects from 1.15.2 to 1.15.4 (#2082)
Bumps [follow-redirects](https://github.com/follow-redirects/follow-redirects) from 1.15.2 to 1.15.4.
- [Release notes](https://github.com/follow-redirects/follow-redirects/releases)
- [Commits](https://github.com/follow-redirects/follow-redirects/compare/v1.15.2...v1.15.4)

---
updated-dependencies:
- dependency-name: follow-redirects
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-01-10 14:39:48 -05:00
Dharini Jeeva 3f178363d9 chore: 🤖 add attach and detach storage policy permissions (#2080)
* chore: 🤖 add attach and detach storage policy permissions
2024-01-09 11:39:28 -08:00
Devon Anderson 3810217ce7 refactor: 💡 Migrate credential-libraries-list to Hds::Table (#2067)
* refactor: 💡 Migrate `credential-libraries-list` to `Hds::Table`

Migrate `credential-libraries-list` to `Hds::Table` instead of
`Rose::Table`

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

* refactor: 💡 Fix broken test for navigating to `credentials-libraries`

Fix broken test for navigating to `credentials-libraries`

✅ Closes: https://hashicorp.atlassian.net/browse/ICU-11724
2024-01-09 10:27:44 -05:00
Dharini Jeeva b79eebf73a feat: storage policies list view (#2071)
policies list view
2024-01-08 15:12:49 -08:00
Zhihe Li b3abb658ab chore: 🤖 Fix breaking change in labeler when upgrading to v5 (#2078) 2024-01-08 15:06:46 -05:00
hashicorp-tsccr[bot]andhashicorp-tsccr[bot] 245cfb395e Result of tsccr-helper -log-level=info gha update -latest . (#2065)
Co-authored-by: hashicorp-tsccr[bot] <hashicorp-tsccr[bot]@users.noreply.github.com>
2024-01-08 14:10:13 -05:00
Devon Anderson adfa118ae5 refactor: 💡 Migrate credentials-list to Hds::Table (#2059)
* refactor: 💡 Migrate `credentials-list` to `Hds::Table`

Migrate `credentials-list` to `Hds::Table`

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

* refactor: 💡 Refactor table to use `B.data`

Originally the Proxy(Array) was not being taking in as a correct model
object when using the `@columns` synthax, now it seems to work perfectly
fine.

✅ Closes: https://hashicorp.atlassian.net/browse/ICU-11725
2024-01-05 12:23:46 -05:00
Devon Anderson cf0f4ab56a refactor: 💡 Refactor credential-stores-list to use Hds (#2066)
Refactor `credential-stores-list` to use `Hds::Tables`

✅ Closes: https://hashicorp.atlassian.net/browse/ICU-11723
2024-01-05 11:18:22 -05:00
Dharini Jeeva f40878034d fix: 🐛 transform (#2069)
* fix: 🐛 transform

* fix: 🐛 return null if undefined

* fix: 🐛 return null if no object
2024-01-03 17:37:14 -08:00
Dharini Jeeva 01a986e08b chore: 🤖 new routes for storage policy (#2056)
chore: 🤖 new routes for storage policy (#2056)
2024-01-03 12:05:23 -08:00
Dharini Jeeva e3406d9a95 feat: storage policy API and mirage changes (#2054)
* feat: 🎸 add storage policy API and mirage
2024-01-03 11:52:17 -08:00
Devon Anderson d4adbe4317 refactor: 💡 Migrate host-catalogs list to Hds::Table (#2055)
* refactor: 💡 Migrate host-catalogs list to `Hds::Table`

Migrated host-catalogs list to use `Hds::Table` instead of `Rose::Table`

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

* refactor: 💡 use `Hds::Text` component

Use `Hds::Text::Code` component for `code` element.

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

* refactor: 💡 Use `Hds::Text` and `Hds::Code::Snippet`

Refactor element to use `Hds`

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

* refactor: 💡 refactor incorrect usage of `Hds::Code::Snippet`

Refactor incorrect usage of `Hds::Code::Snippet`

✅ Closes: https://hashicorp.atlassian.net/browse/ICU-11726
2024-01-02 12:02:26 -05:00
Devon Anderson 01d4a329ab refactor: 💡 Migrate host-sets-list in host catalog to Hds (#2057)
* refactor: 💡 Migrate host-sets-list in host catalog to `Hds`

Migrate `host-catalog` `host-sets` list to use `Hds::Table`

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

* refactor: 💡 refactor incorrect use of `Hds::Code::Snippet`

Revactor incorrect use of `Hds::Code::Snippet`

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

* Update index.hbs

color for text should be `secondary`

* Update index.hbs

lint error

* refactor: 💡 quick lint fix

quick lint fix

✅ Closes: https://hashicorp.atlassian.net/browse/ICU-11727
2024-01-02 10:15:19 -05:00
Michael Li 659067dd08 test(admin/e2e): Add tags to tests (#2046) 2023-12-20 15:06:38 -05:00
Devon AndersonandCameron Perera ade1601d8d refactor: 💡 Refactor sessions-list to use Hds::Table (#2043)
* refactor: 💡 Refactor `sessions-list` to use `Hds::Table`

Refactor `sessions-list` to use `Hds::Table` instead of `Rose::table`

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

* refactor: 💡 Use `Hds::Text` component for `code` elements

Refactor `code` elements to use `Hds::Text::Code` component for text.

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

* Update ui/admin/app/templates/scopes/scope/sessions/index.hbs

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

* refactor: 💡 Refactor the condition around the `cancelSession`
 route-action, to use the `SessionAbility` for permssion to cancel
 session. Upgrade `Rose::Button` to `Hds::Button`.

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

---------

Co-authored-by: Cameron Perera <cameron.perera@hashicorp.com>
2023-12-14 17:27:09 -05:00
Devon Anderson 4550cd0965 refactor: 💡 Migrate host-catalog/host-list to use Hds (#2044)
* refactor: 💡 Migrate `host-catalog/host-list` to use `Hds`

Migrate `host-catalog/host-list` to use `Hds::Table`

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

* refactor: 💡 `Hds::Text` refactor

Refactored `code` and `p` tag elements to use new `HDS::Text` elements

✅ Closes: https://hashicorp.atlassian.net/browse/ICU-11729
2023-12-14 14:48:10 -05:00
Devon Anderson 0bbc33d073 refactor: 💡 Refactor targets-list to use Hds (#2041)
Migrate `targets-list` from `Rose::Table` to `Hds::Table`.

✅ Closes: https://hashicorp.atlassian.net/browse/ICU-11733
2023-12-13 10:28:32 -05:00
Devon Anderson 69a4eb53b9 refactor: 💡 Refactor workers list to use Hds::Table (#2038)
* refactor: 💡 Refactor workers list to use `Hds::Table`

Refactor workers list to use `Hds::Table` instead of `Rose`.

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

* Refactored `workers-list` table to use `margin-top` custom css instead
of removing the background from `Rose::Toolbar`
2023-12-12 14:52:31 -05:00
Dharini Jeeva d06111c803 fix: 🐛 target cred sources association (#2040) 2023-12-11 16:32:58 -08:00
Carlos Alcaide Corvo b51c8203ee chore: 🤖 Upgrade eslint-plugin-qunit (#2011)
* chore: 🤖 Upgrade eslint-plugin-qunit

* Delete unnecessary assert.expect from tests
2023-12-08 12:56:00 -08:00
Carlos Alcaide Corvo a94572214c chore: 🤖 Refactor main element padding (#2030)
* chore: 🤖 Refactor main element padding

Refactor main element padding to achieve consistency within all our
UI's. This is a quick solution until we adopt app-frame and follow the
same layouting pattern within all our UI's

✅ Closes: ICU-11960

* Delete unnecessasry @use size
2023-12-08 12:31:13 -08:00
Dharini Jeeva 751b5bef78 chore: 🤖 add skip prompts toggle (#2036)
* chore: 🤖 add skip prompts toggle
2023-12-08 09:17:36 -08:00
Kristin BradleyandDharini Jeeva 77f8235ebf Replace Rose::CodeEditor with Hds::CodeBlock within Desktop client (HDS-2827) (#2020)
* HDS-2827 Replace Rose::CodeEditor with Hds::CodeBlock on Create New Worker page

* HDS-2827 Replace Rose::CodeEditor with Hds::CodeBlock in credentials panel

* HDS-2827 Remove un-needed getters, fix formatting errors

* HDS-2827 Revert instances of Hds::CodeBlock added to create workers page

* HDS-2827 Fix failing test

* Apply suggestions from code review

* HDS-2827 Delete old unused css

* HDS-2827 Delete old css

---------

Co-authored-by: Dharini Jeeva <dharini@hashicorp.com>
2023-12-08 12:03:47 -05:00
9782f7e243 feat: 🎸 Implement time-remaining helper into desktop UI (#2018)
* feat: 🎸 implement helper

Implement `time-remainig` helper to display duration of a session for
desktop app.

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

* refactor: 💡 Refactored scenarios

Refactored `ipc.js` scenario to include `expiration_time` for a new
session.

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

* fix: 🐛 Fix add expiration_time when user has no grants to read (#2024)

* refactor: 💡 refactor styles

Removed `div` and added `Hds::Badge` to `h1` element.  Condensed and
renamed styling for title to `session-details-info`

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

* Refactored `projects/targets` controller to return the correct `expiration_time` field returned from CLI.  Cleaned up CSS for `session-details-info` attribute and wrapped `@model.displayname` in span tag.

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

* Update ui/desktop/app/controllers/scopes/scope/projects/targets/index.js

mixed naming expiration field on payload to store

Co-authored-by: Zhihe Li <zhihe.li@hashicorp.com>

* refactor: 💡 refactored page header

Refactored `sessions` header to use `<Hds::Text::Dislpay/>` instead of a
span.

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

* refactor: 💡 refactor cli response

Refactor `expiration` field from CLI response to be the correct
definition

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

* refactor: 💡 refactor sessions layout

Removed span as parent of header information, and pushed styles to
yielded page.header. Fixed stub in test

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

---------

Co-authored-by: Carlos Alcaide Corvo <ccorvo@hashicorp.com>
Co-authored-by: Zhihe Li <zhihe.li@hashicorp.com>
2023-12-07 16:01:57 -05:00
Michael Li 6328cc1fcf test(admin/e2e): Update tests to account for changes in 0.14.3 (#2033)
* test(admin/e2e): Modify password locators due to new Show Password button

* test(admin/e2e): Update breadcrumbs locators due to design updates

Previously, all breadcrumb items were links, but that is no longer the case for the active breadcrumb.
2023-12-07 11:42:04 -05:00
Dharini Jeeva b986064447 fix: 🐛 name (#2035) 2023-12-07 08:14:09 -08:00
Dharini Jeeva 6fbf243c31 fix: 🐛 oidc account id (#2034) 2023-12-06 16:10:44 -08:00
Carlos Alcaide Corvo 66eca93f56 chore: 🤖 Upgrade electron-forge (#2031)
Upgrade electron-forge to the latest version
2023-12-05 14:11:02 -08:00
45d706dd40 Result of tsccr-helper -log-level=info -pin-all-workflows . (#2025)
Co-authored-by: hashicorp-tsccr[bot] <hashicorp-tsccr[bot]@users.noreply.github.com>
Co-authored-by: Dharini Jeeva <dharini@hashicorp.com>
Co-authored-by: Carlos Alcaide Corvo <ccorvo@hashicorp.com>
2023-12-04 15:06:17 -08:00
Carlos Alcaide Corvo 99cf4c8d81 chore: 🤖 Update DC main element padding (#2009)
Update Desktop Client main element padding to look like app-frame HDS implementation within cloud-ui.

✅ Closes: https://hashicorp.atlassian.net/browse/ICU-10497
2023-12-04 14:06:45 -08:00
Carlos Alcaide Corvo 49923d968e chore: 🤖 Upgrade browserslist (#2019) 2023-12-04 10:44:58 -08:00
hashicorp-copywrite[bot] b4a83a46d1 [COMPLIANCE] Add Copyright and License Headers (#2027)
Co-authored-by: hashicorp-copywrite[bot] <110428419+hashicorp-copywrite[bot]@users.noreply.github.com>
2023-12-04 09:13:32 -08:00
Kristin Bradleyanddharini 238ced63f7 HDS-2827 Bump HDS to latest version (#2017)
* HDS-2827 Bump HDS to latest version

* HDS-2827 Bump up to latest version

* chore: 🤖 yarn lock

---------

Co-authored-by: dharini <dharini@hashicorp.com>
2023-11-30 13:02:08 -05:00
dependabot[bot]andDharini Jeeva 602e4e62c3 chore(deps): bump semver from 5.7.1 to 5.7.2 (#2014)
Bumps [semver](https://github.com/npm/node-semver) from 5.7.1 to 5.7.2.
- [Release notes](https://github.com/npm/node-semver/releases)
- [Changelog](https://github.com/npm/node-semver/blob/v5.7.2/CHANGELOG.md)
- [Commits](https://github.com/npm/node-semver/compare/v5.7.1...v5.7.2)

---
updated-dependencies:
- dependency-name: semver
  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>
2023-11-28 18:13:08 -08:00
Devon Anderson f282dbb5b1 feat: 🎸 Create time-remaining helper (#2012)
* feat: 🎸 create helper

Create `time-remaining` helper to track remaining session time.

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

* refactor: 💡 Clean up code for time-remaining helper

Moved time remaining helper into `core` addons folder. Cleaned up the
`time-remaining` helper to use the `DurationUnitFormat` service.

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

* Update session.hbs

removed test implementation

* refactor: 💡 files added for helper

files added for helper

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

* Update session.hbs

fix linting

* refactor: 💡 fix uneeded spacing

Fix spacing on hbs file used for testing time-remaining helper

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

* refactor: 💡 refactor time-remaining helper

Cleaned up code that was returning a string if `differenceInSeconds` was
less than or equal to zero. Code is now conditionally checking in the
`differenceInSeconds` variable if the `difference` is greater than zero.
If it is not then it will return zero and let the `DurationUnitFormat`
handle the rest.

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

* refactor: 💡 fix failing test

Fix failing `time-remaining` test

✅ Closes: https://hashicorp.atlassian.net/browse/ICU-10519
2023-11-28 17:42:22 -05:00
Dharini Jeeva 3f2f2ba756 feat: 🎸 Allow prompts in oidc auth method form (#2007)
* feat: 🎸 Allow prompts in OIDC auth method form
2023-11-28 11:59:16 -08:00
Carlos Alcaide Corvo 02a89bd7ba Chore upgrade eslint and deps (#2010)
* chore: 🤖 Upgrade eslint 

* chore: 🤖 Upgrade eslint-config-prettier

* chore: 🤖 Upgrade eslint-plugin-ember 

* chore: 🤖 Upgrade eslint-plugin-n
2023-11-27 15:31:39 -08:00
Kristin Bradley a891f7a1a5 Boundary: Delete RoseFooter files (HDS-2805) (#2003)
* HDS-2805 Delete RoseFooter files
2023-11-27 07:58:54 -08:00
Devon Anderson 019b3e7390 chore: 🤖 Update stylelint config dependency (#2000)
* chore: 🤖 Update dependency

Updated `styelint-config-standard-scss` to fix incorrect peer dependency
warning for `styelint`

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

* Update _notify.scss

remove test for media query

* refactor: 💡 refactor media queries

Refactor all media queries to include `context` notation.

✅ Closes: https://hashicorp.atlassian.net/browse/ICU-11818
2023-11-22 15:42:24 -05:00
Zhihe Li bcf004b8a4 Reformat codebase with trailing commas in functions (#2006)
* style: 💄 Update trailing commas in API

* style: 💄 Update trailing commas in core

* style: 💄 Update trailing commas in rose

* style: 💄 Update trailing commas in admin

* style: 💄 Update trailing commas in desktop
2023-11-22 14:07:41 -05:00
Carlos Alcaide Corvo cb3a9e3bdc chore: 🤖 Add custom key handler for windows (#2001)
* chore: 🤖 Add custom key handler for windows

Add custom key handler only for Windows OS so we achieve Ctrl+C to copy
within the embedded terminal

* Await for clipboard promise to complete
2023-11-22 09:21:25 -08:00
Lisbet AlvarezandCarlos Alcaide Corvo 4127f6abd7 chore: 🤖 update test release trigger (#1978)
* chore: 🤖 add trigger for new workflow
---------

Co-authored-by: Carlos Alcaide Corvo <ccorvo@hashicorp.com>
2023-11-20 13:12:23 -08:00
hashicorp-copywrite[bot] 45a3cb8d34 [COMPLIANCE] Add Copyright and License Headers (#1999)
Co-authored-by: hashicorp-copywrite[bot] <110428419+hashicorp-copywrite[bot]@users.noreply.github.com>
2023-11-20 08:41:36 -08:00
Kristin Bradley e96171cab0 Replace Rose::Footer with Hds::AppFooter component (HDS-2805) (#1994)
* HDS-2805 Replace Rose::Footer with Hds::AppFooter
2023-11-17 15:30:44 -08:00
Devon Anderson a7bf9a1071 fix: 🐛 testing upgrading ember-electron (#1997)
This is a test to see if upgrading ember-electron will fix issues with
`yarn start:desktop` build failures
2023-11-17 12:38:53 -05:00
Devon Anderson 3b3a00e1ee Upgrade desktop UI to Ember 4.12.2 (#1990)
* Upgrade desktop UI to Ember 4.12.2

* refactor: 💡 refactor scripts

Refactor concurrently scripts, and removed duplicate entries in
`eslintrc.js`

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

* refactor: 💡 peer dependencies

Revert changes to `peerDependencies`.

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

* refactor: 💡 revert config back before upgrade

Revert `styelint-standard-config-scss` back to 6.0.0 so that it can be
put into seperate ticket.

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

* Update _notify.scss

fix misspelling

* refactor: 💡 revert dependency

Revert `stylelint-config-standard-scss` back to original version

✅ Closes: https://hashicorp.atlassian.net/browse/ICU-11747
2023-11-15 11:29:24 -05:00
Carlos Alcaide Corvo 222f0c35b8 Upgrade playwright within desktop as blocker to run node 18 within gh runners (#1993) 2023-11-10 17:10:26 -08:00
Zhihe Li 666491548d fix: 🐛 Fix broken hot reloading for desktop client (#1992) 2023-11-10 14:23:32 -05:00
Devon Anderson 2558ee1353 chore: 🤖 Upgrading to Ember 4.12.2 (#1988)
* chore: 🤖 Upgrading to Ember 4.12.2

Upgrading `admin/ui` to Ember 4.12.2

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

* refactor: 💡 Removed unused package

Removed unused `stylelint` package for `css`

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

* refactor: 💡 removed unused dependency

Removed `stylelint-prettier` dependency

✅ Closes: https://hashicorp.atlassian.net/browse/ICU-11330
2023-11-10 11:21:52 -05:00
Dharini Jeeva c5edd4dd52 Update auth methods form (#1981)
Update auth methods form (#1981)
2023-11-07 11:27:48 -08:00
hashicorp-copywrite[bot] f102e7fca2 [COMPLIANCE] Add Copyright and License Headers (#1986)
Co-authored-by: hashicorp-copywrite[bot] <110428419+hashicorp-copywrite[bot]@users.noreply.github.com>
2023-11-06 09:28:39 -08:00
Lisbet AlvarezandZhihe Li f593e6a8b1 chore: 🤖 update cli version & changelog in desktop (#1985)
* chore: 🤖 update cli version in desktop

* docs: ✏️ update changelog

* Update ui/desktop/CHANGELOG.md

Co-authored-by: Zhihe Li <zhihe.li@hashicorp.com>

---------

Co-authored-by: Zhihe Li <zhihe.li@hashicorp.com>
2023-11-03 16:03:07 -07:00
Cameron PereraandDharini Jeeva f54d48c380 refactor: 💡 allow target connection even with no read ability (#1984)
* refactor: 💡 allow target connection even with no read ability

* Update ui/desktop/tests/acceptance/projects/targets/index-test.js

Co-authored-by: Dharini Jeeva <dharini@hashicorp.com>

* refactor: 💡 remove unneeded await from transitionTo

---------

Co-authored-by: Dharini Jeeva <dharini@hashicorp.com>
2023-11-03 16:01:51 -05:00
0129784322 fix url when user tries to access resource with incorrect url (#1958)
* refactor: 💡 auth-method, account, & managed abilities & routes

* refactor: 💡 credential store resources abilities & routes

* refactor: 💡 group abilities & routes

* refactor: 💡 host-catalog resources abilities & routes

* refactor: 💡 role abilities & routes

* test: 💍 fix route-info-test

* test: 💍 fix host serializer tests

* test: 💍 fix create-test for host-sets

* refactor: 💡 session recording resources abilities & routes

* refactor: 💡 storage bucket abilities & routes

* refactor: 💡 target abilities & routes

* refactor: 💡 user abilities & routes

* refactor: 💡 worker abilities & routes

* refactor: 💡 remove ability changes and add comments

* Update ui/admin/app/utils/route-info.js

Co-authored-by: Zhihe Li <zhihe.li@hashicorp.com>

* test: 💍 add test cases and rename util file

* refactor: 💡 remove dup file and update imports

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

* docs: ✏️ update comments & remove console.log

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

* Update ui/admin/app/routes/scopes/scope/auth-methods/auth-method.js

Co-authored-by: Dharini Jeeva <dharini@hashicorp.com>

---------

Co-authored-by: Zhihe Li <zhihe.li@hashicorp.com>
Co-authored-by: Dharini Jeeva <dharini@hashicorp.com>
2023-11-02 16:08:25 -07:00
Zhihe Li 7317ca2ff5 fix: 🐛 Fix issue with brokered credentials that overflow (#1982)
✅ Closes: https://hashicorp.atlassian.net/browse/ICU-11368
2023-11-02 15:16:22 -04:00
Zhihe Li 1ddabf4980 feat: 🎸 Add checks for cancel permissions in desktop sessions (#1980)
* feat: 🎸 Add checks for cancel permissions in desktop sessions

* chore: 🤖 Move model hook from session to session.index
2023-11-02 13:42:51 -04:00
Devon AndersonandLisbet Alvarez a574023c05 chore: 🤖 Upgrade addons/rose dependencies (#1973)
* chore: 🤖 Upgrade addons/rose dependencies

Upgraded `addons/rose` dependencies to match other addons. Lint fixes,
and fixed scripts for concurrently

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

* v4.4.1...v4.12.2

* Update ember-try.js

change scenarios to match 4.12.2

* Update addons/rose/tests/integration/components/rose/button-test.js

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

* Update ember-try.js

originally had the right scenarios for 4.
12.2

* chore: 🤖 upgrade ember-cli-babel

Upgrade ember-cli-babel to match other addons

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

* Update button-test.js

fix test declaration statement

---------

Co-authored-by: Lisbet Alvarez <107949262+lisbet-alvarez@users.noreply.github.com>
2023-11-01 15:52:00 -04:00
Cameron Perera 861562201b refactor: 💡 remove unused target/sessions controller (#1979) 2023-11-01 13:54:36 -05:00
4cdcaefe15 Result of tsccr-helper -log-level=info -pin-all-workflows . (#1977)
Co-authored-by: hashicorp-tsccr[bot] <hashicorp-tsccr[bot]@users.noreply.github.com>
Co-authored-by: Dharini Jeeva <dharini@hashicorp.com>
2023-11-01 11:22:41 -07:00
Dharini Jeeva e2487b7e98 Fix electron clipboard action (#1976)
* fix: 🐛 allow clipboard write action
2023-11-01 10:06:03 -07:00
Cameron Perera f879bbb1ec Session permissions issue (#1975)
* refactor: 💡 session isCancelable to isAvailable

* refactor: 💡 check for target info for showing target details

* refactor: 💡 add fallback for session data from connect command

* refactor: 💡 remove extra divs

* refactor: 💡 remove await from peekRecord of a session

* test: 💍 add test for no read permission for sessions

* test: 💍 reset global qunit after test is done
2023-11-01 11:22:18 -05:00
Zhihe Li 933e272764 fix: 🐛 Add read:self permission for sessions in ability check (#1974) 2023-11-01 12:06:40 -04:00
dependabot[bot]andZhihe Li 2953635aeb chore(deps): bump browserify-sign from 4.2.1 to 4.2.2 (#1969)
Bumps [browserify-sign](https://github.com/crypto-browserify/browserify-sign) from 4.2.1 to 4.2.2.
- [Changelog](https://github.com/browserify/browserify-sign/blob/main/CHANGELOG.md)
- [Commits](https://github.com/crypto-browserify/browserify-sign/compare/v4.2.1...v4.2.2)

---
updated-dependencies:
- dependency-name: browserify-sign
  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>
2023-10-31 12:38:55 -04:00
hashicorp-copywrite[bot]andZhihe Li 194561e1f8 [COMPLIANCE] Add Copyright and License Headers (#1972)
Co-authored-by: hashicorp-copywrite[bot] <110428419+hashicorp-copywrite[bot]@users.noreply.github.com>
Co-authored-by: Zhihe Li <zhihe.li@hashicorp.com>
2023-10-31 12:17:53 -04:00
Zhihe Li 4a3d8eee63 feat: 🎸 Allow auto connect to SSH targets on windows (#1971) 2023-10-30 18:16:40 -04:00
Dharini Jeeva 7d6f3df140 chore: update HDS to 3.0.2 (#1970)
* chore: 🤖 update to hds 3.0.2
2023-10-30 12:56:38 -07:00
Dharini Jeeva 722acdc1fc chore: 🤖 refactor key value list component, text input support (#1957)
refactor: 💡 refactor list wrapper component and fix test
2023-10-30 12:30:05 -07:00
Carlos Alcaide Corvoandcameronperera 3f8e39d0e1 Host set permission issue (#1968)
* refactor: 💡 allow for graceful error handling when connecting

to a target where host-sets cannot be fetched

* refactor: 💡 update for loop to for...of loop

* Move fetching host from target to session domain

* Decouple getting target host-sets and getting hosts from the host-sets, now this code is extracted in 2 methods. Now if the user does not have permissions to fetch host or host-sets we do not show an error and we allow for quick-connect approach

* Fix a check within getHostsFromHostSets

* Change a for loop for Promise.all within getTargetHostSets

* Change a for loop for Promise.All within getHostsFromHostSets

* Delete unnecessary condition

* Delete unnecessary condition

* chore: 🤖 remove host sources from target mirage factory

by default it uses address when using 'withAssociations'

* test: 💍 update target address tests to use 'withOneHost'

* test: 💍 remove connect tests from scopes acceptance tests

* refactor: 💡 remove can initiate connect target ability

and associated code and tests

* refactor: 💡 update target model afterModel hook, and preconnect

* refactor: 💡 revert 'withAssociations' mirage change

* test: 💍 add tests for permissions issues for host-sets and host

* test: 💍 visiting session without permissions to read hosts

---------

Co-authored-by: cameronperera <cameron.perera@hashicorp.com>
2023-10-30 12:54:37 -05:00
Devon Anderson 9e7852f18d chore: 🤖 Upgrade addons/core to Ember 4.12.2 (#1965)
* chore: 🤖 Upgrade `addons/core` to Ember 4.12.2

Upgrade `addons/core` to Ember 4.12.2

✅ Closes: ICU-11341

* refactor: 💡 testing updating plugin-proposal-decorators version

Update `@babel/plugin-proposal-decorators` to latest version.

* refactor: 💡 testing legacy plugin-proposa-decorators version

Testin `legacy` version for `plugin-proposal-decorators` plugin

* refactor: 💡 testing plugin-proposal-decorators

Testing `@babel/plugin-proposal-decorators`

* refactor: 💡 Revert @babel/exlint-parser to previous version

Revert `@babel/eslint-parser` to use version 2018 EcmaScript version
until further research is done on latest versions

* Update package.json

put @babel/core back into `devDependencies`

* refactor: 💡 testing linging changes

Pushed ember-tempalate-lint, prettier, and ember template lint plugin
for prettier to latest versions to test why CI builds are not passing.

✅ Closes: https://hashicorp.atlassian.net/browse/ICU-11341
2023-10-27 11:10:30 -04:00
hashicorp-copywrite[bot]andZhihe Li c548c381bf [COMPLIANCE] Add Copyright and License Headers (#1966)
Co-authored-by: hashicorp-copywrite[bot] <110428419+hashicorp-copywrite[bot]@users.noreply.github.com>
Co-authored-by: Zhihe Li <zhihe.li@hashicorp.com>
2023-10-24 14:31:07 -04:00
Zhihe Li 63be0f3aec chore: 🤖 Update commitizen hook to add jira link automatically (#1959) 2023-10-24 13:07:27 -04:00
Susmitha Girumala 8e4fac5ce2 Manually trigger admin ui build (#1964) 2023-10-20 10:16:06 +02:00
Dharini Jeeva 2a9666285a fix: 🐛 name (#1963) 2023-10-20 00:41:25 -07:00
Dharini Jeeva bff94d6b4d fix: 🐛 release name (#1962) 2023-10-20 00:12:08 -07:00
Michael Li 5b8fc06e21 test(admin/e2e): Update test timeout to 60s (#1955) 2023-10-17 13:06:21 -04:00
Lisbet AlvarezandZhihe Li a20483d1af update breadcrumbs to use hds::breadcrumbs (#1934)
* refactor: 💡 initial changes for updating breadcrumbs to use hds

* refactor: 💡 add breadcrumbs to all paths

* refactor: 💡 add more hds breadcrumbs to remaining paths

* refactor: 💡 remove BreadCrumbs from templates

* refactor: 💡 remove breadcrumb only controller files

* test: 💍 remove unnused test files & add missing tests

* test: 💍 update tests

* test: 💍 add missing scope in test

* test: 💍 fix test

* refactor: 💡 remove icons

* refactor: 💡 remove addon and use service instead

* docs: ✏️ add comment to breadcrumb service

* test: 💍 update service unit test

* docs: ✏️ add comments to breadcrumb components

* Update ui/admin/app/components/breadcrumbs/container/index.js

Co-authored-by: Zhihe Li <zhihe.li@hashicorp.com>

---------

Co-authored-by: Zhihe Li <zhihe.li@hashicorp.com>
2023-10-17 09:45:34 -07:00
dependabot[bot] 0bf5221389 chore(deps): bump @babel/traverse from 7.15.0 to 7.23.2 (#1954)
Bumps [@babel/traverse](https://github.com/babel/babel/tree/HEAD/packages/babel-traverse) from 7.15.0 to 7.23.2.
- [Release notes](https://github.com/babel/babel/releases)
- [Changelog](https://github.com/babel/babel/blob/main/CHANGELOG.md)
- [Commits](https://github.com/babel/babel/commits/v7.23.2/packages/babel-traverse)

---
updated-dependencies:
- dependency-name: "@babel/traverse"
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-10-17 15:59:41 +02:00
hashicorp-copywrite[bot] 297db470bd [COMPLIANCE] Add Copyright and License Headers (#1953)
Co-authored-by: hashicorp-copywrite[bot] <110428419+hashicorp-copywrite[bot]@users.noreply.github.com>
2023-10-16 13:29:31 -04:00
Dharini Jeeva 91a6023145 Refactor key value list component (#1949)
* refactor: 💡 update keyvalue list component to allow only rows
2023-10-12 14:42:23 -07:00
Devon Anderson 7b96dd1f81 Upgrade addons/auth to Ember 4.12 (#1947)
* Ember `addon/auth` upgrade v4.4.1...v4.12.2

* Update .npmignore

* refactor: 💡 Quick refactor

Refactor `.eslintrc.js` to current `ecmaVersion` and use latest
`babelOptions`. Revert `.prettier.js` to use previous overrides. Setup
scripts to use `concurrently` instead of `npm-run-all`

* refactor: 💡 removed `npm-run-all`

Removed `npm-run-all` from package.json
2023-10-11 17:17:42 -04:00
Carlos Alcaide Corvo aee55cb171 Chore icu 9086 audit resolutions (#1928) 2023-10-11 12:09:23 +02:00
Carlos Alcaide Corvo 370b3ea1fb Chore icu 9085 audit resolutions (#1927)
* chore: 🤖 Delete shell-quote from resolutions

* chore: 🤖 Delete hawk from resolutions

* chore: 🤖 Modify resolutions for async
2023-10-11 11:38:34 +02:00
Carlos Alcaide Corvo 4f972a82d6 chore: 🤖 Modify ansi-html resolution (#1922) 2023-10-11 10:48:06 +02:00
1256 changed files with 32692 additions and 17189 deletions

No files matched your search

+14 -7
View File
@@ -2,22 +2,29 @@
# SPDX-License-Identifier: MPL-2.0
addons:
- addons/**/*
- changed-files:
- any-glob-to-any-file: "addons/**/*"
api-addon:
- addons/api/**/*
- changed-files:
- any-glob-to-any-file: "addons/api/**/*"
auth-addon:
- addons/auth/**/*
- changed-files:
- any-glob-to-any-file: "addons/auth/**/*"
styles-addon:
- addons/rose/**/*
- changed-files:
- any-glob-to-any-file: "addons/rose/**/*"
ui:
- ui/**/*
- changed-files:
- any-glob-to-any-file: "ui/**/*"
admin:
- ui/admin/**/*
- changed-files:
- any-glob-to-any-file: "ui/admin/**/*"
desktop:
- ui/desktop/**/*
- changed-files:
- any-glob-to-any-file: "ui/desktop/**/*"
+22 -20
View File
@@ -3,21 +3,23 @@ on:
push:
branches:
- main
- "release/**"
workflow_dispatch:
jobs:
dependencies:
name: Install dependencies
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@8ade135a41bc03ea155e62e844d188df1ea18608 # v4.1.0
- uses: actions/cache@704facf57e6136b1bc63b828d79edcd491f0ee84 # v3.3.2
- uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
- uses: actions/cache@0c45773b623bea8c8e75f6c82b208c3cf94ea4f9 # v4.0.2
id: node-modules-cache
with:
path: '**/node_modules'
path: "**/node_modules"
key: node-modules-${{ hashFiles('**/yarn.lock') }}
restore-keys: |
node-modules-
- uses: actions/setup-node@5e21ff4d9bc1a8cf6de233a3057d20ec6b3fb69d # v3.8.1
- uses: actions/setup-node@60edb5dd545a775178f52524783378180af0d1f8 # v4.0.2
with:
node-version: 16
- run: yarn install
@@ -26,26 +28,26 @@ jobs:
needs: [dependencies]
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@8ade135a41bc03ea155e62e844d188df1ea18608 # v4.1.0
- uses: actions/cache@704facf57e6136b1bc63b828d79edcd491f0ee84 # v3.3.2
- uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
- uses: actions/cache@0c45773b623bea8c8e75f6c82b208c3cf94ea4f9 # v4.0.2
id: node-modules-cache
with:
path: '**/node_modules'
path: "**/node_modules"
key: node-modules-${{ hashFiles('**/yarn.lock') }}
restore-keys: |
node-modules-
- name: Build
uses: actions/setup-node@5e21ff4d9bc1a8cf6de233a3057d20ec6b3fb69d # v3.8.1
uses: actions/setup-node@60edb5dd545a775178f52524783378180af0d1f8 # v4.0.2
with:
node-version: 16
- run: yarn run build:ui:admin:oss
- name: Upload artifact admin-ui
uses: actions/upload-artifact@a8a3f3ad30e3422c9c7b888a15615d19a852ae32 # v3.1.3
uses: actions/upload-artifact@5d5d22a31266ced268874388b861e4b58bb5c2f3 # v4.3.1
with:
name: admin-ui
path: ./ui/admin/dist/
- name: Upload artifact OSS admin UI
uses: actions/upload-artifact@a8a3f3ad30e3422c9c7b888a15615d19a852ae32 # v3.1.3
uses: actions/upload-artifact@5d5d22a31266ced268874388b861e4b58bb5c2f3 # v4.3.1
with:
name: admin-ui-oss
path: ./ui/admin/dist/
@@ -54,21 +56,21 @@ jobs:
needs: [dependencies]
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@8ade135a41bc03ea155e62e844d188df1ea18608 # v4.1.0
- uses: actions/cache@704facf57e6136b1bc63b828d79edcd491f0ee84 # v3.3.2
- uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
- uses: actions/cache@0c45773b623bea8c8e75f6c82b208c3cf94ea4f9 # v4.0.2
id: node-modules-cache
with:
path: '**/node_modules'
path: "**/node_modules"
key: node-modules-${{ hashFiles('**/yarn.lock') }}
restore-keys: |
node-modules-
- name: Build
uses: actions/setup-node@5e21ff4d9bc1a8cf6de233a3057d20ec6b3fb69d # v3.8.1
uses: actions/setup-node@60edb5dd545a775178f52524783378180af0d1f8 # v4.0.2
with:
node-version: 16
- run: yarn run build:ui:admin:enterprise
- name: Upload artifact enterprise admin UI
uses: actions/upload-artifact@a8a3f3ad30e3422c9c7b888a15615d19a852ae32 # v3.1.3
uses: actions/upload-artifact@5d5d22a31266ced268874388b861e4b58bb5c2f3 # v4.3.1
with:
name: admin-ui-ent
path: ./ui/admin/dist/
@@ -77,21 +79,21 @@ jobs:
needs: [dependencies]
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@8ade135a41bc03ea155e62e844d188df1ea18608 # v4.1.0
- uses: actions/cache@704facf57e6136b1bc63b828d79edcd491f0ee84 # v3.3.2
- uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
- uses: actions/cache@0c45773b623bea8c8e75f6c82b208c3cf94ea4f9 # v4.0.2
id: node-modules-cache
with:
path: '**/node_modules'
path: "**/node_modules"
key: node-modules-${{ hashFiles('**/yarn.lock') }}
restore-keys: |
node-modules-
- name: Build
uses: actions/setup-node@5e21ff4d9bc1a8cf6de233a3057d20ec6b3fb69d # v3.8.1
uses: actions/setup-node@60edb5dd545a775178f52524783378180af0d1f8 # v4.0.2
with:
node-version: 16
- run: yarn run build:ui:admin:hcp
- name: Upload artifact HCP admin UI
uses: actions/upload-artifact@a8a3f3ad30e3422c9c7b888a15615d19a852ae32 # v3.1.3
uses: actions/upload-artifact@5d5d22a31266ced268874388b861e4b58bb5c2f3 # v4.3.1
with:
name: admin-ui-hcp
path: ./ui/admin/dist/
@@ -0,0 +1,34 @@
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@8ade135a41bc03ea155e62e844d188df1ea18608 # v4.1.0
uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
# Initializes the CodeQL tools for scanning.
- name: Initialize CodeQL
uses: github/codeql-action/init@8e0b1c74b1d5a0077b04d064c76ee714d3da7637 # codeql-bundle-v2.14.6
uses: github/codeql-action/init@423a04bb2cb7cd2643007122588f1387778f14d0 # codeql-bundle-v2.16.5
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@8e0b1c74b1d5a0077b04d064c76ee714d3da7637 # codeql-bundle-v2.14.6
uses: github/codeql-action/analyze@423a04bb2cb7cd2643007122588f1387778f14d0 # codeql-bundle-v2.16.5
+1 -1
View File
@@ -6,6 +6,6 @@ jobs:
triage:
runs-on: ubuntu-latest
steps:
- uses: actions/labeler@ac9175f8a1f3625fd0d4fb234536d26811351594 # v4.3.0
- uses: actions/labeler@8558fd74291d67161a8a78ce36a881fa63b766a9 # v5.0.0
with:
repo-token: "${{ secrets.GITHUB_TOKEN }}"
+12 -12
View File
@@ -6,15 +6,15 @@ jobs:
name: Install dependencies
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@8ade135a41bc03ea155e62e844d188df1ea18608 # v4.1.0
- uses: actions/cache@704facf57e6136b1bc63b828d79edcd491f0ee84 # v3.3.2
- uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
- uses: actions/cache@0c45773b623bea8c8e75f6c82b208c3cf94ea4f9 # v4.0.2
id: node-modules-cache
with:
path: '**/node_modules'
key: node-modules-${{ hashFiles('**/yarn.lock') }}
restore-keys: |
node-modules-
- uses: actions/setup-node@5e21ff4d9bc1a8cf6de233a3057d20ec6b3fb69d # v3.8.1
- uses: actions/setup-node@60edb5dd545a775178f52524783378180af0d1f8 # v4.0.2
with:
node-version: 16
- run: yarn install
@@ -24,15 +24,15 @@ jobs:
needs: [dependencies]
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@8ade135a41bc03ea155e62e844d188df1ea18608 # v4.1.0
- uses: actions/cache@704facf57e6136b1bc63b828d79edcd491f0ee84 # v3.3.2
- uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
- uses: actions/cache@0c45773b623bea8c8e75f6c82b208c3cf94ea4f9 # v4.0.2
id: node-modules-cache
with:
path: '**/node_modules'
key: node-modules-${{ hashFiles('**/yarn.lock') }}
restore-keys: |
node-modules-
- uses: actions/setup-node@5e21ff4d9bc1a8cf6de233a3057d20ec6b3fb69d # v3.8.1
- uses: actions/setup-node@60edb5dd545a775178f52524783378180af0d1f8 # v4.0.2
with:
node-version: 16
- run: yarn run compliance:licenses
@@ -43,15 +43,15 @@ jobs:
runs-on: ubuntu-latest
timeout-minutes: 5
steps:
- uses: actions/checkout@8ade135a41bc03ea155e62e844d188df1ea18608 # v4.1.0
- uses: actions/cache@704facf57e6136b1bc63b828d79edcd491f0ee84 # v3.3.2
- uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
- uses: actions/cache@0c45773b623bea8c8e75f6c82b208c3cf94ea4f9 # v4.0.2
id: node-modules-cache
with:
path: '**/node_modules'
key: node-modules-${{ hashFiles('**/yarn.lock') }}
restore-keys: |
node-modules-
- uses: actions/setup-node@5e21ff4d9bc1a8cf6de233a3057d20ec6b3fb69d # v3.8.1
- uses: actions/setup-node@60edb5dd545a775178f52524783378180af0d1f8 # v4.0.2
with:
node-version: 16
- run: yarn lint
@@ -62,13 +62,13 @@ jobs:
runs-on: ubuntu-latest
timeout-minutes: 15
steps:
- uses: actions/checkout@8ade135a41bc03ea155e62e844d188df1ea18608 # v4.1.0
- uses: actions/cache@704facf57e6136b1bc63b828d79edcd491f0ee84 # v3.3.2
- uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
- uses: actions/cache@0c45773b623bea8c8e75f6c82b208c3cf94ea4f9 # v4.0.2
id: node-modules-cache
with:
path: '**/node_modules'
key: node-modules-${{ hashFiles('**/yarn.lock') }}
- uses: actions/setup-node@5e21ff4d9bc1a8cf6de233a3057d20ec6b3fb69d # v3.8.1
- uses: actions/setup-node@60edb5dd545a775178f52524783378180af0d1f8 # v4.0.2
with:
node-version: 16
- run: yarn test
+1 -1
View File
@@ -7,7 +7,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@8ade135a41bc03ea155e62e844d188df1ea18608 # v4.1.0
uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
with:
token: ${{ secrets.ELEVATED_GITHUB_TOKEN }}
- run: |
+1 -1
View File
@@ -9,7 +9,7 @@ jobs:
trigger-gha-release:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@8ade135a41bc03ea155e62e844d188df1ea18608 # v4.1.0
- uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
- name: Release description
run: |
echo "Triggering release with a TAG ${GITHUB_REF#refs/tags/}"
+13 -2
View File
@@ -6,11 +6,22 @@ COMMIT_SOURCE=$2
SHA1=$3
# Gets the current branch name but if we're in a detached head state, return "HEAD"
BRANCH_NAME=$(git rev-parse --abbrev-ref HEAD)
# Regex to match the ICU-#### branch name pattern we use
ISSUE_REGEX="^(ICU-[0-9]+)"
# Don't run commitizen for merge or squash commits, as well as when rebasing
if [ "${COMMIT_SOURCE}" = merge ] || [ "${COMMIT_SOURCE}" = squash ] || [ "${COMMIT_SOURCE}" = "message" -a "${BRANCH_NAME}" = "HEAD" ];then
exit 0
fi
# This is to allow interaction with the terminal for commitizen
exec < /dev/tty && npx git-cz --hook || true
# If the branch name matches, set the JIRA link automatically
if [[ $BRANCH_NAME =~ $ISSUE_REGEX ]]
then
issue="${BASH_REMATCH[1]}"
url="https://hashicorp.atlassian.net/browse/${issue}"
exec < /dev/tty && npx git-cz --issues="$url" --hook || true
else
# This is to allow interaction with the terminal for commitizen
exec < /dev/tty && npx git-cz --hook || true
fi
+3 -1
View File
@@ -38,7 +38,6 @@ module.exports = {
files: [
'./.eslintrc.js',
'./.prettierrc.js',
'./.stylelintrc.js',
'./.template-lintrc.js',
'./ember-cli-build.js',
'./index.js',
@@ -60,6 +59,9 @@ module.exports = {
// Test files:
files: ['tests/**/*-test.{js,ts}'],
extends: ['plugin:qunit/recommended'],
rules: {
'qunit/require-expect': [2, 'except-simple'],
},
},
],
};
@@ -0,0 +1,110 @@
/**
* Copyright (c) HashiCorp, Inc.
* SPDX-License-Identifier: MPL-2.0
*/
import sinon from 'sinon';
import { typeOf } from '@ember/utils';
import { resourceNames } from 'api/handlers/client-daemon-handler';
import { singularize } from 'ember-inflector';
/**
* This test helper can be used to help setup your sinon stubs in your tests.
* Must be called after setupMirage.
*
* ```js
* import setupStubs from 'api/test-support/handlers/client-daemon-search';
*
* module('Acceptance | my test', function(hooks) {
* setupApplicationTest(hooks);
* setupMirage(hooks);
* setupStubs(hooks);
*
* // add your actual tests here
* });
* ```
*
* This will setup a stub for the IPC service and include helper methods to
* help setup what the client daemon search command returns.
*
* @module Test Helpers
* @public
*/
export default function setupStubs(hooks) {
let stubTypes = [];
hooks.beforeEach(function () {
const ipcService = this.owner.lookup('service:ipc');
this.ipcStub = sinon.stub(ipcService, 'invoke');
/**
* We aim to still use mirage data when stubbing out the client daemon
* search. However, the handler expects the search data to be raw JSON from
* the API which will get serialized. We add back the scope object for it to
* get correctly normalized and other fields such as "attributes" from the
* API will already be hoisted and will not be re-normalized from mirage data.
*
* This convenience method can take in multiple types,
* e.g. this.stubClientDaemonSearch('targets', 'sessions').
* This will have sinon stub out each call so the first call to search will
* provide all the models from the first parameter you specify,
* the second call will provide all the models from the second argument, etc.
* @param types
*/
this.stubClientDaemonSearch = (...types) => {
stubTypes = types;
types.forEach((type, i) => {
let models;
let resourceName;
if (typeOf(type) === 'object') {
models = type.func();
resourceName = type.resource;
} else {
models = this.server.schema[type].all().models;
resourceName = type;
}
this.ipcStub
.withArgs('searchClientDaemon')
.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);
// Serialize the data properly to standard JSON as that is what
// we're expecting from the client daemon response
return JSON.parse(JSON.stringify(modelData));
}),
});
});
};
});
hooks.afterEach(function () {
// Verify the number of mocks we set up match with how
// many times the client daemon was called with
sinon.assert.callCount(
this.ipcStub.withArgs('searchClientDaemon'),
stubTypes.length,
);
stubTypes.forEach((type, i) => {
// Assert that the stub was called with the resource we're trying to mock
// so we don't mistakenly mock the wrong resource
const ipcCall = this.ipcStub.withArgs('searchClientDaemon').getCall(i);
let resource = type;
if (typeOf(type) === 'object') {
resource = type.resource;
}
const mappedResourceName = resourceNames[singularize(resource)];
sinon.assert.match(ipcCall.args[1], { resource: mappedResourceName });
});
sinon.restore();
});
}
@@ -0,0 +1,35 @@
/**
* Copyright (c) HashiCorp, Inc.
* SPDX-License-Identifier: MPL-2.0
*/
/**
* This test helper can help set up and cleanup the database in your tests.
*
* ```js
* import { setupIndexedDb } from 'api/test-support/helpers/indexed-db';
*
* module('Acceptance | my test', function(hooks) {
* setupApplicationTest(hooks);
* setupIndexedDb(hooks);
*
* // add your actual tests here
* });
* ```
*
* @param hooks
*/
export function setupIndexedDb(hooks) {
hooks.beforeEach(function () {
const indexedDb = this.owner.lookup('service:indexed-db');
indexedDb.setup(`test-indexed-db-${Date.now()}`);
});
hooks.afterEach(async function () {
const indexedDb = this.owner.lookup('service:indexed-db');
await indexedDb.db.delete();
});
}
export default setupIndexedDb;
@@ -18,7 +18,7 @@ export default class ChannelRecordingAbility extends ModelAbility {
const sessionRecording = this.model.connection_recording.session_recording;
const sessionRecordingAbility = this.abilities.abilityFor(
'session-recording',
sessionRecording
sessionRecording,
);
return this.model.isAsciicast && sessionRecordingAbility.canDownload;
+46
View File
@@ -0,0 +1,46 @@
/**
* Copyright (c) HashiCorp, Inc.
* SPDX-License-Identifier: MPL-2.0
*/
import ModelAbility from './model';
import { service } from '@ember/service';
/**
* Provides abilities for storage policies.
*/
export default class PolicyAbility extends ModelAbility {
// =services
@service features;
// =permissions
/**
* This ensures that storage policies may be read only if the
* session-recording feature flag is enabled.
*/
get canRead() {
return this.features.isEnabled('ssh-session-recording')
? super.canRead
: false;
}
/**
* This ensures that storage policies may be updated only if the
* session-recording feature flag is enabled.
*/
get canUpdate() {
return this.features.isEnabled('ssh-session-recording')
? super.canUpdate
: false;
}
/**
* This ensures that storage policies may be deleted only if the
* session-recording feature flag is enabled.
*/
get canDelete() {
return this.features.isEnabled('ssh-session-recording')
? super.canDelete
: false;
}
}
+1 -1
View File
@@ -54,7 +54,7 @@ export default class RoleAbility extends ModelAbility {
type === 'user' || type === 'group' || type === 'managed-group';
if (!typeIsValid)
throw new InvalidRolePrincipalTypeError(
`Expected a role principal of type 'user', 'group', or 'managed-group'. Got '${type}'.`
`Expected a role principal of type 'user', 'group', or 'managed-group'. Got '${type}'.`,
);
return this.can.can(`read ${type}`, this.model);
}
+28
View File
@@ -0,0 +1,28 @@
/**
* Copyright (c) HashiCorp, Inc.
* SPDX-License-Identifier: MPL-2.0
*/
import ModelAbility from './model';
/**
* Provides abilities for scopes.
*/
export default class ScopeAbility extends ModelAbility {
// =permissions
/**
* Permission that checks whether a policy can be attached to a scope
* @type {boolean}
*/
get canAttachStoragePolicy() {
return this.hasAuthorizedAction('attach-storage-policy');
}
/**
* Permission that checks whether a policy can be detached to a scope
* @type {boolean}
*/
get canDetachStoragePolicy() {
return this.hasAuthorizedAction('detach-storage-policy');
}
}
@@ -21,7 +21,22 @@ export default class SessionRecordingAbility extends ModelAbility {
return !this.model.isUnknown && super.canRead;
}
/**
* Only "known" session recording types may be deleted.
* @type {boolean}
*/
get canDelete() {
return !this.model.isUnknown && super.canDelete && this.model.isAvailable;
}
get canDownload() {
return this.hasAuthorizedAction('download');
}
/* Permission that checks whether a policy can be reapplied to a session recording
* @type {boolean}
*/
get canReapplyStoragePolicy() {
return this.hasAuthorizedAction('reapply-storage-policy');
}
}
+17 -2
View File
@@ -14,10 +14,25 @@ export default class SessionAbility extends ModelAbility {
// =permissions
/**
* Only "active" or "pending" sessions may be read.
* Only available sessions may be read.
* @type {boolean}
*/
get canRead() {
return (this.model.isActive || this.model.isPending) && super.canRead;
return (
this.model.isAvailable &&
(this.hasAuthorizedAction('read:self') || super.canRead)
);
}
/**
* Only available sessions may be canceled.
* @type {boolean}
*/
get canCancel() {
return (
this.model.isAvailable &&
(this.hasAuthorizedAction('cancel:self') ||
this.hasAuthorizedAction('cancel'))
);
}
}
+39 -19
View File
@@ -45,7 +45,7 @@ function prenormalizeArrayResponse(response) {
}
export default class ApplicationAdapter extends RESTAdapter.extend(
AdapterBuildURLMixin
AdapterBuildURLMixin,
) {
// =attributes
@@ -108,22 +108,38 @@ export default class ApplicationAdapter extends RESTAdapter.extend(
/**
* Intercepts "empty" responses and adds an empty `items` array.
* @override
* @method findAll
* @return {Promise} promise
*/
findAll() {
return super.findAll(...arguments).then(prenormalizeArrayResponse);
}
/**
* Intercepts "empty" responses and adds an empty `items` array.
* This query method now supports pagination by checking the responseType and
* passing in the list token if the responseType indicates more data
* @override
* @method query
* @return {Promise} promise
*/
query() {
return super.query(...arguments).then(prenormalizeArrayResponse);
async query(store, schema, query) {
const queryObject = structuredClone(query);
let result;
let data = [];
// If the query has a page_size, we skip the pagination logic
// and return the initial result. This is being used to determine
// if the controller supports pagination
if (query.page_size) {
result = await super.query(store, schema, query);
return prenormalizeArrayResponse(result);
}
// Run this loop as long as the response_type is delta,
// which indicates that there are more items in the list
do {
result = await super.query(store, schema, queryObject);
//add the result items to a data array
if (result && result.items) {
data.push(...result.items);
//pass in the list token for subsequent calls to fetch the remaining list items
queryObject.list_token = result.list_token;
}
} while (result && result.response_type === 'delta');
result.items = data;
return prenormalizeArrayResponse(result);
}
/**
@@ -196,7 +212,10 @@ export default class ApplicationAdapter extends RESTAdapter.extend(
handleResponse(status, headers, payload, requestData) {
if (this.isInvalid(status, headers, payload)) {
const detailedMessage = this.generatedDetailedMessage(...arguments);
const transformedPayload = this.transformValidationErrors(payload);
const transformedPayload = this.transformValidationErrors(
payload,
status,
);
return new InvalidError(transformedPayload.errors, detailedMessage);
}
return super.handleResponse(status, headers, payload, requestData);
@@ -254,17 +273,18 @@ export default class ApplicationAdapter extends RESTAdapter.extend(
* error format.
*
* @param {object} payload
* @param status
* @return {object}
*/
transformValidationErrors(payload) {
transformValidationErrors(payload, status) {
const fieldErrors = get(payload, 'details.request_fields') || [];
// Normalize the primary error message into "base", which is an error
// that applies to the whole model instance
const baseError = {
isInvalid: true,
status: payload.source,
code: payload.code,
detail: payload.message,
status,
code: payload?.kind,
detail: payload?.message,
source: { pointer: '/data' },
};
// Normalize field-specific errors, if any.
@@ -299,6 +319,6 @@ export default class ApplicationAdapter extends RESTAdapter.extend(
* @return {String} detailed error message
*/
generatedDetailedMessage(status, headers, payload /*, requestData*/) {
return payload.message;
return payload?.message;
}
}
@@ -55,7 +55,7 @@ export default class SessionRecordingAdapter extends ApplicationAdapter {
throw this.handleResponse(
response.status,
response.headers,
await response.text()
await response.text(),
);
}
}
@@ -0,0 +1,64 @@
/**
* Copyright (c) HashiCorp, Inc.
* SPDX-License-Identifier: MPL-2.0
*/
import BaseModel from '../../models/base';
import { attr } from '@ember-data/model';
/**
* Alias contains all fields related to an Alias resource
*/
export default class GeneratedAliasModel extends BaseModel {
// =attributes
@attr('string', {
description: 'The type of the resource, to help differentiate schemas',
})
type;
@attr('string', {
description: 'Optional name for identification purposes.',
})
name;
@attr('string', {
description: 'Optional user-set description for identification purposes.',
})
description;
@attr('date', {
description: 'The time this resource was created\nOutput only.',
readOnly: true,
})
created_time;
@attr('date', {
description: 'The time this resource was last updated\nOutput only.',
readOnly: true,
})
updated_time;
@attr('number', {
description: 'Current version number of this resource.',
})
version;
@attr('string', {
description:
'This is the value referenced by the user that is resolved to the destination id.',
})
value;
@attr('string', {
description: 'This is the id of the resource that this Alias points to.',
})
destination_id;
@attr('object', {
isNestedAttribute: true,
description:
'This contains a host_id which is the id of the host that the session will be authorized for.',
})
authorize_session_arguments;
}
@@ -158,6 +158,13 @@ export default class GeneratedAuthMethodModel extends BaseModel {
})
account_claim_maps;
@attr('string-array', {
for: 'oidc',
emptyArrayIfMissing: true,
isNestedAttribute: true,
})
prompts;
// =attributes(ldap)
@attr('boolean', {
@@ -31,7 +31,7 @@ export default class GeneratedChannelRecordingModel extends BaseModel {
'The total number of errors that occurred during the use of this Channel.',
readOnly: true,
})
errors;
errors_number;
@attr('date', {
description: 'The time the Channel started.',
@@ -38,7 +38,7 @@ export default class GeneratedConnectionRecordingModel extends BaseModel {
'The total number of errors that occurred during the use of this Connection.',
readOnly: true,
})
errors;
errors_number;
@attr('date', {
description: 'The time the Connection started.',
@@ -75,6 +75,18 @@ export default class GeneratedCredentialLibraryModel extends BaseModel {
})
path;
@attr('string', {
for: 'vault-generic',
description: 'It indicates the type of credential the library returns.',
})
credential_type;
@attr('object', {
for: 'vault-generic',
description: 'It indicates the credential mapping overrides.',
})
credential_mapping_overrides;
@attr('string', {
for: 'vault-ssh-certificate',
isNestedAttribute: true,
@@ -54,4 +54,10 @@ export default class GeneratedHostModel extends BaseModel {
readOnly: true,
})
plugin;
@attr({
emptyArrayIfMissing: true,
readOnly: true,
})
host_set_ids;
}
@@ -0,0 +1,61 @@
/**
* Copyright (c) HashiCorp, Inc.
* SPDX-License-Identifier: MPL-2.0
*/
import BaseModel from '../../models/base';
import { attr } from '@ember-data/model';
/**
* Storage Policy is a resource that manages the lifecycle of Session Recordings,
* particularly to meet compliance frameworks.
*/
export default class GeneratedPolicyModel extends BaseModel {
// =attributes
@attr('string', {
description: 'The type of the resource, to help differentiate schemas',
})
type;
@attr('string', {
description: 'Optional name for identification purposes.',
})
name;
@attr('string', {
description: 'Optional user-set description for identification purposes.',
})
description;
@attr('date', {
description: 'The time this resource was created\nOutput only.',
readOnly: true,
})
created_time;
@attr('date', {
description: 'The time this resource was last updated\nOutput only.',
readOnly: true,
})
updated_time;
@attr('number', {
description: 'Current version number of this resource.',
})
version;
@attr('object', {
isNestedAttribute: true,
description:
'Days is the number of days for which a session recording will be retained.',
})
retain_for;
@attr('object', {
isNestedAttribute: true,
description:
'Days is the number of days for which a session recording will be automatically deleted.',
})
delete_after;
}
@@ -49,4 +49,9 @@ export default class GeneratedScopeModel extends BaseModel {
description: 'Current version number of this resource.',
})
version;
@attr('string', {
description: 'The ID of the associated storage policy',
})
storage_policy_id;
}
@@ -70,7 +70,7 @@ export default class GeneratedSessionRecordingModel extends BaseModel {
'The total number of errors that occurred during the use of the Session.',
readOnly: true,
})
errors;
errors_number;
@attr('date', {
description: 'The time the Session started.',
@@ -109,4 +109,17 @@ export default class GeneratedSessionRecordingModel extends BaseModel {
readOnly: true,
})
error_details;
@attr('date', {
description: 'The time until a session recording is required to be stored.',
readOnly: true,
})
retain_until;
@attr('date', {
description:
'The time a session recording is scheduled to be automatically deleted.',
readOnly: true,
})
delete_after;
}
@@ -32,6 +32,13 @@ export default class GeneratedSessionModel extends BaseModel {
})
updated_time;
@attr('date', {
description:
'After this time the connection will be expired, e.g. forcefully terminated.\nOutput only.',
readOnly: true,
})
expiration_time;
@attr('number', {
description: 'Current version number of this resource.',
})
@@ -73,6 +73,12 @@ export default class GeneratedStorageBucketModel extends BaseModel {
})
region;
@attr('string', {
isNestedAttribute: true,
description: 'The MinIO location server.',
})
endpoint_url;
//this field is not used in the UI, but this is kept here to replicate the API
@attr('string', {
readOnly: true,
@@ -108,4 +108,17 @@ export default class GeneratedTargetModel extends BaseModel {
isNestedAttribute: true,
})
enable_session_recording;
@attr('array', {
description:
'with_aliases specify the aliases that should be created when the target is created. ',
})
with_aliases;
@attr('array', {
readOnly: true,
description:
'with_aliases specify the aliases that should be created when the target is created. ',
})
aliases;
}
@@ -0,0 +1,167 @@
/**
* Copyright (c) HashiCorp, Inc.
* SPDX-License-Identifier: MPL-2.0
*/
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';
/**
* Not all types are yet supported by the client daemon so we'll
* just whitelist the ones we need to start with. Keys are the resource
* types and the values are the fields that are searchable by the client.
* @type {{session: string[], alias: string[], target: string[]}}
*/
const supportedTypes = {
target: ['id', 'name', 'description', 'address', 'scope_id'],
session: ['id', 'type', 'status', 'endpoint', 'scope_id', 'target_id'],
alias: ['id', 'type', 'value', 'destination_id'],
};
/**
* Map the model resource name to the client daemon resource name
* @type {{session: string, alias: string, target: string}}
*/
export const resourceNames = {
target: 'targets',
session: 'sessions',
alias: 'resolvable-aliases',
};
const fetchControllerData = async (context, next) => {
const { data } = context.request;
const { query: originalQuery } = data;
// remove client daemon specific query params
// eslint-disable-next-line no-unused-vars
const { query, page, pageSize, ...remainingQuery } = originalQuery;
// If we get an error or client daemon is unavailable, fall back to calling the API
context.request.data.query = remainingQuery;
const results = await next(context.request);
const models = results.content.toArray();
const paginatedResult = paginateResults(models, page, pageSize);
paginatedResult.meta = { totalItems: models.length };
return paginatedResult;
};
/**
* Handler to sit in front of the API request layer
* so we can request from the daemon first
*/
export default class ClientDaemonHandler {
@service session;
@service ipc;
constructor(context) {
setOwner(this, getOwner(context));
}
async request(context, next) {
switch (context.request.op) {
case 'query': {
const { store, data } = context.request;
const { type, query, options: { pushToStore = true } = {} } = data;
const isClientDaemonRunning = await this.ipc.invoke(
'isClientDaemonRunning',
);
// eslint-disable-next-line no-unused-vars
let { recursive, scope_id, page, pageSize, ...remainingQuery } = query;
let searchQuery = '';
if (
!Object.keys(supportedTypes).includes(type) ||
!isClientDaemonRunning
) {
return fetchControllerData(context, next);
}
if (remainingQuery.query) {
const { search, filters } = remainingQuery.query;
searchQuery = generateMQLExpression({
search: {
text: search,
fields: supportedTypes[type],
},
filters,
});
}
const sessionData = this.session.data?.authenticated;
const auth_token_id = sessionData?.id;
const token = sessionData?.token;
remainingQuery = {
...remainingQuery,
query: searchQuery,
auth_token_id,
token,
resource: resourceNames[type],
};
let clientDaemonResults = {};
try {
clientDaemonResults = await this.ipc.invoke(
'searchClientDaemon',
remainingQuery,
);
} catch (e) {
// If we got a 403, most likely the client daemon was restarted and our token is no longer valid
// I'm not sure if we can get a 401 since we always send a token but we'll handle it in the same way
if (e.statusCode === 403 || e.statusCode === 401) {
try {
await this.ipc.invoke('addTokenToClientDaemon', {
tokenId: auth_token_id,
token,
});
clientDaemonResults = await this.ipc.invoke(
'searchClientDaemon',
remainingQuery,
);
} catch {
// If it fails again just fall back to fetching controller data
}
}
return fetchControllerData(context, next);
}
// 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(clientDaemonResults);
const payload = { items: paginateResults(results, page, pageSize) };
const schema = store.modelFor(type);
const serializer = store.serializerFor(type);
const normalizedPayload = serializer.normalizeResponse(
store,
schema,
payload,
null,
'query',
);
// Return the raw data if we don't push to the store.
let records = normalizedPayload.data.map((record) => ({
...record.attributes,
id: record.id,
}));
if (pushToStore) {
records = store.push(normalizedPayload);
}
// Set a meta property on the array to store the total items of the results.
// 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 };
return records;
}
default:
return next(context.request);
}
}
}
@@ -0,0 +1,172 @@
/**
* Copyright (c) HashiCorp, Inc.
* SPDX-License-Identifier: MPL-2.0
*/
import { modelIndexes } from 'api/services/indexed-db';
import { inject as service } from '@ember/service';
import { getOwner, setOwner } from '@ember/application';
import { queryIndexedDb } from '../utils/indexed-db-query';
import { paginateResults } from '../utils/paginate-results';
import { hashCode } from '../utils/hash-code';
/**
* Handler to sit in front of the API request layer
* so we can handle any caching with indexedDb first
*/
export default class IndexedDbHandler {
@service indexedDb;
constructor(context) {
setOwner(this, getOwner(context));
}
async request(context, next) {
switch (context.request.op) {
case 'query': {
const { store, data } = context.request;
// TODO: Remove storeToken option as this is a temporary fix for auth-methods.
const {
type,
query,
options: {
pushToStore = true,
peekIndexedDB = false,
storeToken = true,
} = {},
} = data;
const supportedModels = Object.keys(modelIndexes);
const { db: indexedDb } = this.indexedDb ?? {};
// Go through normal flow if we don't yet support the model
// or if we don't have an indexedDb instance
if (!supportedModels.includes(type) || !indexedDb) {
return next(context.request);
}
let { page, pageSize, query: queryObj, ...remainingQuery } = query;
const adapter = store.adapterFor(type);
const schema = store.modelFor(type);
const serializer = store.serializerFor(type);
if (!peekIndexedDB) {
const tokenKey = `${type}-${hashCode(remainingQuery)}`;
let listToken;
if (storeToken) {
listToken = await indexedDb.token.get(tokenKey);
}
let payload;
try {
payload = await adapter.query(store, schema, {
...remainingQuery,
list_token: listToken?.token,
});
} catch (e) {
// If we get an invalid list token, we'll delete the token and
// clear the DB and try again without a token.
if (
e?.errors[0].status === 400 &&
e?.errors[0].code === 'invalid list token'
) {
await indexedDb[type].clear();
// Delete all tokens of the same resource type so we don't keep clearing the DB.
// Even if other tokens may still be valid, we might have cleared data that they
// depended on so we should clear all tokens of the same type when clearing the DB.
const tokenKeys = await indexedDb.token
.where(':id')
.startsWith(type)
.primaryKeys();
await indexedDb.token.bulkDelete(tokenKeys);
payload = await adapter.query(store, schema, {
...remainingQuery,
});
} else {
throw e;
}
}
// Store the token we just got back from the payload if it exists
if (payload.list_token && storeToken) {
await indexedDb.token.put({
id: tokenKey,
token: payload.list_token,
});
}
// Remove any records from the DB if the API indicates they've been deleted
if (payload.removed_ids?.length > 0) {
await indexedDb[type].bulkDelete(payload.removed_ids);
}
// This is a temporary fix of clearing the DB (specifically for auth-methods)
// since we are not storing the token we do not get back a list of removed_ids
// from the API call and we do not want deleted items from showing in list view.
if (!storeToken) {
await indexedDb[type].clear();
}
const normalizedPayload = serializer.normalizeResponse(
store,
schema,
payload,
null,
'query',
);
const { data: payloadData } = normalizedPayload;
// Store the new data we just got back from the API refresh
const items = payloadData.map((datum) =>
this.indexedDb.normalizeData({
data: datum,
cleanData: true,
schema,
serializer,
}),
);
await indexedDb[type].bulkPut(items);
}
const indexedDbResults = await queryIndexedDb(
indexedDb,
type,
queryObj,
);
const dbRecords = paginateResults(indexedDbResults, page, pageSize).map(
(item) =>
this.indexedDb.normalizeData({
data: item,
cleanData: false,
schema,
serializer,
}),
);
// Return the raw data if we don't push to the store.
let records = dbRecords.map((record) => ({
...record.attributes,
id: record.id,
}));
if (pushToStore) {
records = store.push({ data: dbRecords });
}
// Set a meta property on the array to store the total items of the results.
// 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: indexedDbResults.length };
return records;
}
default:
return next(context.request);
}
}
}
@@ -0,0 +1,27 @@
/**
* Copyright (c) HashiCorp, Inc.
* SPDX-License-Identifier: MPL-2.0
*/
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,
};
+1 -1
View File
@@ -87,7 +87,7 @@ export default class AccountModel extends GeneratedAccountModel {
changePassword(
currentPassword,
newPassword,
options = { adapterOptions: {} }
options = { adapterOptions: {} },
) {
const defaultAdapterOptions = {
method: 'change-password',
+10
View File
@@ -0,0 +1,10 @@
/**
* Copyright (c) HashiCorp, Inc.
* SPDX-License-Identifier: MPL-2.0
*/
import GeneratedAliasModel from '../generated/models/alias';
export const TYPE_ALIAS_TARGET = 'target';
export const TYPES_ALIAS = Object.freeze([TYPE_ALIAS_TARGET]);
export default class AliasModel extends GeneratedAliasModel {}
+1
View File
@@ -37,6 +37,7 @@ export const options = {
account_claim_maps: {
to: ['sub', 'name', 'email'],
},
prompts: ['consent', 'select_account', 'login'],
},
ldap: {
account_attribute_maps: {
@@ -11,6 +11,18 @@ import GeneratedCredentialLibraryModel from '../generated/models/credential-libr
export const options = {
http_method: ['GET', 'POST'],
key_type: ['ed25519', 'ecdsa', 'rsa'],
credential_types: ['ssh_private_key', 'username_password'],
mapping_overrides: {
username_password: {
username_attribute: 'Username',
password_attribute: 'Password',
},
ssh_private_key: {
private_key_attribute: 'Private Key',
private_key_passphrase_attribute: 'Private Key Passphrase',
username_attribute: 'Username',
},
},
};
export const TYPE_CREDENTIAL_LIBRARY_VAULT_GENERIC = 'vault-generic';
+7 -1
View File
@@ -6,7 +6,13 @@
import GeneratedCredentialStoreModel from '../generated/models/credential-store';
import { equal } from '@ember/object/computed';
export const types = ['static', 'vault'];
export const TYPE_CREDENTIAL_STORE_STATIC = 'static';
export const TYPE_CREDENTIAL_STORE_VAULT = 'vault';
export const TYPES_CREDENTIAL_STORE = Object.freeze([
TYPE_CREDENTIAL_STORE_STATIC,
TYPE_CREDENTIAL_STORE_VAULT,
]);
export default class CredentialStoreModel extends GeneratedCredentialStoreModel {
// =attributes
+16 -3
View File
@@ -5,8 +5,19 @@
import GeneratedHostCatalogModel from '../generated/models/host-catalog';
export const types = ['static', 'plugin'];
export const pluginTypes = ['aws', 'azure'];
export const TYPE_HOST_CATALOG_STATIC = 'static';
export const TYPE_HOST_CATALOG_DYNAMIC = 'plugin';
export const TYPES_HOST_CATALOG = Object.freeze([
TYPE_HOST_CATALOG_STATIC,
TYPE_HOST_CATALOG_DYNAMIC,
]);
export const TYPE_HOST_CATALOG_PLUGIN_AWS = 'aws';
export const TYPE_HOST_CATALOG_PLUGIN_AZURE = 'azure';
export const TYPES_HOST_CATALOG_PLUGIN = [
TYPE_HOST_CATALOG_PLUGIN_AWS,
TYPE_HOST_CATALOG_PLUGIN_AZURE,
];
export default class HostCatalogModel extends GeneratedHostCatalogModel {
// =attributes
@@ -32,7 +43,9 @@ export default class HostCatalogModel extends GeneratedHostCatalogModel {
* @type {boolean}
*/
get isUnknown() {
return this.isPlugin && !pluginTypes.includes(this.plugin?.name);
return (
this.isPlugin && !TYPES_HOST_CATALOG_PLUGIN.includes(this.plugin?.name)
);
}
/**
+4 -2
View File
@@ -4,7 +4,7 @@
*/
import GeneratedHostSetModel from '../generated/models/host-set';
import { pluginTypes } from './host-catalog';
import { TYPES_HOST_CATALOG_PLUGIN } from './host-catalog';
export default class HostSetModel extends GeneratedHostSetModel {
// =attributes
@@ -30,7 +30,9 @@ export default class HostSetModel extends GeneratedHostSetModel {
* @type {boolean}
*/
get isUnknown() {
return this.isPlugin && !pluginTypes.includes(this.plugin?.name);
return (
this.isPlugin && !TYPES_HOST_CATALOG_PLUGIN.includes(this.plugin?.name)
);
}
/**
+4 -2
View File
@@ -5,7 +5,7 @@
import GeneratedHostModel from '../generated/models/host';
import { attr } from '@ember-data/model';
import { pluginTypes } from './host-catalog';
import { TYPES_HOST_CATALOG_PLUGIN } from './host-catalog';
export default class HostModel extends GeneratedHostModel {
// =attributes
@@ -64,7 +64,9 @@ export default class HostModel extends GeneratedHostModel {
* @type {boolean}
*/
get isUnknown() {
return this.isPlugin && !pluginTypes.includes(this.plugin?.name);
return (
this.isPlugin && !TYPES_HOST_CATALOG_PLUGIN.includes(this.plugin?.name)
);
}
/**
+9
View File
@@ -0,0 +1,9 @@
/**
* Copyright (c) HashiCorp, Inc.
* SPDX-License-Identifier: MPL-2.0
*/
import GeneratedPolicyModel from '../generated/models/policy';
export const TYPE_POLICY = 'storage';
export default class PolicyModel extends GeneratedPolicyModel {}
+4 -95
View File
@@ -6,17 +6,11 @@
import GeneratedRoleModel from '../generated/models/role';
import { attr } from '@ember-data/model';
import { inject as service } from '@ember/service';
import { all, resolve } from 'rsvp';
import {
TYPE_AUTH_METHOD_OIDC,
TYPE_AUTH_METHOD_LDAP,
} from 'api/models/auth-method';
export default class RoleModel extends GeneratedRoleModel {
// =services
@service store;
@service resourceFilterStore;
// =attributes
@@ -27,7 +21,7 @@ export default class RoleModel extends GeneratedRoleModel {
* see obvious. Instead, the application layer is expected to load referenced
* users and groups as needed.
*/
@attr('principal-array', {
@attr('array', {
readOnly: true,
emptyArrayIfMissing: true,
})
@@ -55,7 +49,7 @@ export default class RoleModel extends GeneratedRoleModel {
get userIDs() {
return this.principals
.filter(({ type }) => type === 'user')
.map(({ principal_id }) => principal_id);
.map(({ id }) => id);
}
/**
@@ -65,7 +59,7 @@ export default class RoleModel extends GeneratedRoleModel {
get groupIDs() {
return this.principals
.filter(({ type }) => type === 'group')
.map(({ principal_id }) => principal_id);
.map(({ id }) => id);
}
/**
@@ -75,94 +69,9 @@ export default class RoleModel extends GeneratedRoleModel {
get managedGroupIDs() {
return this.principals
.filter(({ type }) => type === 'managed group')
.map(({ principal_id }) => principal_id);
.map(({ id }) => id);
}
/**
* A promise that resolves to an array of User instances.
* When calling this getter, be sure to await resolution
* before interacting with the results.
* @type {Promise[UserModel]}
*/
get users() {
const ids = this.userIDs;
// Role has prinicipal IDs,
// return a promise which resolves model instances for those IDs
if (ids?.length) {
return this.resourceFilterStore
.queryBy('user', { id: ids }, { scope_id: 'global', recursive: true })
.then((models) => models.map((model) => model));
}
// No principal IDs,
// return a promise resolving to an empty array
return resolve([]);
}
/**
* A promise that resolves to an array of Group instances.
* When calling this getter, be sure to await resolution
* before interacting with the results.
* @type {Promise[GroupModel]}
*/
get groups() {
const ids = this.groupIDs;
// Role has prinicipal IDs,
// return a promise which resolves model instances for those IDs
if (ids?.length) {
return this.resourceFilterStore
.queryBy('group', { id: ids }, { scope_id: 'global', recursive: true })
.then((models) => models.map((model) => model));
}
// No principal IDs,
// return a promise resolving to an empty array
return resolve([]);
}
/**
* A promise that resolves to an array of ManagedGroup instances.
* When calling this getter, be sure to await resolution
* before interacting with the results.
* @type {Promise[ManagedGroupModel]}
*/
get managedGroups() {
const ids = this.managedGroupIDs;
// Role has prinicipal IDs
// return a promise which resolves model instances for those IDs
if (ids?.length) {
// Collect all auth methods.
const authMethods = this.resourceFilterStore.queryBy(
'auth-method',
{ type: [TYPE_AUTH_METHOD_OIDC, TYPE_AUTH_METHOD_LDAP] },
{ scope_id: 'global', recursive: true }
);
// For each auth method, query all managed groups with IDs
// that match the role's manage group principal IDs.
const managedGroups = authMethods
.then((methods) =>
all(
methods.map(({ id: auth_method_id }) =>
this.resourceFilterStore
.queryBy('managed-group', { id: ids }, { auth_method_id })
.then((models) => models.map((model) => model))
)
)
)
// The result is an array of arrays of model instances (grouped by
// auth methods), so these must be flattened.
.then((grouped) => grouped.flat());
return managedGroups;
}
// No principal IDs,
// return a promise resolving to an empty array
return resolve([]);
}
// =methods
/**
+57 -14
View File
@@ -4,13 +4,15 @@
*/
import GeneratedScopeModel from '../generated/models/scope';
import { computed } from '@ember/object';
export const scopeTypes = {
global: 'global',
org: 'org',
project: 'project',
};
export const TYPE_SCOPE_GLOBAL = 'global';
export const TYPE_SCOPE_ORG = 'org';
export const TYPE_SCOPE_PROJECT = 'project';
export const TYPES_SCOPE = Object.freeze([
TYPE_SCOPE_GLOBAL,
TYPE_SCOPE_ORG,
TYPE_SCOPE_PROJECT,
]);
export default class ScopeModel extends GeneratedScopeModel {
// =attributes
@@ -18,9 +20,8 @@ export default class ScopeModel extends GeneratedScopeModel {
/**
* @type {boolean}
*/
@computed('type')
get isGlobal() {
return this.type === scopeTypes.global;
return this.type === TYPE_SCOPE_GLOBAL;
}
// There is only one global scope and it cannot be created by clients,
// thus no set.
@@ -28,22 +29,64 @@ export default class ScopeModel extends GeneratedScopeModel {
/**
* @type {boolean}
*/
@computed('type')
get isOrg() {
return this.type === scopeTypes.org;
return this.type === TYPE_SCOPE_ORG;
}
set isOrg(value) {
if (value) this.type = scopeTypes.org;
if (value) this.type = TYPE_SCOPE_ORG;
}
/**
* @type {boolean}
*/
@computed('type')
get isProject() {
return this.type === scopeTypes.project;
return this.type === TYPE_SCOPE_PROJECT;
}
set isProject(value) {
if (value) this.type = scopeTypes.project;
if (value) this.type = TYPE_SCOPE_PROJECT;
}
/**
* Attach policy via the `attach-staorage-policy` method.
* @param {[string]} policyId
* @param {object} options
* @param {object} options.adapterOptions
* @return {Promise}
*/
attachStoragePolicy(policyId, options = { adapterOptions: {} }) {
const defaultAdapterOptions = {
method: 'attach-storage-policy',
policyId,
};
// There is no "deep merge" in ES.
return this.save({
...options,
adapterOptions: {
...defaultAdapterOptions,
...options.adapterOptions,
},
});
}
/**
* Detaches policy via the `detach-storage-policy` method.
* @param {[string]} policyId
* @param {object} options
* @param {object} options.adapterOptions
* @return {Promise}
*/
detachStoragePolicy(policyId, options = { adapterOptions: {} }) {
const defaultAdapterOptions = {
method: 'detach-storage-policy',
policyId,
};
// There is no "deep merge" in ES.
return this.save({
...options,
adapterOptions: {
...defaultAdapterOptions,
...options.adapterOptions,
},
});
}
}
@@ -69,4 +69,23 @@ export default class SessionRecordingModel extends GeneratedSessionRecordingMode
this.create_time_values?.user?.name || this.create_time_values?.user?.id
);
}
/**
* Reapply policy dates via the `reapply-staorage-policy` method.
* @param {object} options
* @param {object} options.adapterOptions
* @return {Promise}
*/
reapplyStoragePolicy(options = { adapterOptions: {} }) {
const defaultAdapterOptions = {
method: 'reapply-storage-policy',
};
return this.save({
...options,
adapterOptions: {
...defaultAdapterOptions,
...options.adapterOptions,
},
});
}
}
+16 -5
View File
@@ -4,7 +4,6 @@
*/
import GeneratedSessionModel from '../generated/models/session';
import { computed } from '@ember/object';
import { equal } from '@ember/object/computed';
import { tracked } from '@glimmer/tracking';
import { A } from '@ember/array';
@@ -77,7 +76,7 @@ class SessionCredential {
if (this.#payloadSecret?.decoded) {
const secretJSON = this.#payloadSecret.decoded;
return Object.keys(secretJSON).map(
(key) => new SessionCredential.SecretItem(key, secretJSON[key])
(key) => new SessionCredential.SecretItem(key, secretJSON[key]),
);
} else {
// decode from base64
@@ -127,8 +126,7 @@ export default class SessionModel extends GeneratedSessionModel {
/**
* @type {boolean}
*/
@computed('isActive', 'isPending')
get isCancelable() {
get isAvailable() {
return this.isActive || this.isPending;
}
@@ -136,7 +134,6 @@ export default class SessionModel extends GeneratedSessionModel {
* The full proxy address and port if address exists, otherwise null.
* @type {?string}
*/
@computed('proxy_address', 'proxy_port')
get proxy() {
return this.proxy_address
? `${this.proxy_address}:${this.proxy_port}`
@@ -148,9 +145,23 @@ export default class SessionModel extends GeneratedSessionModel {
* @type {TargetModel}
*/
get target() {
if (!this.target_id) {
return null;
}
return this.store.peekRecord('target', this.target_id);
}
/**
* The user associated with this session (if loaded).
* @type {UserModel}
*/
get user() {
if (!this.user_id) {
return null;
}
return this.store.peekRecord('user', this.user_id);
}
// =methods
/**
+10
View File
@@ -9,8 +9,10 @@ export const TYPE_STORAGE_BUCKET_PLUGIN = 'plugin';
export const TYPES_STORAGE_BUCKET = Object.freeze([TYPE_STORAGE_BUCKET_PLUGIN]);
export const TYPE_STORAGE_BUCKET_PLUGIN_AWS_S3 = 'aws';
export const TYPE_STORAGE_BUCKET_PLUGIN_MINIO = 'minio';
export const TYPES_STORAGE_BUCKET_PLUGIN = Object.freeze([
TYPE_STORAGE_BUCKET_PLUGIN_AWS_S3,
TYPE_STORAGE_BUCKET_PLUGIN_MINIO,
]);
export const TYPE_CREDENTIAL_STATIC = 'static';
@@ -75,6 +77,14 @@ export default class StorageBucketModel extends GeneratedStorageBucketModel {
return this.compositeType === TYPE_STORAGE_BUCKET_PLUGIN_AWS_S3;
}
/**
* True if the storage bucket plugin type is MinIO
* @type {boolean}
*/
get isMinIO() {
return this.compositeType === TYPE_STORAGE_BUCKET_PLUGIN_MINIO;
}
/**
* If the storage bucket is a plugin return `plugin.name`,
* otherwise return the storage bucket type.
+22 -8
View File
@@ -108,6 +108,14 @@ export default class TargetModel extends GeneratedTargetModel {
.filter((s) => s && s.target_id === this.id);
}
/**
* Available sessions associated with this target (but only already loaded sessions).
* @type {SessionModel[]}
*/
get availableSessions() {
return this.sessions.filter((session) => session.isAvailable);
}
/**
* The project associated with this target (if already loaded).
* @type {ScopeModel}
@@ -122,11 +130,17 @@ export default class TargetModel extends GeneratedTargetModel {
*/
get isActive() {
const pendingOrActiveSessions = this.sessions.filter(
(s) => s.isActive || s.isPending
(s) => s.isActive || s.isPending,
);
return Boolean(pendingOrActiveSessions.length);
}
get associatedAliases() {
return this.store
.peekAll('alias')
.filter((alias) => alias?.destination_id === this.id);
}
// =methods
/**
@@ -195,7 +209,7 @@ export default class TargetModel extends GeneratedTargetModel {
*/
addBrokeredCredentialSources(
brokeredCredentialSourceIDs,
options = { adapterOptions: {} }
options = { adapterOptions: {} },
) {
const defaultAdapterOptions = {
method: 'add-credential-sources',
@@ -221,7 +235,7 @@ export default class TargetModel extends GeneratedTargetModel {
*/
addInjectedApplicationCredentialSources(
injectedApplicationCredentialSourceIDs,
options = { adapterOptions: {} }
options = { adapterOptions: {} },
) {
const defaultAdapterOptions = {
method: 'add-credential-sources',
@@ -247,7 +261,7 @@ export default class TargetModel extends GeneratedTargetModel {
*/
removeBrokeredCredentialSources(
brokeredCredentialSourceIDs,
options = { adapterOptions: {} }
options = { adapterOptions: {} },
) {
const defaultAdapterOptions = {
method: 'remove-credential-sources',
@@ -272,7 +286,7 @@ export default class TargetModel extends GeneratedTargetModel {
removeBrokeredCredentialSource(brokeredCredentialSourceID, options) {
return this.removeBrokeredCredentialSources(
[brokeredCredentialSourceID],
options
options,
);
}
@@ -286,7 +300,7 @@ export default class TargetModel extends GeneratedTargetModel {
*/
removeInjectedApplicationCredentialSources(
injectedApplicationCredentialSourceIDs,
options = { adapterOptions: {} }
options = { adapterOptions: {} },
) {
const defaultAdapterOptions = {
method: 'remove-credential-sources',
@@ -310,11 +324,11 @@ export default class TargetModel extends GeneratedTargetModel {
*/
removeInjectedApplicationCredentialSource(
injectedApplicationCredentialSourceID,
options
options,
) {
return this.removeInjectedApplicationCredentialSources(
[injectedApplicationCredentialSourceID],
options
options,
);
}
+2 -2
View File
@@ -37,7 +37,7 @@ export default class WorkerModel extends GeneratedWorkerModel {
return Object.values(this.config_tags).reduce(
(previousCount, currentTags) => previousCount + currentTags.length,
0
0,
);
}
@@ -51,7 +51,7 @@ export default class WorkerModel extends GeneratedWorkerModel {
}
return Object.entries(this.config_tags).flatMap(([key, value]) =>
value.map((tag) => ({ key, value: tag }))
value.map((tag) => ({ key, value: tag })),
);
}
+1 -1
View File
@@ -110,7 +110,7 @@ export default class AccountSerializer extends ApplicationSerializer {
serialized = this.serializeForChangePassword(
snapshot,
currentPassword,
newPassword
newPassword,
);
}
return serialized;
+7 -7
View File
@@ -145,18 +145,18 @@ export default class ApplicationSerializer extends RESTSerializer {
const transformedPayload = {};
// Find the Ember-data-expected root key name.
const payloadKey = this.payloadKeyFromModelName(
primaryModelClass.modelName
primaryModelClass.modelName,
);
// Copy the data rooted under `items` in the existing payload into the new
// payload under the expected root key name.
transformedPayload[payloadKey] = structuredClone(payload.items);
transformedPayload[payloadKey] = structuredClone(payload?.items);
// Return the result of normalizing the transformed payload.
return super.normalizeArrayResponse(
store,
primaryModelClass,
transformedPayload,
id,
requestType
requestType,
);
}
@@ -183,7 +183,7 @@ export default class ApplicationSerializer extends RESTSerializer {
const transformedPayload = {};
// Find the Ember-data-expected root key name.
const payloadKey = this.payloadKeyFromModelName(
primaryModelClass.modelName
primaryModelClass.modelName,
);
// Copy the unrooted payload under the expected root key name.
transformedPayload[payloadKey] = payload;
@@ -193,7 +193,7 @@ export default class ApplicationSerializer extends RESTSerializer {
primaryModelClass,
transformedPayload,
id,
requestType
requestType,
);
}
@@ -318,7 +318,7 @@ export default class ApplicationSerializer extends RESTSerializer {
primaryModelClass,
payload,
id,
requestType
requestType,
) {
const newPayload = structuredClone(payload);
@@ -338,7 +338,7 @@ export default class ApplicationSerializer extends RESTSerializer {
primaryModelClass,
newPayload,
id,
requestType
requestType,
);
}
}
+1 -1
View File
@@ -74,7 +74,7 @@ export default class AuthMethodSerializer extends ApplicationSerializer {
normalizeArrayResponse() {
const normalized = super.normalizeArrayResponse(...arguments);
normalized.data = normalized.data.sort((a) =>
a.attributes.is_primary ? -1 : 1
a.attributes.is_primary ? -1 : 1,
);
return normalized;
}
@@ -0,0 +1,23 @@
/**
* Copyright (c) HashiCorp, Inc.
* SPDX-License-Identifier: MPL-2.0
*/
import ApplicationSerializer from './application';
import { EmbeddedRecordsMixin } from '@ember-data/serializer/rest';
export default class ChannelSerializer extends ApplicationSerializer.extend(
EmbeddedRecordsMixin,
) {
normalize(typeClass, hash, ...rest) {
const normalizedHash = structuredClone(hash);
const err = normalizedHash.errors;
delete normalizedHash.errors;
const normalized = super.normalize(typeClass, normalizedHash, ...rest);
// we should not override the ember models errors field,
// so we rename the errors field from the api
normalized.data.attributes.errors_number = err;
return normalized;
}
}
@@ -7,9 +7,21 @@ import ApplicationSerializer from './application';
import { EmbeddedRecordsMixin } from '@ember-data/serializer/rest';
export default class ConnectionSerializer extends ApplicationSerializer.extend(
EmbeddedRecordsMixin
EmbeddedRecordsMixin,
) {
attrs = {
channel_recordings: { embedded: 'always' },
};
normalize(typeClass, hash, ...rest) {
const normalizedHash = structuredClone(hash);
const err = normalizedHash.errors;
delete normalizedHash.errors;
const normalized = super.normalize(typeClass, normalizedHash, ...rest);
// we should not override the ember models errors field,
// so we rename the errors field from the api
normalized.data.attributes.errors_number = err;
return normalized;
}
}
@@ -7,6 +7,7 @@ import ApplicationSerializer from './application';
import {
TYPE_CREDENTIAL_LIBRARY_VAULT_GENERIC,
TYPE_CREDENTIAL_LIBRARY_VAULT_SSH_CERTIFICATE,
options,
} from '../models/credential-library';
export default class CredentialLibrarySerializer extends ApplicationSerializer {
@@ -31,9 +32,34 @@ export default class CredentialLibrarySerializer extends ApplicationSerializer {
return super.serialize(...arguments);
}
}
serializeAttribute(snapshot, json) {
const value = super.serializeAttribute(...arguments);
const { credential_type, type, credential_mapping_overrides, isNew } =
snapshot.record;
if (
type === TYPE_CREDENTIAL_LIBRARY_VAULT_GENERIC &&
credential_mapping_overrides &&
credential_type &&
!isNew
) {
// API expects to send null to fields if it is undefined or deleted
json.credential_mapping_overrides = Object.keys(
options.mapping_overrides[credential_type],
).reduce((obj, key) => {
if (credential_mapping_overrides[key]) {
obj[key] = credential_mapping_overrides[key];
} else {
obj[key] = null;
}
return obj;
}, {});
return value;
}
}
serializeVaultGeneric() {
const serialized = super.serialize(...arguments);
if (serialized.attributes) {
// Set `http_request_body` only if `http_method` is POST
// otherwise set to null to have the field removed
+1 -1
View File
@@ -24,7 +24,7 @@ export default class CredentialSerializer extends ApplicationSerializer {
if (serialized?.attributes?.json_object) {
serialized.attributes.object = JSON.parse(
serialized.attributes.json_object
serialized.attributes.json_object,
);
delete serialized.attributes.json_object;
}
+3 -3
View File
@@ -14,7 +14,7 @@ export default class RoleSerializer extends ApplicationSerializer {
* include **only grants** and the version. Normally, grants are not
* serialized.
* If `adapterOptions.principalIDs` is set (to an array of user and
* group IDs), then the payload is serialized via `serializewithPrincipals`.
* group IDs), then the payload is serialized via `serializeWithPrincipals`.
* @override
* @param {Snapshot} snapshot
* @return {object}
@@ -26,7 +26,7 @@ export default class RoleSerializer extends ApplicationSerializer {
serialized = this.serializeWithGrantStrings(snapshot, grantStrings);
const principalIDs = snapshot?.adapterOptions?.principalIDs;
if (principalIDs)
serialized = this.serializewithPrincipals(snapshot, principalIDs);
serialized = this.serializeWithPrincipals(snapshot, principalIDs);
return serialized;
}
@@ -50,7 +50,7 @@ export default class RoleSerializer extends ApplicationSerializer {
* @param {[string]} principalIDs
* @return {object}
*/
serializewithPrincipals(snapshot, principalIDs) {
serializeWithPrincipals(snapshot, principalIDs) {
return {
version: snapshot.attr('version'),
principal_ids: principalIDs,
+35
View File
@@ -0,0 +1,35 @@
/**
* Copyright (c) HashiCorp, Inc.
* SPDX-License-Identifier: MPL-2.0
*/
import ApplicationSerializer from './application';
export default class ScopeSerializer extends ApplicationSerializer {
// =methods
serialize(snapshot) {
let serialized = super.serialize(...arguments);
const policyId = snapshot?.adapterOptions?.policyId;
if (policyId) {
serialized = this.serializeWithStoragePolicy(snapshot, policyId);
}
return serialized;
}
/**
* Returns a payload containing only version and storage policy id,
* rather than existing instances on the model.
* @param {Snapshot} snapshot
* @param {[string]} hostSetIDs
* @return {object}
*/
serializeWithStoragePolicy(snapshot, policyId) {
return {
version: snapshot.attr('version'),
storage_policy_id: policyId,
};
}
}
@@ -6,9 +6,31 @@
import ApplicationSerializer from './application';
import { EmbeddedRecordsMixin } from '@ember-data/serializer/rest';
export default class RecordingSerializer extends ApplicationSerializer.extend(
EmbeddedRecordsMixin
EmbeddedRecordsMixin,
) {
attrs = {
connection_recordings: { embedded: 'always' },
};
serialize(snapshot) {
let serialized = super.serialize(...arguments);
// The post request for reapply-storage-policy doesn't expect a payload,
// so we return nothing
if (snapshot?.adapterOptions?.method === 'reapply-storage-policy') {
return {};
}
return serialized;
}
normalize(typeClass, hash, ...rest) {
const normalizedHash = structuredClone(hash);
const err = normalizedHash.errors;
delete normalizedHash.errors;
const normalized = super.normalize(typeClass, normalizedHash, ...rest);
// we should not override the ember models errors field,
// so we rename the errors field from the api
normalized.data.attributes.errors_number = err;
return normalized;
}
}
+37 -6
View File
@@ -4,7 +4,10 @@
*/
import ApplicationSerializer from './application';
import { TYPE_CREDENTIAL_DYNAMIC } from '../models/storage-bucket';
import {
TYPE_CREDENTIAL_DYNAMIC,
TYPE_STORAGE_BUCKET_PLUGIN_AWS_S3,
} from '../models/storage-bucket';
const fieldsByCredentialType = {
static: [
@@ -12,27 +15,55 @@ const fieldsByCredentialType = {
'secret_access_key',
'region',
'disable_credential_rotation',
'endpoint_url',
],
dynamic: [
'role_arn',
'role_external_id',
'role_session_name',
'role_tags',
'disable_credential_rotation',
'region',
'disable_credential_rotation',
'endpoint_url',
],
};
export default class StorageBucketSerializer extends ApplicationSerializer {
/**
* Serializes storage-bucket. ATM just AWS needs specific serialization,
* for the other plugin types use default.
* @param {object} snapshot
* @returns
*/
serialize(snapshot) {
const serialized = super.serialize(...arguments);
const { credentialType } = snapshot.record;
const pluginType = snapshot.record.plugin?.name;
const serialized = super.serialize(...arguments);
// Common for all pluginTypes
if (!snapshot.record.isNew) {
delete serialized.bucket_name;
delete serialized.bucket_prefix;
}
if (credentialType === TYPE_CREDENTIAL_DYNAMIC) {
serialized.attributes.disable_credential_rotation = true;
if (pluginType === TYPE_STORAGE_BUCKET_PLUGIN_AWS_S3) {
return this.serializeAws(serialized, credentialType);
}
return serialized;
}
/**
* Returns a storage bucket serialized object specific for aws
* @param {object} serialized
* @param {string} credentialType
* @returns
*/
serializeAws(serialized, credentialType) {
if (serialized.attributes) {
if (credentialType === TYPE_CREDENTIAL_DYNAMIC) {
serialized.attributes.disable_credential_rotation = true;
}
delete serialized.attributes.endpoint_url;
}
return serialized;
}
@@ -45,7 +76,7 @@ export default class StorageBucketSerializer extends ApplicationSerializer {
if (options.isNestedAttribute && json.attributes) {
// The key must be included in the fieldsByType list above
if (!fieldsByCredentialType[credentialType].includes(key))
//API requires these fields to be null
// API requires these fields to be null
json.attributes[key] = null;
}
+25 -4
View File
@@ -36,14 +36,22 @@ export default class TargetSerializer extends ApplicationSerializer {
if (brokeredCredentialSourceIDs)
serialized = this.serializeWithBrokeredCredentialSources(
snapshot,
brokeredCredentialSourceIDs
brokeredCredentialSourceIDs,
);
if (injectedApplicationCredentialSourceIDs)
serialized = this.serializeWithInjectedApplicationCredentialSources(
snapshot,
injectedApplicationCredentialSourceIDs
injectedApplicationCredentialSourceIDs,
);
if (serialized?.with_aliases) {
// API expects scope id along with every alias value
serialized.with_aliases = serialized.with_aliases.map((item) => ({
...item,
scope_id: 'global',
}));
}
// Delete session recording related fields from non-SSH targets
if (type !== TYPE_TARGET_SSH) {
delete serialized?.attributes?.storage_bucket_id;
@@ -75,7 +83,7 @@ export default class TargetSerializer extends ApplicationSerializer {
*/
serializeWithBrokeredCredentialSources(
snapshot,
brokered_credential_source_ids
brokered_credential_source_ids,
) {
return {
version: snapshot.attr('version'),
@@ -92,7 +100,7 @@ export default class TargetSerializer extends ApplicationSerializer {
*/
serializeWithInjectedApplicationCredentialSources(
snapshot,
injected_application_credential_source_ids
injected_application_credential_source_ids,
) {
return {
version: snapshot.attr('version'),
@@ -112,4 +120,17 @@ export default class TargetSerializer extends ApplicationSerializer {
storage_bucket_id: snapshot?.attr('storage_bucket_id'),
};
}
normalize(typeClass, hash, ...rest) {
const normalizedHash = structuredClone(hash);
const normalized = super.normalize(typeClass, normalizedHash, ...rest);
// Ember data retains the previous entry in the array attr when the updated attr becomes undefined/empty.
// So, we explicitly set the attr to an empty array if the updated attribute is undefined from the API
if (!normalized.data.attributes.aliases) {
normalized.data.attributes.aliases = [];
}
return normalized;
}
}
+1 -1
View File
@@ -22,7 +22,7 @@ export default class WorkerSerializer extends ApplicationSerializer {
if (workerGeneratedAuthToken)
serialized = this.serializeWithGeneratedToken(
snapshot,
workerGeneratedAuthToken
workerGeneratedAuthToken,
);
return serialized;
}
+147
View File
@@ -0,0 +1,147 @@
/**
* Copyright (c) HashiCorp, Inc.
* SPDX-License-Identifier: MPL-2.0
*/
import Service from '@ember/service';
import Dexie from 'dexie';
import { typeOf } from '@ember/utils';
// List of resources we support to be cached and searched in
// indexedDb. Any field that can be searched upon should be added to
// this index. Increment the version number of the database whenever
// indexes change.
export const modelIndexes = {
token: '&id, token',
target:
'&id, attributes.created_time, attributes.type, attributes.name, attributes.description, attributes.address, attributes.scope.scope_id',
session:
'&id, attributes.created_time, attributes.type, attributes.status, attributes.endpoint, attributes.target_id, attributes.user_id, attributes.scope.scope_id',
user: '&id, attributes.created_time, attributes.name, attributes.description, attributes.scope.scope_id',
group:
'&id, attributes.created_time, attributes.name, attributes.description, attributes.scope.scope_id',
role: '&id, attributes.created_time, attributes.name, attributes.description, attributes.scope.scope_id',
scope:
'&id, attributes.created_time, attributes.type, attributes.name, attributes.description, attributes.scope.scope_id',
'credential-store':
'&id, attributes.created_time, attributes.name, attributes.description, attributes.type, attributes.scope.scope_id',
'host-catalog':
'&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',
};
export const formatDbName = (userId, clusterUrl) =>
`boundary-${userId}-${clusterUrl}`;
/**
* Recursively copy over the object and convert any booleans to "true" or "false" so they can be indexed.
* Also converts any ember-like arrays back to a standard array.
* @param result
* @param object
* @returns {*}
*/
const convertFields = (result, object) => {
Object.entries(object).forEach(([key, value]) => {
if (typeOf(value) === 'object') {
result[key] = convertFields({}, value);
} else if (typeOf(value) === 'boolean') {
result[key] = value ? 'true' : 'false';
} else if (typeOf(value) === 'array') {
result[key] = [...value];
} else {
result[key] = value;
}
});
return result;
};
/**
* Recursively copy over the object and convert any string "true" or "false" back to booleans.
* Will also convert any array fields back using their model transformation.
* @param result
* @param object
* @param schema
* @param serializer
* @returns {*}
*/
const unconvertFields = (result, object, schema, serializer) => {
Object.entries(object).forEach(([key, value]) => {
if (typeOf(value) === 'object') {
result[key] = unconvertFields({}, value, schema, serializer);
} else if (value === 'true' || value === 'false') {
result[key] = value === 'true';
} else if (typeOf(value) === 'array') {
const attribute = schema.attributes.get(key);
// If attribute type is array, we transform it back to a tracked array
if (attribute?.type === 'array') {
const transformer = serializer.transformFor(attribute.type);
result[key] = transformer.deserialize(value, attribute.options);
return;
}
result[key] = value;
} else {
result[key] = value;
}
});
return result;
};
/**
* Service to encapsulate the IndexedDB implementation. To use this service, call
* `setup` from the application root and
*/
export default class IndexedDbService extends Service {
// =attributes
#db;
get db() {
return this.#db;
}
setup(dbName) {
// Don't run setup again if we already have one or if we didn't get a name
if (this.#db || !dbName) {
return;
}
this.#db = new Dexie(dbName);
this.#db.version(1).stores(modelIndexes);
}
/**
* Cleanup the data by converting all fields to plain javascript objects.
* We will also convert booleans to "false" or "true".
* IndexedDB doesn't support indexes on boolean values so we have to
* convert them to be able to support using boolean values.
*
* Undo the operation by setting `convertFields` to false.
*
* @param {Object} data
* @param {Boolean} cleanData
* @param {Object} schema
* @param {Object} serializer
* @return {{id, type, attributes: {}, relationships: {}}}
*/
normalizeData({ data, cleanData, schema, serializer }) {
if (!data) {
return data;
}
let { id, type, attributes = {}, relationships = {} } = data;
return {
id,
type,
attributes: cleanData
? convertFields({}, attributes)
: unconvertFields({}, attributes, schema, serializer),
relationships: cleanData
? convertFields({}, relationships)
: unconvertFields({}, relationships, schema, serializer),
};
}
}
@@ -42,8 +42,8 @@ export class ResourceFilter {
return this.in(value.contains, key);
}
return this.equals(key, value);
})
)
}),
),
);
})
.flat()
+22
View File
@@ -0,0 +1,22 @@
/**
* Copyright (c) HashiCorp, Inc.
* SPDX-License-Identifier: MPL-2.0
*/
import Store, { CacheHandler } from '@ember-data/store';
import RequestManager from '@ember-data/request';
import { LegacyNetworkHandler } from '@ember-data/legacy-compat';
import IndexedDbHandler from 'api/handlers/indexed-db-handler';
export default class extends Store {
requestManager = new RequestManager();
constructor(args) {
super(args);
const indexedDbHandler = new IndexedDbHandler(this);
this.requestManager.use([indexedDbHandler, LegacyNetworkHandler]);
this.requestManager.useCache(CacheHandler);
}
}
+19
View File
@@ -0,0 +1,19 @@
/**
* Copyright (c) HashiCorp, Inc.
* SPDX-License-Identifier: MPL-2.0
*/
import Transform from '@ember-data/serializer/transform';
import { TrackedArray } from 'tracked-built-ins';
export default class ArrayTransform extends Transform {
deserialize(serialized) {
const arr = new TrackedArray(serialized || []);
return arr;
}
serialize(deserialized) {
const arr = deserialized || [];
return arr;
}
}
+29
View File
@@ -0,0 +1,29 @@
/**
* Copyright (c) HashiCorp, Inc.
* SPDX-License-Identifier: MPL-2.0
*/
import Transform from '@ember-data/serializer/transform';
import { TrackedObject } from 'tracked-built-ins';
export default class ObjectTransform extends Transform {
/**
* @param serialized
* @returns {object}
*/
deserialize(serialized) {
const obj = new TrackedObject(serialized || {});
return obj;
}
/**
* @param deserialized
* @returns {object}
*/
serialize(deserialized) {
if (!deserialized) {
return {};
}
return deserialized;
}
}
@@ -1,26 +0,0 @@
/**
* Copyright (c) HashiCorp, Inc.
* SPDX-License-Identifier: MPL-2.0
*/
import Transform from '@ember-data/serializer/transform';
export default class PrincipalArrayTransform extends Transform {
deserialize(serialized) {
const stringValues = serialized || [];
return stringValues.map(({ id: principal_id, scope_id, type }) => ({
principal_id,
scope_id,
type,
}));
}
serialize(deserialized) {
const strings = deserialized || [];
return strings.map(({ principal_id: id, scope_id, type }) => ({
id,
scope_id,
type,
}));
}
}
+29
View File
@@ -0,0 +1,29 @@
/**
* Copyright (c) HashiCorp, Inc.
* SPDX-License-Identifier: MPL-2.0
*/
/**
* Takes an object and gets the JSON stringified version of it to be converted
* to a hash code. Taken from https://stackoverflow.com/a/8076436
* @param obj
*/
export const hashCode = (obj) => {
if (!obj) {
return 0;
}
// Use a replacer function to sort the keys of the object so we get the same hashcode
// regardless of the order of the keys.
const jsonString = JSON.stringify(obj, Object.keys(obj).sort());
let hash = 0;
for (let i = 0; i < jsonString.length; i++) {
let code = jsonString.charCodeAt(i);
hash = (hash << 5) - hash + code;
hash = hash & hash; // Convert to 32bit integer
}
// Make sure the hash is positive since we're using it as an ID
return Math.abs(hash);
};
+263
View File
@@ -0,0 +1,263 @@
/**
* Copyright (c) HashiCorp, Inc.
* SPDX-License-Identifier: MPL-2.0
*/
import { get } from '@ember/object';
import { modelIndexes } from '../services/indexed-db';
/**
* Takes a POJO representing a filter query and builds a query to
* query indexedDb with. Note that the first filter is important as that
* will use the actual index in indexedDb while any subsequent ones will be less efficient.
*
* @example
* const filter = queryIndexedDb(indexedDb, type, {
* search: generated',
* filters: {
* scope_id: {
* logicalOperator: 'and',
* values: [{ notEquals: 'scope1' }, { notEquals: 'scope2' }],
* },
* },
* });
*/
export async function queryIndexedDb(indexedDb, resource, query) {
let { search, filters = {} } = query ?? {};
let filterCollection = indexedDb[resource];
search = getSearchObject(search, resource);
filters = cleanObject(filters);
if (Object.keys(filters).length) {
// Remove the first item to use as the initial collection and then reduce the remaining ones
const entries = Object.entries(filters);
const [firstKey, firstFilterArrayOrObject] = entries.shift();
filterCollection = await entries.reduce(
async (currCollection, [key, filterArrayOrObject]) => {
// Grab the results from the set of one filters to be `AND` together with the rest of the filters
const filterResults = await buildInitialWhereClause({
table: indexedDb[resource],
key,
filterArrayOrObject,
}).primaryKeys();
const resultIdsSet = new Set(filterResults);
return (await currCollection).and((record) => {
return resultIdsSet.has(record.id);
});
},
buildInitialWhereClause({
key: firstKey,
table: indexedDb[resource],
filterArrayOrObject: firstFilterArrayOrObject,
}),
);
}
if (search) {
const { text, fields } = search;
filterCollection = filterCollection.filter((record) =>
fields
.map((key) => get(record, key))
.some((element) => {
if (typeof element === 'string') {
return element?.toLowerCase().includes(text?.toLowerCase());
}
}),
);
}
// OrderBy has to be used on where clauses while if it's a
// collection already we have to use sortBy. We'll also sort by
// descending order based on created time to match the API as any
// "or" clause can change the order
if (filterCollection.orderBy) {
return filterCollection.orderBy(getKey('created_time')).reverse().toArray();
}
return filterCollection.reverse().sortBy(getKey('created_time'));
}
const buildInitialWhereClause = ({ filterArrayOrObject, table, key }) => {
const filterValueArray = Array.isArray(filterArrayOrObject)
? filterArrayOrObject
: filterArrayOrObject.values;
const { logicalOperator } = filterArrayOrObject;
// Short circuit if all the filter types were equals or notEquals since indexedDb
// can more efficiently query if we pass all values at once
const checkAllFilterType = (type) =>
filterValueArray.every((obj) => Object.keys(obj)[0] === type);
if (checkAllFilterType('equals')) {
return table
.where(getKey(key))
.anyOf(filterValueArray.map((obj) => obj['equals']));
}
if (checkAllFilterType('notEquals')) {
return table
.where(getKey(key))
.noneOf(filterValueArray.map((obj) => obj['notEquals']));
}
// Remove the first item to use as the initial where clause and then reduce the remaining ones
const [firstOperation, firstFilterValue] = Object.entries(
filterValueArray[0],
)[0];
// Not all are filters are equals or notEquals,
// manually build the initial where clause and resulting collections
return filterValueArray.slice(1).reduce(
(result, currObj) => {
const [operation, value] = Object.entries(currObj)[0];
return buildIndexedDbCollection({
key: getKey(key),
value,
collection: result,
operation,
logicalOperator,
});
},
buildIndexedDbWhere({
table,
key: getKey(key),
operation: firstOperation,
value: firstFilterValue,
}),
);
};
/**
* Builds the initial where clause for indexed DB to filter on. Note that this makes
* the first filter important as that will do the real filtering from indexed DB while
* any subsequent filter has to be done in memory.
*/
const buildIndexedDbWhere = ({ table, key, value, operation }) => {
const baseWhereClause = table.where(key);
switch (operation) {
case 'contains':
// We return an error due to not being able to support contains on first filter due to performance.
throw new Error('Contains is not supported as the first filter.');
case 'gt':
return baseWhereClause.above(value);
case 'gte':
return baseWhereClause.aboveOrEqual(value);
case 'lt':
return baseWhereClause.below(value);
case 'lte':
return baseWhereClause.belowOrEqual(value);
case 'notEquals':
return baseWhereClause.notEqual(value);
default:
return baseWhereClause.equals(value);
}
};
/**
* Continues building the queries for indexed DB to filter on. Note that these are not true
* indexed DB queries and in fact just standard JS filters for logical "and" queries and parallel queries
* to indexed DB for logical "or" queries that get deduped.
*/
const buildIndexedDbCollection = ({
key,
value,
collection,
operation,
logicalOperator,
}) => {
if (logicalOperator === 'and') {
switch (operation) {
case 'contains':
return collection.and((record) => get(record, key)?.includes(value));
case 'gt':
return collection.and((record) => get(record, key) > value);
case 'gte':
return collection.and((record) => get(record, key) >= value);
case 'lt':
return collection.and((record) => get(record, key) < value);
case 'lte':
return collection.and((record) => get(record, key) <= value);
case 'notEquals':
return collection.and((record) => get(record, key) !== value);
default:
return collection.and((record) => get(record, key) === value);
}
}
switch (operation) {
case 'contains':
// We return an error due to not being able to support contains on this filter due to performance.
throw new Error(
'Contains is not supported as a filter option with "or" operator.',
);
case 'gt':
return collection.or(key).above(value);
case 'gte':
return collection.or(key).aboveOrEqual(value);
case 'lt':
return collection.or(key).below(value);
case 'lte':
return collection.or(key).belowOrEqual(value);
case 'notEquals':
return collection.or(key).notEqual(value);
default:
return collection.or(key).equals(value);
}
};
/**
* Translates the fields passed in from the UI for resources to the keys indexed DB knows them as.
* Usually it's the path of the actual normalized model.
*/
const getKey = (key) => {
switch (key) {
case 'scope_id':
return `attributes.scope.${key}`;
case 'id':
return key;
default:
return `attributes.${key}`;
}
};
/**
* Cleans the object to remove any keys that have a value of an empty array. This makes
* it easier so we don't have to worry about empty arrays getting queried in indexed db.
*/
const cleanObject = (obj) => {
if (!obj) {
return {};
}
return Object.entries(obj).reduce((result, [key, value]) => {
if (Array.isArray(value)) {
if (value.length > 0) {
result[key] = value;
}
} else if (value.values.length > 0) {
result[key] = value;
}
return result;
}, {});
};
/**
* Makes the search object that is expected when a user searches. Uses
* the indexes we setup in indexed db.
*/
const getSearchObject = (text, resource) => {
if (!text) {
return null;
}
return {
text,
fields: modelIndexes[resource]
.split(', ')
.map((index) => index.replace('&', '')),
};
};
+141
View File
@@ -0,0 +1,141 @@
/**
* Copyright (c) HashiCorp, Inc.
* SPDX-License-Identifier: MPL-2.0
*/
/**
* Takes a POJO representing a filter query and converts it to an
* MQL expression string which is understood by the client daemon.
*
* @example
* const filter = generateMQLFilterExpression({
* name: { logicalOperator: 'and', values: [{ notEquals: 'search text' }, { notEquals: 'test' }] },
* scope_id: [{ equals: 'scope1'}, { equals: 'scope2' }],
* });
*
* // (name % "search text") and (scope_id = "scope1" or scope_id = "scope2")
*/
export function generateMQLFilterExpression(filterObj) {
if (!filterObj) {
return null;
}
const expressions = Object.entries(filterObj)
.map(([key, filterArrayOrObject]) => {
const filterValueArray = Array.isArray(filterArrayOrObject)
? filterArrayOrObject
: filterArrayOrObject.values;
let clauses;
const filterValues = filterValueArray.map((filterObjValue) => {
if (!filterObjValue) {
return null;
}
const [operation, value] = Object.entries(filterObjValue)[0];
switch (operation) {
case 'contains':
return contains(key, value);
case 'gt':
return gt(key, value);
case 'gte':
return gte(key, value);
case 'lt':
return lt(key, value);
case 'lte':
return lte(key, value);
case 'notEquals':
return notEquals(key, value);
default:
return equals(key, value);
}
});
// Default to `or` if we don't have a logical operator
const { logicalOperator } = filterArrayOrObject;
if (logicalOperator === 'and') {
clauses = and(filterValues);
} else {
clauses = or(filterValues);
}
return parenthetical(clauses);
})
.filter((item) => item);
return and(expressions);
}
/**
* Takes a POJO representing a search query and converts it to an
* MQL expression string which is understood by the client daemon.
*
* @example
* const search = generateMQLSearchExpression({
* text: 'search',
* fields: ['id', 'name', 'description']
* });
*
* // (id % 'search' or name % 'search' or description % 'search')
*/
export function generateMQLSearchExpression(searchObj) {
if (!searchObj) {
return null;
}
const { text, fields } = searchObj;
return parenthetical(
or(fields.map((field) => contains(field, text)).filter((item) => item)),
);
}
/**
* Generates the MQL expression when a user passes in both search and filters.
*/
export function generateMQLExpression(obj) {
const { search, filters } = obj;
const expressions = [
generateMQLSearchExpression(search),
generateMQLFilterExpression(filters),
].filter((item) => item);
return and(expressions);
}
const isEmpty = (input) =>
input === null || input === undefined || input === '';
// Escape any double quotes or backslashes and add quotes if it's a string
const sanitize = (input) =>
typeof input === 'string' ? `"${input?.replace(/(["\\])/g, '\\$1')}"` : input;
// Comparison Operators
const equals = (key, value) =>
!isEmpty(value) ? `${key} = ${sanitize(value)}` : null;
const notEquals = (key, value) =>
!isEmpty(value) ? `${key} != ${sanitize(value)}` : null;
const contains = (key, value) =>
!isEmpty(value) ? `${key} % ${sanitize(value)}` : null;
const gt = (key, value) =>
!isEmpty(value) ? `${key} > ${sanitize(value)}` : null;
const gte = (key, value) =>
!isEmpty(value) ? `${key} >= ${sanitize(value)}` : null;
const lt = (key, value) =>
!isEmpty(value) ? `${key} < ${sanitize(value)}` : null;
const lte = (key, value) =>
!isEmpty(value) ? `${key} <= ${sanitize(value)}` : null;
// Logical Operators
const and = (clauses) => clauses.join(' and ');
const or = (clauses) => clauses.join(' or ');
const parenthetical = (expression) => (expression ? `(${expression})` : null);
@@ -0,0 +1,29 @@
/**
* Copyright (c) HashiCorp, Inc.
* SPDX-License-Identifier: MPL-2.0
*/
/**
* Takes an array and the current page and pagesize to calculate the correct
* number of results to return to the caller.
*
* @param array
* @param page
* @param pageSize
* @returns {[*]}
*/
export const paginateResults = (array, page, pageSize) => {
const length = array?.length;
if (!array || length === 0) {
return [];
}
if (!page || !pageSize) {
return array;
}
const offset = (page - 1) * pageSize;
const start = Math.min(length - 1, offset);
const end = Math.min(length, offset + pageSize);
return array.slice(start, end);
};
@@ -3,4 +3,4 @@
* SPDX-License-Identifier: MPL-2.0
*/
export { default } from 'api/transforms/principal-array';
export { default } from 'api/abilities/policy';
+6
View File
@@ -0,0 +1,6 @@
/**
* Copyright (c) HashiCorp, Inc.
* SPDX-License-Identifier: MPL-2.0
*/
export { default } from 'api/abilities/scope';
@@ -0,0 +1,6 @@
/**
* Copyright (c) HashiCorp, Inc.
* SPDX-License-Identifier: MPL-2.0
*/
export { default, resourceNames } from 'api/handlers/client-daemon-handler';
@@ -0,0 +1,6 @@
/**
* Copyright (c) HashiCorp, Inc.
* SPDX-License-Identifier: MPL-2.0
*/
export { default, initialize } from 'api/initializers/deprecations';
+6
View File
@@ -0,0 +1,6 @@
/**
* Copyright (c) HashiCorp, Inc.
* SPDX-License-Identifier: MPL-2.0
*/
export { default } from 'api/models/alias';
+6
View File
@@ -0,0 +1,6 @@
/**
* Copyright (c) HashiCorp, Inc.
* SPDX-License-Identifier: MPL-2.0
*/
export { default } from 'api/models/policy';
@@ -0,0 +1,6 @@
/**
* Copyright (c) HashiCorp, Inc.
* SPDX-License-Identifier: MPL-2.0
*/
export { default } from 'api/serializers/channel-recording';
+6
View File
@@ -0,0 +1,6 @@
/**
* Copyright (c) HashiCorp, Inc.
* SPDX-License-Identifier: MPL-2.0
*/
export { default } from 'api/serializers/scope';
+6
View File
@@ -0,0 +1,6 @@
/**
* Copyright (c) HashiCorp, Inc.
* SPDX-License-Identifier: MPL-2.0
*/
export { default } from 'api/services/indexed-db';
+6
View File
@@ -0,0 +1,6 @@
/**
* Copyright (c) HashiCorp, Inc.
* SPDX-License-Identifier: MPL-2.0
*/
export { default } from 'api/services/store';
+6
View File
@@ -0,0 +1,6 @@
/**
* Copyright (c) HashiCorp, Inc.
* SPDX-License-Identifier: MPL-2.0
*/
export { default } from 'api/transforms/array';
+6
View File
@@ -0,0 +1,6 @@
/**
* Copyright (c) HashiCorp, Inc.
* SPDX-License-Identifier: MPL-2.0
*/
export { default } from 'api/transforms/object';
+123 -69
View File
@@ -73,8 +73,12 @@ function routes() {
return scope.scope ? scope.scope.id === scope_id : false;
});
}
return resultSet.filter(makeBooleanFilter(filter));
}
const filteredResultSet = resultSet.filter(makeBooleanFilter(filter));
// add a response_type to the response to simulate pagination
// without having response_type, the unsupported controller modal
// will show when running with mirage
return { items: filteredResultSet.models, response_type: 'complete' };
},
);
this.post('/scopes', function ({ scopes }) {
// Parent scope comes through the payload via `scope_id`, but this needs
@@ -88,31 +92,32 @@ function routes() {
this.get('/scopes/:id');
this.patch('/scopes/:id');
this.del('/scopes/:id');
this.post(
'/scopes/:idMethod',
function ({ scopes }, { params: { idMethod } }) {
const attrs = this.normalizedRequestAttrs();
const id = idMethod.split(':')[0];
const method = idMethod.split(':')[1];
const scope = scopes.find(id);
const updatedAttrs = {
version: attrs.version,
storagePolicyId: attrs.storagePolicyId,
};
if (method === 'attach-storage-policy') {
updatedAttrs.storagePolicyId = attrs.storagePolicyId;
}
if (method === 'detach-storage-policy') {
updatedAttrs.storagePolicyId = '';
}
return scope.update(updatedAttrs);
},
);
// Auth & IAM resources
this.get(
'/auth-methods',
({ authMethods }, { queryParams: { scope_id, recursive, filter } }) => {
let resultSet;
if (recursive && scope_id === 'global') {
resultSet = authMethods.all();
} else if (recursive) {
resultSet = authMethods.where((authMethod) => {
const authMethodModel = authMethods.find(authMethod.id);
return (
authMethod.scopeId === scope_id ||
authMethodModel?.scope?.scope?.id === scope_id
);
});
} else {
resultSet = authMethods.where(
(authMethod) => authMethod.scopeId === scope_id
);
}
return resultSet.filter(makeBooleanFilter(filter));
}
);
this.get('/auth-methods');
this.post('/auth-methods', function ({ authMethods }) {
const attrs = this.normalizedRequestAttrs();
if (attrs.type === 'oidc') {
@@ -130,7 +135,7 @@ function routes() {
}
return authMethods.find(id).update(attrs);
}
},
);
this.del('/auth-methods/:id', ({ authMethods }, { params: { id } }) => {
const authMethod = authMethods.find(id);
@@ -149,7 +154,7 @@ function routes() {
'/accounts',
(
{ accounts },
{ queryParams: { auth_method_id: authMethodId, filter } }
{ queryParams: { auth_method_id: authMethodId, filter } },
) => {
let resultSet;
if (authMethodId) {
@@ -158,7 +163,7 @@ function routes() {
resultSet = accounts.all();
}
return resultSet.filter(makeBooleanFilter(filter));
}
},
);
this.post('/accounts');
this.get('/accounts/:id');
@@ -184,7 +189,7 @@ function routes() {
updatedAttrs.attributes.password = attrs.new_password;
}
return account.update(updatedAttrs);
}
},
);
// Authenticate + auth methods custom routes
@@ -211,7 +216,7 @@ function routes() {
resultSet = users.where((user) => user.scopeId === scope_id);
}
return resultSet.filter(makeBooleanFilter(filter));
}
},
);
this.post('/users');
this.get('/users/:id');
@@ -262,7 +267,7 @@ function routes() {
resultSet = groups.where((group) => group.scopeId === scope_id);
}
return resultSet.filter(makeBooleanFilter(filter));
}
},
);
this.post('/groups');
this.get('/groups/:id');
@@ -294,13 +299,11 @@ function routes() {
});
}
return group.update(updatedAttrs);
}
},
);
// IAM: Roles
this.get('/roles', ({ roles }, { queryParams: { scope_id: scopeId } }) => {
return roles.where({ scopeId });
});
this.get('/roles');
this.post('/roles');
this.get('/roles/:id');
this.patch('/roles/:id');
@@ -309,7 +312,7 @@ function routes() {
'/roles/:idMethod',
function (
{ roles, users, groups, managedGroups },
{ params: { idMethod } }
{ params: { idMethod } },
) {
const attrs = this.normalizedRequestAttrs();
const id = idMethod.split(':')[0];
@@ -361,7 +364,7 @@ function routes() {
updatedAttrs.managedGroupIds = updatedAttrs.managedGroupIds.filter(
(id) => {
return !attrs.principalIds.includes(id);
}
},
);
}
@@ -373,18 +376,13 @@ function routes() {
}
return role.update(updatedAttrs);
}
},
);
// Other resources
// host-catalog
this.get(
'/host-catalogs',
({ hostCatalogs }, { queryParams: { scope_id: scopeId } }) => {
return hostCatalogs.where({ scopeId });
}
);
this.get('/host-catalogs');
this.post(
'/host-catalogs',
function ({ hostCatalogs }, { queryParams: { plugin_name } }) {
@@ -396,7 +394,7 @@ function routes() {
};
}
return hostCatalogs.create(attrs);
}
},
);
this.get('/host-catalogs/:id');
this.patch('/host-catalogs/:id');
@@ -408,7 +406,7 @@ function routes() {
'/hosts',
function ({ hosts }, { queryParams: { host_catalog_id: hostCatalogId } }) {
return hosts.where({ hostCatalogId });
}
},
);
this.post('/hosts', function ({ hostCatalogs, hosts }) {
const attrs = this.normalizedRequestAttrs();
@@ -426,14 +424,22 @@ function routes() {
'/host-sets',
function (
{ hostSets },
{ queryParams: { host_catalog_id: hostCatalogId } }
{ queryParams: { host_catalog_id: hostCatalogId } },
) {
return hostSets.where({ hostCatalogId });
}
},
);
this.post('/host-sets', function ({ hostCatalogs, hostSets }) {
const attrs = this.normalizedRequestAttrs();
const hostCatalog = hostCatalogs.find(attrs.hostCatalogId);
//this needs to be attached while creating a plugin type host set to mimic API
if (hostCatalog.plugin) {
attrs.type = 'plugin';
attrs.plugin = {
name: hostCatalog.plugin.name,
};
}
attrs.scopeId = hostCatalog.scope.id;
return hostSets.create(attrs);
});
@@ -469,7 +475,7 @@ function routes() {
}
return hostSet.update(updatedAttrs);
}
},
);
// target
@@ -492,7 +498,7 @@ function routes() {
resultSet = targets.where((target) => target.scopeId === scope_id);
}
return resultSet.filter(makeBooleanFilter(filter));
}
},
);
this.post('/targets', function ({ targets }) {
const attrs = this.normalizedRequestAttrs();
@@ -540,7 +546,7 @@ function routes() {
resultSet = sessions.where((session) => session.scopeId === scope_id);
}
return resultSet.filter(makeBooleanFilter(filter));
}
},
);
this.get('/sessions/:id', function ({ sessions }, { params: { id } }) {
const session = sessions.find(id);
@@ -565,7 +571,7 @@ function routes() {
updatedAttrs.status = 'canceling';
}
return session.update(updatedAttrs);
}
},
);
// auth-tokens
@@ -578,11 +584,7 @@ function routes() {
// credential-stores
this.get(
'/credential-stores',
({ credentialStores }, { queryParams: { scope_id: scopeId } }) =>
credentialStores.where({ scopeId })
);
this.get('/credential-stores');
this.get('/credential-stores/:id');
this.post('/credential-stores');
@@ -595,8 +597,8 @@ function routes() {
'/credential-libraries',
(
{ credentialLibraries },
{ queryParams: { credential_store_id: credentialStoreId } }
) => credentialLibraries.where({ credentialStoreId })
{ queryParams: { credential_store_id: credentialStoreId } },
) => credentialLibraries.where({ credentialStoreId }),
);
this.get('/credential-libraries/:id');
this.post(
@@ -606,7 +608,7 @@ function routes() {
const credentialStore = credentialStores.find(attrs.credentialStoreId);
attrs.scopeId = credentialStore.scope.id;
return credentialLibraries.create(attrs);
}
},
);
this.del('/credential-libraries/:id');
this.patch('/credential-libraries/:id');
@@ -617,8 +619,8 @@ function routes() {
'/credentials',
(
{ credentials },
{ queryParams: { credential_store_id: credentialStoreId } }
) => credentials.where({ credentialStoreId })
{ queryParams: { credential_store_id: credentialStoreId } },
) => credentials.where({ credentialStoreId }),
);
this.get('/credentials/:id');
this.post('/credentials', function ({ credentialStores, credentials }) {
@@ -636,7 +638,7 @@ function routes() {
'/managed-groups',
(
{ managedGroups },
{ queryParams: { auth_method_id: authMethodId, filter } }
{ queryParams: { auth_method_id: authMethodId, filter } },
) => {
let resultSet;
if (authMethodId) {
@@ -645,7 +647,7 @@ function routes() {
resultSet = managedGroups.all();
}
return resultSet.filter(makeBooleanFilter(filter));
}
},
);
this.post('/managed-groups');
this.get('/managed-groups/:id');
@@ -657,7 +659,7 @@ function routes() {
'/workers',
({ workers }, { queryParams: { scope_id: scopeId } }) => {
return workers.where({ scopeId });
}
},
);
this.get('/workers/:id');
this.del('/workers/:id');
@@ -681,7 +683,7 @@ function routes() {
return storageBuckets.all();
}
return storageBuckets.where({ scopeId });
}
},
);
this.get('/storage-buckets/:id');
this.del('/storage-buckets/:id');
@@ -700,21 +702,53 @@ function routes() {
delete attrs.secrets;
return storageBuckets.create(attrs);
}
},
);
//storage-policy
this.get(
'/policies',
({ policies }, { queryParams: { scope_id: scopeId } }) => {
return policies.where({ scopeId });
},
);
this.get('/policies/:id');
this.del('/policies/:id');
this.patch('/policies/:id');
this.post('/policies', function ({ policies }) {
const attrs = this.normalizedRequestAttrs();
return policies.create(attrs);
});
// Alias
this.get(
'/aliases',
({ aliases }, { queryParams: { scope_id: scopeId } }) => {
return aliases.where({ scopeId });
},
);
this.get('/aliases/:id');
this.del('/aliases/:id');
this.patch('/aliases/:id');
this.post('/aliases', function ({ aliases }) {
const attrs = this.normalizedRequestAttrs();
return aliases.create(attrs);
});
// session recordings
this.get(
'/session-recordings',
(
{ sessionRecordings },
{ queryParams: { scope_id: scopeId, recursive } }
{ queryParams: { scope_id: scopeId, recursive } },
) => {
if (recursive && scopeId === 'global') {
return sessionRecordings.all();
}
return sessionRecordings.where({ scopeId });
}
},
);
this.get(
'/session-recordings/:idMethod',
@@ -727,9 +761,29 @@ function routes() {
} else {
return sessionRecordings.find(id);
}
}
},
);
this.post(
'/session-recordings/:idMethod',
function ({ sessionRecordings }, { params: { idMethod } }) {
const attrs = this.normalizedRequestAttrs();
const id = idMethod.split(':')[0];
const method = idMethod.split(':')[1];
const record = sessionRecordings.find(id);
const updatedAttrs = {
version: attrs.version,
};
if (method === 'reapply-storage-policy') {
updatedAttrs.retain_until = faker.date.recent();
updatedAttrs.delete_after = faker.date.recent();
}
return record.update(updatedAttrs);
},
);
this.del('/session-recordings/:id');
/* Uncomment the following line and the Response import above
* Then change the response code to simulate error responses.
* this.get('/scopes', () => new Response(505));
+22
View File
@@ -0,0 +1,22 @@
/**
* Copyright (c) HashiCorp, Inc.
* SPDX-License-Identifier: MPL-2.0
*/
import factory from '../generated/factories/alias';
import permissions from '../helpers/permissions';
import generateId from '../helpers/id';
const destinationIDs = ['', generateId('t_')];
export default factory.extend({
id: () => generateId('alt_'),
destination_id: (i) => destinationIDs[i % destinationIDs.length],
authorized_actions: () =>
permissions.authorizedActionsFor('alias') || [
'no-op',
'read',
'update',
'delete',
],
});
+12 -5
View File
@@ -9,6 +9,7 @@ import permissions from '../helpers/permissions';
import generateId from '../helpers/id';
import {
TYPE_AUTH_METHOD_PASSWORD,
TYPE_AUTH_METHOD_OIDC,
TYPE_AUTH_METHOD_LDAP,
TYPES_AUTH_METHOD,
@@ -23,11 +24,17 @@ export default factory.extend({
'delete',
'authenticate',
],
authorized_collection_actions: () => {
return {
accounts: ['create', 'list'],
'managed-groups': ['create', 'list'],
};
authorized_collection_actions() {
switch (this.type) {
case TYPE_AUTH_METHOD_PASSWORD:
return { accounts: ['create', 'list'] };
case TYPE_AUTH_METHOD_LDAP:
case TYPE_AUTH_METHOD_OIDC:
return {
accounts: ['create', 'list'],
'managed-groups': ['create', 'list'],
};
}
},
id: () => generateId('am_'),
@@ -11,12 +11,18 @@ import {
TYPE_CREDENTIAL_LIBRARY_VAULT_GENERIC,
TYPE_CREDENTIAL_LIBRARY_VAULT_SSH_CERTIFICATE,
TYPES_CREDENTIAL_LIBRARY,
options,
} from 'api/models/credential-library';
export default factory.extend({
id: () => generateId('cl_'),
type: (i) => TYPES_CREDENTIAL_LIBRARY[i % TYPES_CREDENTIAL_LIBRARY.length],
credential_type(i) {
if (this.type === TYPE_CREDENTIAL_LIBRARY_VAULT_GENERIC) {
return options.credential_types[i % options.credential_types.length];
}
},
authorized_actions: () =>
permissions.authorizedActionsFor('credential-library') || [
'no-op',
+11 -2
View File
@@ -54,7 +54,7 @@ export default factory.extend({
return {
disable_credential_rotation: faker.datatype.boolean(),
region: `us-${faker.location.cardinalDirection()}-${faker.number.int(
9
9,
)}`,
};
case 'azure':
@@ -85,7 +85,16 @@ export default factory.extend({
afterCreate(hostCatalog, server) {
const { scope, type } = hostCatalog;
const hosts = server.createList('host', 10, { scope, hostCatalog, type });
server.createList('host-set', 3, { scope, hostCatalog, hosts, type });
const hostSets = server.createList('host-set', 3, {
scope,
hostCatalog,
hosts,
type,
});
const hostSetIds = hostSets.map((hostSet) => hostSet.id);
hosts.forEach((host) => {
host.update({ hostSetIds });
});
},
}),
});
+35
View File
@@ -0,0 +1,35 @@
/**
* Copyright (c) HashiCorp, Inc.
* SPDX-License-Identifier: MPL-2.0
*/
import factory from '../generated/factories/policy';
import permissions from '../helpers/permissions';
import { faker } from '@faker-js/faker';
import generateId from '../helpers/id';
export default factory.extend({
id: () => generateId('pst_'),
authorized_actions: () =>
permissions.authorizedActionsFor('policy') || [
'no-op',
'read',
'update',
'delete',
],
attributes() {
return {
retain_for: {
days: faker.number.int({ min: 10, max: 100 }),
overridable: faker.datatype.boolean(),
},
delete_after: {
days: faker.number.int({ min: 101, max: 500 }),
overridable: faker.datatype.boolean(),
},
};
},
});
+2 -2
View File
@@ -21,8 +21,8 @@ export default factory.extend({
],
// eslint-disable-next-line ember/avoid-leaking-state-in-ember-objects
grant_strings: () => [
'id=*;action=*',
'id=*;type=host-catalog;actions=create,read',
'ids=*;action=*',
'ids=*;type=host-catalog;actions=create,read',
],
id: () => generateId('r_'),
+28 -16
View File
@@ -11,36 +11,48 @@ import generateId from '../helpers/id';
export default factory.extend({
type: 'global',
authorized_actions: () =>
permissions.authorizedActionsFor('scope') || [
'no-op',
'read',
'update',
'delete',
],
authorized_actions() {
const authorizedActions = ['no-op', 'read', 'update'];
// Storage policies can only be attatched to global and org scopes.
if (this.type === 'global' || this.type === 'org') {
authorizedActions.push('attach-storage-policy', 'detach-storage-policy');
}
if (this.type === 'org' || this.type === 'project') {
authorizedActions.push('delete');
}
return permissions.authorizedActionsFor('scope') || authorizedActions;
},
authorized_collection_actions() {
const collectionActions = {
scopes: ['create', 'list'],
users: ['create', 'list'],
sessions: ['list'],
groups: ['create', 'list'],
roles: ['create', 'list'],
targets: ['create', 'list'],
'credential-stores': ['create', 'list'],
'auth-methods': ['create', 'list'],
'host-catalogs': ['create', 'list'],
};
// Worker permissions only available on the global scope
// Resources that are available only on the global scope
if (this.type === 'global') {
collectionActions.workers = ['create:worker-led', 'list'];
collectionActions.aliases = ['create', 'list'];
}
// Session recording resources are only available on global or org scope
// Resources that are only available on the global or the org scope
if (this.type === 'global' || this.type === 'org') {
collectionActions['storage-buckets'] = ['create', 'list'];
collectionActions['session-recordings'] = ['list'];
collectionActions.users = ['create', 'list'];
collectionActions['auth-methods'] = ['create', 'list'];
collectionActions['policies'] = ['create', 'list'];
}
if (this.type === 'project') {
collectionActions['credential-stores'] = ['create', 'list'];
collectionActions['host-catalogs'] = ['create', 'list'];
collectionActions.sessions = ['list'];
collectionActions.targets = ['create', 'list'];
}
return collectionActions;
@@ -58,7 +70,7 @@ export default factory.extend({
type: 'org',
scope: { id: record.id, type: record.type },
},
'withChildren'
'withChildren',
);
}
if (record.type === 'org') {
@@ -43,11 +43,24 @@ export default factory.extend({
: null;
},
retain_until() {
return this.state === STATE_SESSION_RECORDING_AVAILABLE
? faker.date.recent()
: null;
},
delete_after() {
return this.state === STATE_SESSION_RECORDING_AVAILABLE
? faker.date.recent()
: null;
},
authorized_actions: () =>
permissions.authorizedActionsFor('session-recording') || [
'no-op',
'read',
'download',
'reapply-storage-policy',
'delete',
],
withNonExistingUserAndTarget: trait({
@@ -57,7 +70,8 @@ export default factory.extend({
const session = pickRandomElement(server.schema.sessions.all().models);
session.id = 'deleted_session';
const target = pickRandomElement(
server.schema.targets.where((target) => target.storage_bucket_id).models
server.schema.targets.where((target) => target.storage_bucket_id)
.models,
);
target.id = 'deleted_target';
@@ -77,7 +91,8 @@ export default factory.extend({
const user = pickRandomElement(server.schema.users.all().models);
const session = pickRandomElement(server.schema.sessions.all().models);
const target = pickRandomElement(
server.schema.targets.where((target) => target.storage_bucket_id).models
server.schema.targets.where((target) => target.storage_bucket_id)
.models,
);
sessionRecording.update({
+3 -1
View File
@@ -7,6 +7,7 @@ import factory from '../generated/factories/session';
import { trait } from 'miragejs';
import { faker } from '@faker-js/faker';
import generateId from '../helpers/id';
import permissions from '../helpers/permissions';
const statusStrings = ['pending', 'active', 'canceling', 'terminated'];
@@ -15,7 +16,8 @@ export const pickRandomStatusString = () =>
export default factory.extend({
id: () => generateId('ss_'),
authorized_actions: () =>
permissions.authorizedActionsFor('session') || ['read', 'cancel'],
status: pickRandomStatusString(),
/**
@@ -11,6 +11,7 @@ import {
TYPES_STORAGE_BUCKET as types,
TYPES_STORAGE_BUCKET_PLUGIN,
TYPE_STORAGE_BUCKET_PLUGIN_AWS_S3,
TYPE_STORAGE_BUCKET_PLUGIN_MINIO,
} from 'api/models/storage-bucket';
// Represents known plugin types, except "foobar" which models the possibility
@@ -46,10 +47,14 @@ export default factory.extend({
case TYPE_STORAGE_BUCKET_PLUGIN_AWS_S3:
return {
region: `us-${faker.location.cardinalDirection()}-${faker.number.int(
9
9,
)}`,
disable_credential_rotation: faker.datatype.boolean(),
};
case TYPE_STORAGE_BUCKET_PLUGIN_MINIO:
return {
endpoint_url: faker.internet.url(),
};
}
},
});
+9 -1
View File
@@ -60,7 +60,7 @@ export default factory.extend({
randomlySelectedCredentialLibraries = server.schema.credentialLibraries
.where(
(credentialLibrary) => credentialLibrary.scopeId === target.scope.id
(credentialLibrary) => credentialLibrary.scopeId === target.scope.id,
)
.models.filter(() => randomBoolean())
.map((cred) => cred.id);
@@ -82,6 +82,14 @@ export default factory.extend({
});
}
const aliases = server.schema.aliases.all().models;
const randomlySelectedAliases =
aliases.length === 0 ? undefined : faker.helpers.arrayElement(aliases);
if (randomlySelectedAliases) {
target.update({
aliases: randomlySelectedAliases.aliases,
});
}
target.update({
hostSets: randomlySelectedHostSets,
brokeredCredentialSourceIds: [
@@ -0,0 +1,21 @@
/**
* Copyright (c) HashiCorp, Inc.
* SPDX-License-Identifier: MPL-2.0
*/
import { Factory } from 'miragejs';
import { faker } from '@faker-js/faker';
import { TYPE_ALIAS_TARGET } from 'api/models/alias';
/**
* GeneratedAliasModelFactory
*/
export default Factory.extend({
name: () => faker.word.words(),
type: TYPE_ALIAS_TARGET,
value: () => faker.word.words(),
description: () => faker.word.words(),
created_time: () => faker.date.recent(),
updated_time: () => faker.date.recent(),
version: () => faker.number.int(),
});
@@ -42,6 +42,7 @@ export default Factory.extend({
signing_algorithms: ['RS256', 'RS384'],
allowed_audiences: ['www.alice.com', 'www.alice.com/admin'],
idp_ca_certs: ['certificate-1234', 'certificate-5678'],
prompts: ['consent'],
};
break;
case TYPE_AUTH_METHOD_LDAP:
@@ -51,7 +52,7 @@ export default Factory.extend({
certificates: [faker.string.alphanumeric(50)],
client_certificate: faker.string.alphanumeric(50),
client_certificate_key: `---Begin Certificate --- ${faker.string.alphanumeric(
170
170,
)} ---End Certificate ---`,
client_certificate_key_hmac: faker.string.alphanumeric(50),
enable_groups: true,
Loaded 100 of 1256 files, more files were not shown because too many files have changed in this diff. Show more