Compare commits

..
123 Commits
Author SHA1 Message Date
Dharini Jeeva c21b8fdb64 chore: 🤖 update changelog (#1170)
* chore: 🤖 update changelog and bump up the binary version to 0.9.1
2022-07-06 13:13:57 -07:00
Carlos Alcaide CorvoandRandall Morey 60005f0233 chore: 🤖 Update @babel/plugin-proposal-decorators (#1157)
Update @babel/plugin-proposal-decorators

Co-authored-by: Randall Morey <randall@randallmorey.com>
2022-06-30 08:52:07 -04:00
Randall Morey da89e2f82e fix: 🐛 unable to filter for terminated sessions (#1169)
* fix: 🐛 unable to filter for terminated sessions

* fix: 🐛 reenable sessions mocks
2022-06-29 20:42:12 -04:00
Carlos Alcaide CorvoandRandall Morey c9d6f37343 chore: 🤖 Update @ember/test-helpers (#1159)
Update @ember/test-helpers

Co-authored-by: Randall Morey <randall@randallmorey.com>
2022-06-29 17:35:17 -04:00
Carlos Alcaide CorvoandRandall Morey 85e4b46821 Chore update doctoc (#1165)
* chore: 🤖 Update doc toc

Update doc toc

* chore: 🤖 Fix doctoc within core

Co-authored-by: Randall Morey <randall@randallmorey.com>
2022-06-29 16:26:36 -04:00
Carlos Alcaide CorvoandRandall Morey d464419e47 chore: 🤖 Update Cross OS (#1164)
Update Cross OS

Co-authored-by: Randall Morey <randall@randallmorey.com>
2022-06-29 15:28:46 -04:00
Carlos Alcaide CorvoandRandall Morey 021803942f chore: 🤖 Update babel-loader (#1163)
Update babel-loader

Co-authored-by: Randall Morey <randall@randallmorey.com>
2022-06-29 15:10:41 -04:00
Randall Morey eeba8dceb6 fix: 🐛 merge conflict in yarn.lock (#1168) 2022-06-29 14:10:59 -04:00
Carlos Alcaide CorvoandRandall Morey 8764633111 chore: 🤖 Update @hashicorp/flight-icons (#1162)
Update @hashicorp/flight-icons

Co-authored-by: Randall Morey <randall@randallmorey.com>
2022-06-29 13:00:27 -04:00
Carlos Alcaide CorvoandRandall Morey 9becadd3f1 chore: 🤖 Update @glimmer (#1161)
Update @glimmer

Co-authored-by: Randall Morey <randall@randallmorey.com>
2022-06-29 12:08:00 -04:00
Carlos Alcaide CorvoandRandall Morey 9f45a9a955 chore: 🤖 Update @ember/render-modifiers (#1158)
Update @ember/render-modifiers

Co-authored-by: Randall Morey <randall@randallmorey.com>
2022-06-29 11:34:31 -04:00
Carlos Alcaide CorvoandRandall Morey 51b94f7ac8 Chore update babel eslint parser (#1155)
* chore: 🤖 Fix merging conflicts

* chore: 🤖 Fix merging conflicts

Co-authored-by: Randall Morey <randall@randallmorey.com>
2022-06-29 10:51:41 -04:00
Randall Morey 890cfe5168 Refactor attributes fragments (#1156)
* refactor: 💡 migrate managed-group off fragments

* refactor: 💡 migrate credential-store off fragments

* refactor: 💡 migrate credential-library off fragments

* refactor: 💡 migrate account off fragments
2022-06-28 19:30:26 -04:00
Dharini Jeeva fe225653ec fix: 🐛 overflow dropdown ui issue (#1160) 2022-06-28 13:13:09 -07:00
Carlos Alcaide Corvo dce7447880 chore: 🤖 Upgrade @babel/core (#1153)
Upgrade @babel/core
2022-06-28 11:08:16 -07:00
Carlos Alcaide Corvo 330c3de256 Chore upgrade desktop dependencies 2 (#1152) 2022-06-28 10:27:47 -07:00
Carlos Alcaide Corvo 2d15a62990 fix: 🐛 Lock file discrepancy (#1154)
Lock file discrepancy
2022-06-27 14:38:51 -07:00
Zhihe Li 62af6e2f6e Use precommit hooks (#1150)
* chore: 🤖 Add husky and hooks

* chore: 🤖 Add lint staged for fixing lint issues

* chore: 🤖 Use prettier and disable conflicting prettier rules

* docs: ✏️ Update commit documentation in README
2022-06-27 14:35:52 -04:00
Carlos Alcaide Corvo f50acc9913 Chore upgrade desktop dependencies (#1151) 2022-06-27 09:33:10 -07:00
Dharini Jeeva 2900692c6c chore: bump up release version and Update change log (#1141)
* chore: 🤖 update to changelog and release version
2022-06-20 13:15:34 -07:00
Cameron PereraandDharini Jeeva 193a7e9600 refactor: 💡 Remove template file to fix onboarding flow titles (#1148)
Co-authored-by: Dharini Jeeva <dharini@hashicorp.com>
2022-06-20 12:01:25 -05:00
Dharini Jeeva 6b3091ea1b chore: 🤖 update to credential source (#1146) 2022-06-20 09:45:50 -07:00
Randall Morey 26baf8a80b fix: grant scope field should be functional (#1147) 2022-06-20 12:28:13 -04:00
Randall Moreyanddharini 4ef66fdd29 Add minimum support for static credential stores to admin UI (#1145)
* cred store read ability

* filter out static cred stores and credentials from credential libraries

* chore: 🤖 finish up minimum static cred store support

Co-authored-by: dharini <dharini@hashicorp.com>
2022-06-18 10:56:25 -04:00
Cameron Perera 52904dc639 Chore add onboarding role (#1142)
* chore: generate a role authorized to access the generated onboarding target
2022-06-16 16:11:11 -07:00
Cameron Perera f3a5ef5b7c refactor: 💡 Update routing to use project id in quick-start (#1140)
✅ Closes: ICU-4821
2022-06-15 15:06:09 -05:00
Randall Morey 7d8012ef1f chore: apply darker color theme to sidebar (#1139)
* chore: apply darker color theme to sidebar

* chore: hide global footer for now due to sidebar change
2022-06-15 14:27:08 -05:00
Cameron Perera 18434d4203 chore: 🤖 Disable ssh feature work (#1138)
Disable ssh feature
2022-06-15 10:42:49 -07:00
Cameron Perera d7e458ab85 refactor: 💡 Remove default value for IP address and port (#1137)
* refactor: 💡 Remove default value for IP address and port
2022-06-14 20:39:50 -07:00
Cameron Perera c5416e770a feat: 🎸 Add Controller URL component to Success screen (#1135)
* feat: 🎸 Add Controller URL component to Success screen

✅ Closes: ICU-4785

* style: 💄 Update Success screen styles to match wireframe

* refactor: 💡 Update class names to be more descriptive

* refactor: 💡 Update styles for Success card

* test: 💍 Fix failing test
2022-06-14 16:36:11 -05:00
Dharini Jeeva 2bb1c9cfec Chore onboarding route (#1136)
* fix: onboarding redirects
2022-06-14 14:21:48 -07:00
Dharini Jeeva 8bdd4416fc transition to target lists when the resource creation is successful (#1134)
* feat: 🎸  redirect the user to target lists within the project after successfully creating a resource.
2022-06-14 12:32:04 -07:00
Cameron Pereraanddharini a5da593f07 Create successful resource creation screen (#1132)
* feat: 🎸 Create successful resource creation screen

Create a screen with helpful information about Boundary once resources
have been created for the user

✅ Closes: ICU-4558

* style: 💄 remove stale comment

* chore: 🤖 resolve conflicts and merge main

Co-authored-by: dharini <dharini@hashicorp.com>
2022-06-14 09:33:51 -05:00
Randall MoreyandCameron Perera 15dc735322 chore: move onboarding to top level (#1131)
* chore: move onboarding to top level

* chore: add types

* Update ui/admin/app/routes/onboarding.js

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

* fix: broken paths

* chore: fix broken success route and simplify error handling

* fix: tests

Co-authored-by: Cameron Perera <cameron.perera@hashicorp.com>
2022-06-13 16:38:18 -04:00
Dharini Jeeva d69b0f90d8 Icu 4556 create a quick setup screen (#1129)
* feat: 🎸 Create a resource onboarding form
2022-06-10 15:43:20 -07:00
Cameron Perera 0bb5989259 feat: 🎸 Create form to choose onboarding guide path (#1124)
* feat: 🎸 Create onboarding welcome form
2022-06-09 15:47:07 -07:00
Carlos Alcaide Corvo 106999746f docs: ✏️ Update docs for yarn scripts (#1101) 2022-06-08 14:05:56 -07:00
Carlos Alcaide Corvo d60ae81bdc Fix rose peer dependencies (#1128)
Fix Rose peer dependency warnings
2022-06-08 09:25:28 -07:00
Carlos Alcaide Corvo c7cb1fbbd8 chore: 🤖 Update electron from 13 to 14 (#1125)
Update electron from 13 to 14
2022-06-08 09:09:18 -07:00
Dharini Jeeva 8a05dbbc56 create new image component (#1127)
* feat:  create image component
2022-06-08 08:45:59 -07:00
Randall Morey dc78fe9028 Chore include terminated (#1126)
* chore: 🤖 add include_terminated=true when filtering terminated

* chore: 🤖 add include_terminated=true when filtering terminated
2022-06-07 15:40:33 -04:00
Randall MoreyandDharini Jeeva 24f630f084 Chore onboarding routing logic (#1123)
* chore: 🤖 stub out onboarding routes

* chore: initial onboarding routing logic

* chore: initial routing logic and resource creation

* chore: route "manual" to new org

* Update en-us.yaml

* fix: linting

Co-authored-by: Dharini Jeeva <dharini@hashicorp.com>
2022-06-03 13:25:53 -04:00
Cameron Perera d4ac887f7a Create CODEOWNERS file (#1122)
* chore: Create CODEOWNERS file

* chore: update CODEOWNERS

* chore: 🤖 finalize CODEOWNERS changes
2022-06-03 09:44:45 -05:00
Randall Morey 9fe8ce2c00 chore: 🤖 stub out onboarding routes (#1118) 2022-06-02 08:48:34 -04:00
Randall Morey af3cfb7298 chore: 🤖 generate more realistic mock IDs (#1117)
* chore: 🤖 generate more realistic mock IDs

* Update id.js
2022-06-01 14:02:18 -04:00
Zhihe Li df609dcf2c refactor: 💡 Update deprecated new window handler (#1111)
✅ Closes: ICU-4037
2022-05-20 12:53:52 -04:00
Zhihe Li 1b9f774937 fix: 🐛 Use more common hasOwnProperty and don't modify payload (#1112) 2022-05-19 17:52:10 -04:00
Randall Morey 509215f787 chore: 🤖 display auth method names in auth form, if available (#1113) 2022-05-19 15:56:48 -04:00
Carlos Alcaide Corvo 698160d423 refactor: 💡 Rename Admin UI enterprise artifact (#1110)
Rename Admin UI generated artifact for the enterprise edition.
2022-05-17 07:03:22 -07:00
Cameron PereraandDharini Jeeva 12b18510b9 refactor: 💡 Update language to use Sign In and Sign Out (#1109)
* refactor: 💡 Update language to use Sign In and Sign Out

Update authenticate/deauthenticate language to sign in and sign out
respectively

✅ Closes: ICU-3941

* refactor: 💡 Change translation keys back to (de)authenticate

Co-authored-by: Dharini Jeeva <dharini@hashicorp.com>
2022-05-16 17:28:45 -05:00
aa52b6f9bc fix: 🐛 Update validateOrigin to throw error on bad request (#1107)
* fix: 🐛 Update validateOrigin to throw error on bad request

If the result from netRequestPromise is successful but a not a 200
response, validateOrigin will throw an error

✅ Closes: ICU-4238

* Update ui/desktop/electron-app/src/models/runtime-settings.js

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

* refactor: 💡 Add comment as to why we don't throw error for 3xxs

* Update ui/desktop/electron-app/src/models/runtime-settings.js

Co-authored-by: Randall Morey <randall@randallmorey.com>

* Update ui/desktop/electron-app/src/models/runtime-settings.js

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

Co-authored-by: Zhihe Li <zhihe.li@hashicorp.com>
Co-authored-by: Randall Morey <randall@randallmorey.com>
2022-05-16 12:20:56 -05:00
Dharini Jeeva ee47f8e19e fix: 🐛 add featureflag to target creation template (#1108)
* fix: 🐛 add featureflag to target creation template

* refactor: 💡 remove else block
2022-05-13 10:57:52 -07:00
Zhihe Li 97196368cb Fix Users page not updating fields correctly (#1105)
* fix: 🐛 Normalize update responses to track removed fields

✅ Closes: ICU-4189
2022-05-12 10:16:14 -04:00
Carlos Alcaide Corvo 7e792d3f76 Refactor UI generated artifacts creation. (#1104)
* Refactor UI generated artifacts creation. Now we generate OSS and enterprise specific artifacts

* Split builds in two separate jobs
2022-05-11 13:28:30 -07:00
Randall Morey f4df337761 chore: update github actions validator to depend on previous jobs (#1081) 2022-05-06 10:32:11 -04:00
Cameron Perera de44863d02 chore: 🤖 Add lzma-native to resolutions (#1103)
* chore: 🤖 Add lzma-native and appdmg to resolutions

* chore: 🤖 Remove appdmg resolution from electron-app

Tested that CI steps passed.
2022-05-05 17:35:53 -05:00
Cameron Perera e3f9feb474 Update polling interval to 300 seconds (5 minutes) (#1102)
Update polling interval to 300 seconds (5 minutes)
2022-05-05 11:43:07 -05:00
Carlos Alcaide Corvo 57410b7bb6 refactor: 💡 Avoid lint warning (#1095)
* refactor: 💡 Avoid lint warning
2022-05-05 08:28:41 -07:00
Carlos Alcaide Corvo 5e2c6ca0fd feat: 🎸 Add feature editions (#1094)
* feat: 🎸 Add feature editions
2022-05-05 07:42:02 -07:00
Carlos Alcaide Corvo eb36cde137 Update polling intervarl (#1100) 2022-05-04 09:51:16 -07:00
Cameron PereraandZhihe Li ccb266ea7c chore: 🤖 bump binary version and update changelog (#1099)
* chore: 🤖 bump binary version and update changelog

* chore: 🤖 Update Desktop app release date

* chore: 🤖 Update release date

Co-authored-by: Zhihe Li <zhihe.li@hashicorp.com>
2022-05-04 10:32:42 -05:00
ZedandRandall Morey 8545697b43 Add toolbar regions to align refresh button to the right (#1098)
* feat: 🎸 implement toolbar regions and apply to admin sessions

* feat: 🎸 Add toolbar regions for desktop sessions and targets

✅ Closes: ICU-4198

Co-authored-by: Randall Morey <randall@randallmorey.com>
2022-05-03 09:46:47 -04:00
Zed a8ae8d28df fix: 🐛 Reduce extra padding in tables (#1091)
✅ Closes: ICU-4046
2022-05-02 10:14:21 -04:00
Cameron Perera 952b894a32 feat: 🎸 Add ToolbarRefresher component to targets in desktop (#1093)
✅ Closes: ICU-4134
2022-04-29 18:06:11 -05:00
Cameron Perera 6f449b3b9b feat: 🎸 Add ToolbarRefresher component to sessions in admin (#1092)
✅ Closes: ICU-4133
2022-04-29 17:54:08 -05:00
Cameron PereraandRandall Morey 0f3c2f043b style: 💄 Update Refresh Button to animate when loading (#1089)
* style: 💄 Update Refresh Button to animate when loading

* refactor: 💡 Move temporary animation styles to app level styles

Co-authored-by: Randall Morey <randall@randallmorey.com>
2022-04-29 15:29:53 -05:00
Dharini Jeeva 82c94518d9 feat: refresh sessions view in admin ui (#1078) 2022-04-29 14:28:50 -04:00
Randall Morey 68a269efac feature: add toolbar refresher component (#1088) 2022-04-29 13:51:47 -04:00
Zed 75ef323e6d fix: 🐛 Desktop client not correctly loading ember app url (#1090) 2022-04-29 13:38:25 -04:00
Carlos Alcaide Corvo ccde5e88da fix: 🐛 Mac os window lifecycle (#1067) 2022-04-29 09:03:40 -07:00
Carlos Alcaide Corvo 1071241604 chore: 🤖 Increase polling time Admin UI (#1085) 2022-04-29 07:47:03 -07:00
Zed 316f0907fc fix: 🐛 Fix scrollbar for the sidebar in desktop client (#1076)
Fixed scroll bar always appearing in sidebar on macOS for desktop client
and sidebar not staying fixed in windows and linux

✅ Closes: ICU-4143
2022-04-29 10:16:34 -04:00
Cameron Perera 3bdae6dce8 feat: 🎸 refresh targets list view in desktop (#1087)
✅ Closes: ICU-4024
2022-04-28 17:35:52 -05:00
Carlos Alcaide Corvo 367545fd4d refactor: 💡 Encapsulate desktop client window creation (#1066)
Encapsulate desktop client window creation to reuse the creation of new
windows.
2022-04-28 15:23:43 -07:00
Randall Morey 702ad64716 Style toolbar buttons (#1086)
* chore: 🤖 move loading-button component to core addon

* style: toolbar buttons should align with Structure

* fix: buttons should have consistent font
2022-04-28 17:59:43 -04:00
Randall Morey 043dbc3736 chore: 🤖 move loading-button component to core addon (#1083) 2022-04-28 17:49:03 -04:00
Cameron Perera 01e4ec0a07 feat: 🎸 Add minimum refresh time to refresh button for sessions (#1077) 2022-04-28 16:35:46 -04:00
Randall Morey a7b3da2231 feat: 🎸 implement live relative datetime component (#1080) 2022-04-28 16:23:44 -04:00
Randall Morey de6416efbd feat: 🎸 add non-interactive rose toolbar info component (#1075) 2022-04-28 16:01:50 -04:00
76befc0c1d chore: 🤖 Increaase polling time desktop client (#1074)
Increase polling time within desktop client.

Co-authored-by: Dharini Jeeva <dharini@hashicorp.com>
Co-authored-by: Randall Morey <randall@randallmorey.com>
2022-04-28 15:48:33 -04:00
Carlos Alcaide Corvo f71d01902a Revert "feat: 🎸 Add feature editions (#1072)" (#1079)
This reverts commit 56d84d652b.
2022-04-28 12:14:27 -07:00
Carlos Alcaide Corvo 56d84d652b feat: 🎸 Add feature editions (#1072)
Add feature editions
2022-04-28 10:23:35 -07:00
Dharini Jeeva 9cf216179a feat: refresh sessions list view in desktop (#1069)
* feat: 🎸 add a refresh button to sessions list view in desktop
2022-04-28 08:49:37 -07:00
Zed 050cfdd056 fix: 🐛 Fix scrollbars not being dark in dark mode (#1068)
✅ Closes: ICU-4022
2022-04-27 18:18:24 -04:00
Carlos Alcaide Corvo 79fb0db882 docs: ✏️ Update node supported versions (#1071)
Update node supported versions
2022-04-26 17:06:10 -07:00
Cameron Perera a2c6bc643d chore: 🤖 Update the .template-lintrc.js file in addons/rose (#1073)
✅ Closes: ICU-4123
2022-04-26 14:56:13 -05:00
Zed 07ed40ce03 fix: 🐛 Adjusted dark mode gray scale and fixed radio card colors (#1065)
Adjusted dark mode gray scale to be a bit darker and 
made the active selected radio card lighter in dark mode

✅ Closes: ICU-4021
2022-04-26 11:28:02 -04:00
Cameron Perera e0cbbefb41 fix: 🐛 Fix new target navigation issue (#1070)
Fix issue where trying to leave the new target form via the discard
changes dialog would cause the user to have to refresh screen.

✅ Closes: ICU-4047
2022-04-26 08:21:11 -05:00
Carlos Alcaide Corvo 2a1e4858fa chore: 🤖 Update Electron from 12.x to 13.x (#1063) 2022-04-21 12:46:41 -07:00
Cameron Perera 7b154b223a feat: 🎸 Update Target types help text (#1064)
* feat: 🎸 Update Target types help text

✅ Closes: ICU-4014

* refactor: 💡 Update how radio cards determine height

Radio cards will now fill up the entire height of the fieldset they are
in

* style: 💄 Update radio card padding
2022-04-21 13:51:47 -05:00
Carlos Alcaide Corvo 550cadf612 Revert "fix: 🐛 Disable polling for sessions on Desktop (#1058)" (#1062)
This reverts commit 26e074dbef.
2022-04-19 13:22:47 -07:00
Carlos Alcaide Corvo 95cece1481 Revert "fix: 🐛 Disable polling for targets on Desktop (#1059)" (#1061)
This reverts commit 6249e945b8.
2022-04-19 13:06:42 -07:00
Carlos Alcaide Corvo 94a3c1fcf1 Revert "disable polling in admin UI (#1057)" (#1060)
This reverts commit 90c9fa8b73.
2022-04-19 12:51:03 -07:00
Cameron PereraandDharini Jeeva f2b53d2f45 chore: 🤖 Updated pr-template to include Jira base url (#1055)
Co-authored-by: Dharini Jeeva <dharini@hashicorp.com>
2022-04-19 09:35:14 -05:00
Cameron Perera 6249e945b8 fix: 🐛 Disable polling for targets on Desktop (#1059)
✅ Closes: ICU-3954
2022-04-19 09:22:13 -05:00
Cameron Perera 26e074dbef fix: 🐛 Disable polling for sessions on Desktop (#1058)
✅ Closes: ICU-3953
2022-04-19 09:10:09 -05:00
Dharini Jeeva 90c9fa8b73 disable polling in admin UI (#1057)
* fix: 🐛 disable sessions polling

* increase sessions count

* fix: 🐛 undo mirage test
2022-04-18 18:08:23 -04:00
Zed 215bf00407 test: 💍 Verify target worker filter is created correctly (#1056)
✅ Closes: ICU-3893
2022-04-15 16:00:03 -04:00
Cameron Perera d8efefc2b3 test: 💍 Verify target worker filter can be edited (#1054)
✅ Closes: ICU-3892
2022-04-15 13:52:31 -05:00
Cameron Perera 95ed2c0fda feat: 🎸 Add worker filter field in target form (#1053)
* feat: 🎸 Add worker filter field in target form

✅ Closes: ICU-3891

* feat: 🎸 Add Learn More link to Worker Filter input field
2022-04-14 15:27:36 -05:00
Carlos Alcaide Corvo 8776b46277 Chore update eslint (#1045)
Update eslint and eslint-plugin-ember to their latest versions.
2022-04-13 14:17:46 -07:00
Zed 670f38df74 feat: 🎸 Add mirage data for the worker_filter (#1051)
* feat: 🎸 Add mirage data for the "worker_filter" attribute

✅ Closes: ICU-3888
2022-04-12 17:42:13 -04:00
Cameron PereraandDharini Jeeva 226475a47d feat: 🎸 Add "worker_filter" attribute to target model (#1049)
* feat: 🎸 Add "worker_filter" attribute to target model

✅ Closes: ICU-3887

* feat: 🎸 Add missing attribute description for worker_filter

* feat: 🎸 Update worker_filter description

Co-authored-by: Dharini Jeeva <dharini@hashicorp.com>
2022-04-12 16:16:51 -05:00
Dharini Jeeva 1072be1eff refactor: 💡 improve target creation (#1050)
* refactor: 💡 improve target creation UX
2022-04-12 14:05:16 -07:00
Carlos Alcaide Corvo 22d8af72ae Feat add build admin UI workflow (#1048)
* chore: 🤖 Add build admin UI workflow
2022-04-08 14:57:20 -07:00
Cameron Perera 79596010e9 feat: 🎸 Update Success Dialog when connecting to target (#1046)
Updated the Success Dialog in desktop app when connecting to a target to
dynamically show target type

✅ Closes: ICU-3647
2022-04-08 14:15:32 -05:00
Carlos Alcaide Corvo 8e884d53ae Revert "chore: 🤖 Add build admin UI workflow (#1043)" (#1047)
This reverts commit 505820eb6c.
2022-04-08 09:06:22 -07:00
Carlos Alcaide Corvo 505820eb6c chore: 🤖 Add build admin UI workflow (#1043)
* chore: 🤖 Add build admin UI workflow
2022-04-08 08:41:48 -07:00
Carlos Alcaide Corvo 4b09c7014b Chore update babel parser (#1044)
Update babel-parser and dependencies.
2022-04-07 14:39:59 -07:00
Cameron Perera f4535c8307 test: 💍 Add tests specific to SSH target creation
* test: 💍 Add tests specific to SSH target creation

* test: 💍 creating new SSH target when enabled or disabled

Verifying the link to create new SSH targets is not present when
ssh-targets is not enabled

* refactor: update create targets acceptance test names
2022-04-06 09:30:49 -05:00
Dharini Jeeva 9fae8f2a9f feat: create ssh type target in admin-ui (#1027)
* feat: 🎸 create ssh type target in admin-UI
2022-03-31 15:34:24 -07:00
Carlos Alcaide Corvo a7bcc0c332 chore: 🤖 Update plist version on desktop (#1040)
Update plist version resolutions on desktop as per dependabot alert.
2022-03-31 10:40:57 -07:00
Dharini Jeeva f877477cd7 feat: 🎸 update target route to support ssh type (#1038)
* feat: 🎸 update target route to support ssh type
2022-03-31 09:50:03 -07:00
Carlos Alcaide Corvo 335df22a38 chore: 🤖 Update plist on admin resolutions (#1039)
Update plist version on admin resolutions as per dependabot alert.
2022-03-31 09:06:34 -07:00
Carlos Alcaide Corvo ca09b538f7 chore: 🤖 Add minimist to desktop resolutions (#1034)
Add minimist to desktop resolutions as per dependabot alert.
2022-03-28 14:10:33 -07:00
Carlos Alcaide Corvo 68ba653984 chore: 🤖 Add minimist to admin resolutions (#1032)
Add minimist to admin resolutions
2022-03-28 13:47:32 -07:00
Michele Degges 5a90533a2e [RelAPI Onboarding] Add release API metadata file (#1031) 2022-03-24 13:52:26 -07:00
Carlos Alcaide Corvo 3d7b8537e1 chore: 🤖 Resolutions ansi-html (#1030)
Add ansi-html to resolutions
2022-03-22 07:23:11 -07:00
Carlos Alcaide Corvo 8d6669c8a1 chore: 🤖 Update git-cz (#1029)
Update git-cz
2022-03-18 14:12:35 -07:00
Dharini Jeeva 7c3f57c7fa chore: display sync interval seconds on host-set plugin forms (#1014)
* chore: 🤖 display sync_interval_seconds toggle on the forms

* chore: 🤖 remove comment

* chore: 🤖 remove extra spacing

* fix: 🐛 update title and add a description for sync_interval

* fix: 🐛 lint in translation

* chore: 🤖 fix typo, remove duplicate code

* chore: 🤖 simplify sync interval field, remove toggling

* fix: 🐛 use correct error code

* fix: 🐛 move sync interval translation to forms

* fix: 🐛 use appropiate translations label
2022-03-17 13:49:18 -07:00
Cameron Perera 2543d14c5a Chore: Add a PR template file (#1028)
* chore: 🤖 Add a PR template file

* chore: 🤖 update pr template

* chore: 🤖 final pr template update

* Update .github/pull_request_template.md

Move JIRA ticket link to the top
2022-03-17 14:00:44 -05:00
Carlos Alcaide Corvo fe7cb014a0 feat: 🎸 Add default custom Model for mirage (#1013)
* feat: 🎸 Add default custom Model for mirage
2022-03-17 11:05:41 -07:00
Carlos Alcaide Corvo adcfb00131 chore: 🤖 Bump binary version and update changelog (#1026)
Bump binary version and update changelog.
2022-03-16 14:41:41 -07:00
292 changed files with 6550 additions and 3138 deletions

No files matched your search

+2
View File
@@ -0,0 +1,2 @@
# Anyone attached to this rule will always been assigned to a pull request
* @hashicorp/boundary-ui
+17
View File
@@ -0,0 +1,17 @@
:tickets: [Jira ticket](https://hashicorp.atlassian.net/browse/JIRA_TICKET_NUMBER)
## Description
<!--
Replace PATH_TO_FEATURE with Vercel link
-->
:technologist: [Admin preview](PATH_TO_FEATURE)
:rose: [Rose preview](PATH_TO_FEATURE)
:desktop_computer: [Desktop preview](PATH_TO_FEATURE)
<!-- Add a brief description of changes here. Include any other necessary relevant links -->
### Screenshots (if appropriate):
+76
View File
@@ -0,0 +1,76 @@
name: Build Admin UI
on:
push:
branches:
- main
jobs:
dependencies:
name: Install dependencies
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions/cache@v3
id: node-modules-cache
with:
path: '**/node_modules'
key: node-modules-${{ hashFiles('**/yarn.lock') }}
restore-keys: |
node-modules-
- uses: actions/setup-node@v3
with:
node-version: '16.x'
- run: yarn install
build-admin-ui-oss:
name: Build Admin UI OSS
needs: [dependencies]
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions/cache@v3
id: node-modules-cache
with:
path: '**/node_modules'
key: node-modules-${{ hashFiles('**/yarn.lock') }}
restore-keys: |
node-modules-
- name: Build
uses: actions/setup-node@v3
with:
node-version: '16.x'
if: steps.node-modules-cache.outputs.cache-hit != 'true'
- run: yarn run build:ui:admin:oss
- name: Upload artifact admin-ui
uses: actions/upload-artifact@v3
with:
name: admin-ui
path: ./ui/admin/dist/
- name: Upload artifact Admin UI OSS
uses: actions/upload-artifact@v3
with:
name: admin-ui-oss
path: ./ui/admin/dist/
build-admin-ui-enterprise:
name: Build Admin UI Enterprise
needs: [dependencies]
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions/cache@v3
id: node-modules-cache
with:
path: '**/node_modules'
key: node-modules-${{ hashFiles('**/yarn.lock') }}
restore-keys: |
node-modules-
- name: Build
uses: actions/setup-node@v3
with:
node-version: '16.x'
if: steps.node-modules-cache.outputs.cache-hit != 'true'
- run: yarn run build:ui:admin:enterprise
- name: Upload artifact Admin UI Enterprise
uses: actions/upload-artifact@v3
with:
name: admin-ui-ent
path: ./ui/admin/dist/
+14 -14
View File
@@ -6,15 +6,15 @@ jobs:
name: Install dependencies
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: actions/cache@v2
- uses: actions/checkout@v3
- uses: actions/cache@v3
id: node-modules-cache
with:
path: '**/node_modules'
key: node-modules-${{ hashFiles('**/yarn.lock') }}
restore-keys: |
node-modules-
- uses: actions/setup-node@v2
- uses: actions/setup-node@v3
with:
node-version: '16.x'
- run: yarn install
@@ -24,15 +24,15 @@ jobs:
needs: [dependencies]
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: actions/cache@v2
- uses: actions/checkout@v3
- uses: actions/cache@v3
id: node-modules-cache
with:
path: '**/node_modules'
key: node-modules-${{ hashFiles('**/yarn.lock') }}
restore-keys: |
node-modules-
- uses: actions/setup-node@v2
- uses: actions/setup-node@v3
with:
node-version: '16.x'
if: steps.node-modules-cache.outputs.cache-hit != 'true'
@@ -40,19 +40,19 @@ jobs:
lint:
name: Lint
needs: [dependencies]
needs: [dependencies, compliance]
runs-on: ubuntu-latest
timeout-minutes: 5
steps:
- uses: actions/checkout@v2
- uses: actions/cache@v2
- uses: actions/checkout@v3
- uses: actions/cache@v3
id: node-modules-cache
with:
path: '**/node_modules'
key: node-modules-${{ hashFiles('**/yarn.lock') }}
restore-keys: |
node-modules-
- uses: actions/setup-node@v2
- uses: actions/setup-node@v3
with:
node-version: '16.x'
if: steps.node-modules-cache.outputs.cache-hit != 'true'
@@ -60,17 +60,17 @@ jobs:
test:
name: Test
needs: [dependencies]
needs: [lint]
runs-on: ubuntu-latest
timeout-minutes: 15
steps:
- uses: actions/checkout@v2
- uses: actions/cache@v2
- uses: actions/checkout@v3
- uses: actions/cache@v3
id: node-modules-cache
with:
path: '**/node_modules'
key: node-modules-${{ hashFiles('**/yarn.lock') }}
- uses: actions/setup-node@v2
- uses: actions/setup-node@v3
with:
node-version: '16.x'
if: steps.node-modules-cache.outputs.cache-hit != 'true'
+6
View File
@@ -0,0 +1,6 @@
#!/usr/bin/env sh
. "$(dirname -- "$0")/_/husky.sh"
yarn compliance:licenses
npx lint-staged
yarn test
+5
View File
@@ -0,0 +1,5 @@
#!/usr/bin/env sh
. "$(dirname -- "$0")/_/husky.sh"
# This is to allow interaction with the terminal for commitizen
exec < /dev/tty && npx git-cz --hook || true
+3
View File
@@ -0,0 +1,3 @@
url_license = "https://github.com/hashicorp/boundary-ui/blob/main/LICENSE"
url_project_website = "https://learn.hashicorp.com/tutorials/boundary/getting-started-desktop-app"
url_source_repository = "https://github.com/hashicorp/boundary-ui"
+8 -8
View File
@@ -38,9 +38,9 @@ You will need the following things properly installed on your computer.
* [Git][git]
* [Node.js][node]
* v10–v15
* Supported versions:`v12`, `v14` and `v16`.
* **Apple Silicon Users**: if you experience problems building or running
Boundary UIs, try Node v15.
Boundary UIs, try Node v14.
* [Yarn][yarn] installed globally
* [Google Chrome][chrome]
* [Firefox][firefox]
@@ -66,7 +66,6 @@ List of available project commands. `yarn run <command-name>`
|---------------------|---|
| build | Builds Admin UI. |
| test | Runs tests in CI mode. |
| commit | Replaces `git commit`, ensures compliance, audit, lint, and test checks pass before commit is allowed and normalizes commit messages across authors. |
| lint | Runs ember-template-lint on all of the hbs, js, and sass files. |
| compliance:audit | Checks for issues using `yarn audit` with moderate and above criticality.|
| compliance:licenses | Checks that all dependencies have OSS-compatible licenses. |
@@ -164,11 +163,12 @@ Enter the origin of your Boundary dev instance, by default is: `http://localhost
### Committing
Instead of the default `git commit`, we prescribe a custom command that ensures
linting and other checks pass before a commit may be completed. It also ensures
that all contributors author consistent commit messages. To get started with a
commit, stage your files as usual. Then run `yarn commit` and follow the
on-screen instructions to author your message.
We use `husky` and `lint-staged` to ensure linting and other checks pass before a
commit is completed. Simply do a `yarn install` to make sure the hooks are installed.
Use a normal `git commit` to go through the checks, if you need to skip these checks,
use `git commit --no-verify` to bypass them. However, a consistent commit message will
still be enforced even if you use `--no-verify`.
#### License Checking
+7 -8
View File
@@ -2,20 +2,19 @@
module.exports = {
root: true,
parser: 'babel-eslint',
parser: '@babel/eslint-parser',
parserOptions: {
ecmaVersion: 2018,
sourceType: 'module',
ecmaFeatures: {
legacyDecorators: true,
// This is specific babel-config. If grows consider creating a babel config file
requireConfigFile: false,
babelOptions: {
plugins: [['@babel/plugin-proposal-decorators', { legacy: true }]],
},
// end of babel-config
},
plugins: ['ember'],
extends: [
'eslint:recommended',
'plugin:ember/recommended',
'plugin:prettier/recommended',
],
extends: ['eslint:recommended', 'plugin:ember/recommended', 'prettier'],
env: {
browser: true,
},
+9 -2
View File
@@ -47,21 +47,28 @@ List of available project commands. `yarn run <command-name>`
| build:development | Builds the dummy app in development mode. |
| build | Builds the dummy app for production. |
| lint | Runs all lint commands. |
| lint:fix | Runs automatic lint fixes for all type of file. |
| lint:hbs | Runs lint for `hbs` template files. |
| lint:hbs:fix | Runs automatic lint fixes for `hbs` template files. |
| lint:js | Lints `js` files. |
| lint:js:fix | Runs automatic lint fixes for `js` files. |
| format | Runs all auto-formatters. |
| format:js | Auto-formats `js` files using Prettier. |
| start | Runs the dummy app local server. |
| test | Runs all tests. |
| test:all | Runs tests across multiple Ember versions with ember-try. |
| test:ember-compatibility | Runs tests across multiple Ember versions with ember-try. |
| precommit | Runs all lint and format. |
| doc:toc | Automatically generates a table of contents for this README file. |
Additional commands in the monorepo package may affect this projects.
## Linting
* `yarn lint:fix`
* `yarn lint:hbs`
* `yarn lint:hbs:fix`
* `yarn lint:js`
* `yarn lint:js --fix`
* `yarn lint:js:fix`
## Formatting
@@ -0,0 +1,16 @@
import ModelAbility from './model';
/**
* Provides abilities for credential store.
*/
export default class CredentialStoreAbility extends ModelAbility {
// =permissions
/**
* Only "known" credential store types may be read.
* @type {boolean}
*/
get canRead() {
return !this.model.isStatic && this.hasAuthorizedAction('read');
}
}
@@ -43,4 +43,20 @@ export default class GeneratedAccountModel extends BaseModel {
description: 'Current version number of this resource.',
})
version;
// =attributes (password)
@attr('string', {
for: 'password',
isNestedAttribute: true,
description: 'The account login name',
})
login_name;
// =attributes (OIDC)
@attr('string', { for: 'oidc', isNestedAttribute: true }) subject;
@attr('string', { for: 'oidc', isNestedAttribute: true }) issuer;
@attr('string', { for: 'oidc', isNestedAttribute: true, readOnly: true })
email;
@attr('string', { for: 'oidc', isNestedAttribute: true, readOnly: true })
full_name;
}
@@ -44,4 +44,27 @@ export default class GeneratedCredentialLibraryModel extends BaseModel {
description: 'Current version number of this resource.',
})
version;
//= attributes (vault)
@attr('string', {
isNestedAttribute: true,
description:
'The HTTP method the library uses when requesting credentials from Vault.',
defaultValue: () => 'GET',
})
http_method;
@attr('string', {
isNestedAttribute: true,
description:
'The body of the HTTP request the library sends to Vault when requesting credentials. Only valid if `http_method` is set to `POST`.',
})
http_request_body;
@attr('string', {
isNestedAttribute: true,
description: 'The path in Vault to request credentials from.',
})
path;
}
@@ -39,4 +39,82 @@ export default class GeneratedCredentialStoreModel extends BaseModel {
description: 'Current version number of this resource.',
})
version;
// =attributes (vault)
@attr('string', {
for: 'vault',
isNestedAttribute: true,
description:
"The address to Vault server. This should be a complete URL such as 'https://127.0.0.1:8200'",
})
address;
@attr('string', {
for: 'vault',
isNestedAttribute: true,
description: 'The namespace within Vault to use.',
})
namespace;
@attr('string', {
for: 'vault',
isNestedAttribute: true,
description:
"A PEM-encoded CA certificate to verify the Vault server's TLS certificate.",
})
ca_cert;
@attr('string', {
for: 'vault',
isNestedAttribute: true,
description:
'Name to use as the SNI host when connecting to Vault via TLS.',
})
tls_server_name;
@attr('boolean', {
for: 'vault',
isNestedAttribute: true,
description: 'Whether or not to skip TLS verification.',
})
tls_skip_verify;
@attr('string', {
for: 'vault',
isNestedAttribute: true,
description: 'A token used for accessing Vault.',
})
token;
@attr('string', {
for: 'vault',
isNestedAttribute: true,
description: 'The Vault token hmac.',
readOnly: true,
})
token_hmac;
@attr('string', {
for: 'vault',
isNestedAttribute: true,
description:
'A PEM-encoded client certificate to use for TLS authentication to the Vault server.',
})
client_certificate;
@attr('string', {
for: 'vault',
isNestedAttribute: true,
description:
"A PEM-encoded private key matching the client certificate from 'client_certificate'.",
})
client_certificate_key;
@attr('string', {
for: 'vault',
isNestedAttribute: true,
description: 'The Vault client certificate key hmac.',
readOnly: true,
})
client_certificate_key_hmac;
}
@@ -44,4 +44,13 @@ export default class GeneratedManagedGroupModel extends BaseModel {
'The ID of the Auth Method that is associated with this ManagedGroup',
})
auth_method_id;
// =attributes (OIDC)
@attr('string', {
isNestedAttribute: true,
description:
'The boolean expression filter to use to determine membership.',
})
filter;
}
@@ -34,6 +34,12 @@ export default class GeneratedTargetModel extends BaseModel {
})
session_connection_limit;
@attr('string', {
description:
'Optional boolean expression to filter the workers that are allowed to satisfy this request.',
})
worker_filter;
@attr('date', {
description: 'The time this resource was created\nOutput only.',
readOnly: true,
+2 -9
View File
@@ -1,17 +1,10 @@
import GeneratedAccountModel from '../generated/models/account';
import { fragment } from 'ember-data-model-fragments/attributes';
import { computed } from '@ember/object';
import { equal } from '@ember/object/computed';
export default class AccountModel extends GeneratedAccountModel {
// =attributes
/**
* Attributes of this resource, if any, represented as a JSON fragment.
* @type {FragmentAccountAttributesModel}
*/
@fragment('fragment-account-attributes', { defaultValue: {} }) attributes;
/**
* @type {boolean}
*/
@@ -26,9 +19,9 @@ export default class AccountModel extends GeneratedAccountModel {
* Convenience for getting username in account.
* @type {string}
*/
@computed('attributes.{email,full_name,login_name}')
@computed('{email,full_name,login_name}')
get accountName() {
const { email, full_name, login_name } = this.attributes;
const { email, full_name, login_name } = this;
return email || full_name || login_name;
}
+1 -21
View File
@@ -1,6 +1,4 @@
import GeneratedCredentialLibraryModel from '../generated/models/credential-library';
import { attr } from '@ember-data/model';
import { fragment } from 'ember-data-model-fragments/attributes';
/**
* Enum options for credential library.
@@ -9,22 +7,4 @@ export const options = {
http_method: ['GET', 'POST'],
};
export default class CredentialLibraryModel extends GeneratedCredentialLibraryModel {
// =error attributes
// These attributes exist solely to capture errors on nested fields.
// See the application adapter's error normalization method for
// more information.
@attr('string', { readOnly: true }) attributes_http_method;
@attr('string', { readOnly: true }) attributes_http_request_body;
@attr('string', { readOnly: true }) attributes_path;
// =attributes
/**
* Attributes of this resource, if any, represented as a JSON fragment.
* @type {FragmentCredentialLibraryAttributesModel}
*/
@fragment('fragment-credential-library-attributes', { defaultValue: {} })
attributes;
}
export default class CredentialLibraryModel extends GeneratedCredentialLibraryModel {}
+5 -23
View File
@@ -1,34 +1,16 @@
import GeneratedCredentialStoreModel from '../generated/models/credential-store';
import { attr } from '@ember-data/model';
import { fragment } from 'ember-data-model-fragments/attributes';
import { equal } from '@ember/object/computed';
export default class CredentialStoreModel extends GeneratedCredentialStoreModel {
// =error attributes
// These attributes exist solely to capture errors on nested fields.
// See the application adapter's error normalization method for
// more information.
@attr('string', { readOnly: true }) attributes_address;
@attr('string', { readOnly: true }) attributes_namespace;
@attr('string', { readOnly: true }) attributes_ca_cert;
@attr('string', { readOnly: true }) attributes_tls_server_name;
@attr('string', { readOnly: true }) attributes_tls_skip_verify;
@attr('string', { readOnly: true }) attributes_token;
@attr('string', { readOnly: true }) attributes_client_certificate;
@attr('string', { readOnly: true }) attributes_client_certificate_key;
// =attributes
/**
* Attributes of this resource, if any, represented as a JSON fragment.
* @type {FragmentAuthMethodAttributesModel}
*/
@fragment('fragment-credential-store-attributes', { defaultValue: {} })
attributes;
/**
* @type {boolean}
*/
@equal('type', 'vault') isVault;
/**
* @type {boolean}
*/
@equal('type', 'static') isStatic;
}
@@ -1,17 +0,0 @@
import Fragment from 'ember-data-model-fragments/fragment';
import { attr } from '@ember-data/model';
export default class FragmentAccountAttributesModel extends Fragment {
// =attributes (password)
@attr('string', {
for: 'password',
description: 'The account login name',
})
login_name;
// =attributes (OIDC)
@attr('string', { for: 'oidc' }) subject;
@attr('string', { for: 'oidc' }) issuer;
@attr('string', { for: 'oidc', readOnly: true }) email;
@attr('string', { for: 'oidc', readOnly: true }) full_name;
}
@@ -1,25 +0,0 @@
import Fragment from 'ember-data-model-fragments/fragment';
import { attr } from '@ember-data/model';
import { options } from './credential-library';
export default class FragmentCredentialLibraryAttributesModel extends Fragment {
//= attributes (vault)
@attr('string', {
description:
'The HTTP method the library uses when requesting credentials from Vault.',
defaultValue: () => options.http_method[0],
})
http_method;
@attr('string', {
description:
'The body of the HTTP request the library sends to Vault when requesting credentials. Only valid if `http_method` is set to `POST`.',
})
http_request_body;
@attr('string', {
description: 'The path in Vault to request credentials from.',
})
path;
}
@@ -1,72 +0,0 @@
import Fragment from 'ember-data-model-fragments/fragment';
import { attr } from '@ember-data/model';
export default class FragmentCredentialStoreAttributesModel extends Fragment {
// =attributes (vault)
@attr('string', {
for: 'vault',
description:
"The address to Vault server. This should be a complete URL such as 'https://127.0.0.1:8200'",
})
address;
@attr('string', {
for: 'vault',
description: 'The namespace within Vault to use.',
})
namespace;
@attr('string', {
for: 'vault',
description:
"A PEM-encoded CA certificate to verify the Vault server's TLS certificate.",
})
ca_cert;
@attr('string', {
for: 'vault',
description:
'Name to use as the SNI host when connecting to Vault via TLS.',
})
tls_server_name;
@attr('boolean', {
for: 'vault',
description: 'Whether or not to skip TLS verification.',
})
tls_skip_verify;
@attr('string', {
for: 'vault',
description: 'A token used for accessing Vault.',
})
token;
@attr('string', {
for: 'vault',
description: 'The Vault token hmac.',
readOnly: true,
})
token_hmac;
@attr('string', {
for: 'vault',
description:
'A PEM-encoded client certificate to use for TLS authentication to the Vault server.',
})
client_certificate;
@attr('string', {
for: 'vault',
description:
"A PEM-encoded private key matching the client certificate from 'client_certificate'.",
})
client_certificate_key;
@attr('string', {
for: 'vault',
description: 'The Vault client certificate key hmac.',
readOnly: true,
})
client_certificate_key_hmac;
}
@@ -1,12 +0,0 @@
import Fragment from 'ember-data-model-fragments/fragment';
import { attr } from '@ember-data/model';
export default class FragmentManagedGroupAttributesModel extends Fragment {
// =attributes (OIDC)
@attr('string', {
description:
'The boolean expression filter to use to determine membership.',
})
filter;
}
-11
View File
@@ -1,18 +1,10 @@
import GeneratedManagedGroupModel from '../generated/models/managed-group';
import { attr } from '@ember-data/model';
import { fragment } from 'ember-data-model-fragments/attributes';
import { A } from '@ember/array';
export default class ManagedGroupModel extends GeneratedManagedGroupModel {
// =attributes
// =error attributes
// These attributes exist solely to capture errors on nested fields.
// See the application adapter's error normalization method for
// more information.
@attr('string', { readOnly: true }) attributes_filter;
/**
* Members is read-only under normal circumstances. But members can
* be persisted via calls to `addMembers()` or `removeMembers()`.
@@ -23,7 +15,4 @@ export default class ManagedGroupModel extends GeneratedManagedGroupModel {
emptyArrayIfMissing: true,
})
member_ids;
@fragment('fragment-managed-group-attributes', { defaultValue: {} })
attributes;
}
+7
View File
@@ -23,6 +23,13 @@ export default class RoleModel extends GeneratedRoleModel {
*/
@array('string', { readOnly: true }) grant_strings;
/**
* Convenience for looking up the grant scope, if loaded.
*/
get grantScope() {
return this.store.peekRecord('scope', this.grant_scope_id);
}
// =methods
/**
+4 -4
View File
@@ -13,7 +13,7 @@ class SessionCredential {
/**
*
*/
static Library = class Library {
static Source = class Source {
id;
name;
description;
@@ -42,7 +42,7 @@ class SessionCredential {
// =attributes
rawCredential;
library;
source;
#payloadSecret;
/**
@@ -72,8 +72,8 @@ class SessionCredential {
// =methods
constructor(cred) {
const { id, name, description, type } = cred.credential_library;
this.library = new SessionCredential.Library(id, name, description, type);
const { id, name, description, type } = cred.credential_source;
this.source = new SessionCredential.Source(id, name, description, type);
this.#payloadSecret = cred.secret;
this.rawCredential = cred;
}
+1 -1
View File
@@ -40,7 +40,7 @@ export default class UserModel extends GeneratedUserModel {
* There are many options, so we fallback in order of precedence.
* @type {string}
*/
@computed('email,full_name,login_name,displayName')
@computed('email', 'full_name', 'login_name')
get accountName() {
const { email, full_name, login_name } = this;
return email || full_name || login_name;
+3 -3
View File
@@ -33,12 +33,12 @@ export default class AccountSerializer extends ApplicationSerializer {
* `attributes` entirely on update.
*/
serializeOIDC(snapshot) {
const { isNew } = snapshot?.record;
const { isNew } = snapshot?.record || {};
let serialized = super.serialize(...arguments);
delete serialized.attributes;
if (isNew) {
serialized.attributes = {};
const { issuer, subject } = snapshot.attr('attributes').record;
const { issuer, subject } = snapshot.record;
if (issuer) serialized.attributes.issuer = issuer;
if (subject) serialized.attributes.subject = subject;
}
@@ -70,7 +70,7 @@ export default class AccountSerializer extends ApplicationSerializer {
}
// Change password custom method
if (snapshot?.adapterOptions?.method === 'change-password') {
const { currentPassword, newPassword } = snapshot?.adapterOptions;
const { currentPassword, newPassword } = snapshot?.adapterOptions || {};
serialized = this.serializeForChangePassword(
snapshot,
currentPassword,
+45 -1
View File
@@ -137,7 +137,7 @@ export default class ApplicationSerializer extends RESTSerializer {
}
/**
* In our API, singluar resources are _unrooted_, whereas Ember Data expects
* In our API, singular resources are _unrooted_, whereas Ember Data expects
* them to be rooted under their model name, e.g. `{modelName: {…}}`.
* This method makes this transformation to accommodate Ember Data.
*
@@ -268,4 +268,48 @@ export default class ApplicationSerializer extends RESTSerializer {
});
return hash;
}
/**
* If the API returns an updated response with removed fields, we need to
* explicitly set any read only field that is on the model but wasn't
* returned in the response to `null`.
* This will let ember data know the field was removed, otherwise
* it won't touch the removed field and will use the old value.
*
* @override
* @param {object} store
* @param {object} primaryModelClass
* @param {object} payload
* @param {?string} id
* @param {string} requestType
* @return {object}
*/
normalizeUpdateRecordResponse(
store,
primaryModelClass,
payload,
id,
requestType
) {
const newPayload = copy(payload, true);
primaryModelClass.attributes.forEach((attribute) => {
const {
name,
options: { readOnly },
} = attribute;
if (readOnly && !Object.prototype.hasOwnProperty.call(newPayload, name)) {
newPayload[name] = null;
}
});
return super.normalizeUpdateRecordResponse(
store,
primaryModelClass,
newPayload,
id,
requestType
);
}
}
@@ -1,3 +1,18 @@
import ApplicationSerializer from './application';
export default class CredentialLibrarySerializer extends ApplicationSerializer {}
export default class CredentialLibrarySerializer extends ApplicationSerializer {
/**
* @override
* @method serialize
* @param {Snapshot} snapshot
*/
serialize() {
const serialized = super.serialize(...arguments);
if (serialized.attributes) {
// Serialize `http_request_body` only if `http_method` is POST
if (!serialized.attributes?.http_method?.match(/post/i))
delete serialized.attributes.http_request_body;
}
return serialized;
}
}
@@ -1,3 +1,24 @@
import ApplicationSerializer from './application';
export default class CredentialStoreSerializer extends ApplicationSerializer {}
export default class CredentialStoreSerializer extends ApplicationSerializer {
/**
* @override
* @method serialize
* @param {Snapshot} snapshot
*/
serialize() {
const serialized = super.serialize(...arguments);
if (serialized.attributes) {
// Token cannot be unset. If it's falsy, it must be removed.
if (!serialized.attributes?.token) delete serialized.attributes.token;
// Client certificate key cannot be unset when certificate is set.
// If it's falsy, it must be removed.
if (
!serialized.attributes?.client_certificate_key &&
serialized.attributes?.client_certificate
)
delete serialized.attributes.client_certificate_key;
}
return serialized;
}
}
@@ -1,26 +0,0 @@
import JSONSerializer from '@ember-data/serializer/json';
export default class FragmentAccountAttributesSerializer extends JSONSerializer {
/**
* If an attribute is annotated as readOnly in the model, don't serialize it.
* Otherwise delegate to default attribute serializer.
*
* @override
* @method serializeAttribute
* @param {Snapshot} snapshot
* @param {Object} json
* @param {String} key
* @param {Object} attribute
*/
serializeAttribute(snapshot, json, key, attribute) {
const { type, options } = attribute;
let value = super.serializeAttribute(...arguments);
// Convert empty strings to null.
if (type === 'string' && json[key] === '') json[key] = null;
// Do not serialize read-only attributes.
if (options.readOnly) delete json[key];
// Client secret cannot be unset. If it's falsy, it must be removed.
if (key === 'client_secret' && !json[key]) delete json[key];
return value;
}
}
@@ -1,27 +0,0 @@
import JSONSerializer from '@ember-data/serializer/json';
export default class FragmentCredentialLibraryAttributesSerializer extends JSONSerializer {
/**
* If an attribute is annotated as readOnly in the model, don't serialize it.
* Otherwise delegate to default attribute serializer.
* Only serialize http_request_body when `http_method` is set to `POST`.
* @override
* @method serializeAttribute
* @param {Snapshot} snapshot
* @param {Object} json
* @param {String} key
* @param {Object} attribute
*/
serializeAttribute(snapshot, json, key, attribute) {
const { type, options } = attribute;
let value = super.serializeAttribute(...arguments);
// Convert empty strings to null.
if (type === 'string' && json[key] === '') json[key] = null;
// Do not serialize read-only attributes.
if (options.readOnly) delete json[key];
// Do not serialize http_request_body unless http_method is POST
if (key === 'http_request_body' && !json['http_method']?.match(/post/i))
delete json[key];
return value;
}
}
@@ -1,34 +0,0 @@
import JSONSerializer from '@ember-data/serializer/json';
export default class FragmentCredentialStoreAttributesSerializer extends JSONSerializer {
/**
* If an attribute is annotated as readOnly in the model, don't serialize it.
* Otherwise delegate to default attribute serializer.
*
* @override
* @method serializeAttribute
* @param {Snapshot} snapshot
* @param {Object} json
* @param {String} key
* @param {Object} attribute
*/
serializeAttribute(snapshot, json, key, attribute) {
const { type, options } = attribute;
let value = super.serializeAttribute(...arguments);
// Convert empty strings to null.
if (type === 'string' && json[key] === '') json[key] = null;
// Do not serialize read-only attributes.
if (options.readOnly) delete json[key];
// Token cannot be unset. If it's falsy, it must be removed.
if (key === 'token' && !json[key]) delete json[key];
// Client certificate key cannot be unset when certificate is set.
// If it's falsy, it must be removed.
if (
key === 'client_certificate_key' &&
!json[key] &&
json['client_certificate']
)
delete json[key];
return value;
}
}
@@ -1,27 +0,0 @@
import JSONSerializer from '@ember-data/serializer/json';
export default class FragmentManagedGroupAttributesSerializer extends JSONSerializer {
/**
* If an attribute is annotated as readOnly in the model, don't serialize it.
* Otherwise delegate to default attribute serializer.
* @override
* @method serializeAttribute
* @param {Snapshot} snapshot
* @param {Object} json
* @param {String} key
* @param {Object} attribute
*/
serializeAttribute(snapshot, json, key, attribute) {
const { type, options } = attribute;
let value = super.serializeAttribute(...arguments);
// Convert empty string to null.
if (type === 'string' && json[key] === '') json[key] = null;
// Do not serialize read-only attributes.
if (options.readOnly) delete json[key];
// Version is sent only if it has a non-nullish value
if (key === 'version') {
if (json[key] === null || json[key] === undefined) delete json[key];
}
return value;
}
}
@@ -0,0 +1 @@
export { default } from 'api/abilities/credential-store';
@@ -1 +0,0 @@
export { default } from 'api/models/fragment-account-attributes';
@@ -1 +0,0 @@
export { default } from 'api/models/fragment-credential-library-attributes';
@@ -1 +0,0 @@
export { default } from 'api/models/fragment-credential-store-attributes';
@@ -1 +0,0 @@
export { default } from 'api/models/fragment-managed-group-attributes';
@@ -1 +0,0 @@
export { default } from 'api/serializers/fragment-account-attributes';
@@ -1 +0,0 @@
export { default } from 'api/serializers/fragment-credential-library-attributes';
@@ -1 +0,0 @@
export { default } from 'api/serializers/fragment-credential-store-attributes';
@@ -1 +0,0 @@
export { default } from 'api/serializers/fragment-managed-group-attributes';
+4
View File
@@ -1,6 +1,7 @@
import factory from '../generated/factories/account';
import { random, internet } from 'faker';
import permissions from '../helpers/permissions';
import generateId from '../helpers/id';
export default factory.extend({
authorized_actions: () =>
@@ -11,6 +12,9 @@ export default factory.extend({
'delete',
'set-password',
],
id: () => generateId('acct_'),
attributes() {
switch (this.type) {
case 'password':
+3 -1
View File
@@ -1,6 +1,7 @@
import factory from '../generated/factories/auth-method';
import { trait } from 'ember-cli-mirage';
import permissions from '../helpers/permissions';
import generateId from '../helpers/id';
const types = ['password', 'oidc'];
@@ -18,7 +19,8 @@ export default factory.extend({
'managed-groups': ['create', 'list'],
};
},
id: (i) => `auth-method-id-${i}`,
id: () => generateId('am_'),
// Cycle through available types
type: (i) => types[i % types.length],
@@ -1,11 +1,12 @@
import factory from '../generated/factories/credential-library';
import { random, system } from 'faker';
import permissions from '../helpers/permissions';
import generateId from '../helpers/id';
const types = ['vault'];
export default factory.extend({
id: (i) => `credential-library-id-${i}`,
id: () => generateId('cl_'),
type: (i) => types[i % types.length],
authorized_actions: () =>
@@ -2,8 +2,9 @@ import factory from '../generated/factories/credential-store';
import { random, internet, datatype } from 'faker';
import { trait } from 'ember-cli-mirage';
import permissions from '../helpers/permissions';
import generateId from '../helpers/id';
const types = ['vault'];
const types = ['vault', 'static'];
export default factory.extend({
authorized_actions: () =>
@@ -18,7 +19,7 @@ export default factory.extend({
'credential-libraries': ['create', 'list'],
};
},
id: (i) => `credential-store-id-${i}`,
id: () => generateId('cs_'),
type: (i) => types[i % types.length],
attributes() {
+3 -1
View File
@@ -1,6 +1,7 @@
import factory from '../generated/factories/group';
import { trait } from 'ember-cli-mirage';
import permissions from '../helpers/permissions';
import generateId from '../helpers/id';
export default factory.extend({
authorized_actions: () =>
@@ -12,7 +13,8 @@ export default factory.extend({
'add-members',
'remove-members',
],
id: (i) => `group-${i}`,
id: () => generateId('g_'),
/**
* Generates some users for the same scope and assigns them to the group
+2 -1
View File
@@ -2,6 +2,7 @@ import factory from '../generated/factories/host-catalog';
import { trait } from 'ember-cli-mirage';
import permissions from '../helpers/permissions';
import { datatype, address, random } from 'faker';
import generateId from '../helpers/id';
const types = ['static', 'plugin'];
// Represents known plugin types, except "foobar" which models the possibility
@@ -11,7 +12,7 @@ const pluginTypes = ['aws', 'azure', 'foobar'];
let pluginTypeCounter = 1;
export default factory.extend({
id: (i) => `host-catalog-id-${i}`,
id: () => generateId('hc_'),
// Cycle through available types
type: (i) => types[i % types.length],
+2 -1
View File
@@ -1,9 +1,10 @@
import factory from '../generated/factories/host-set';
import permissions from '../helpers/permissions';
import { datatype, internet, database } from 'faker';
import generateId from '../helpers/id';
export default factory.extend({
id: (i) => `host-set-id-${i}`,
id: () => generateId('hs_'),
type() {
return this.hostCatalog?.type || factory.attrs.type;
},
+3 -1
View File
@@ -1,9 +1,11 @@
import factory from '../generated/factories/host';
import permissions from '../helpers/permissions';
import { internet, datatype } from 'faker';
import generateId from '../helpers/id';
export default factory.extend({
id: (i) => `host-id-${i}`,
id: () => generateId('h_'),
type() {
return this.hostCatalog?.type || factory.attrs.type;
},
+3 -1
View File
@@ -1,11 +1,11 @@
import factory from '../generated/factories/managed-group';
import { random } from 'faker';
import permissions from '../helpers/permissions';
import generateId from '../helpers/id';
const types = ['oidc'];
export default factory.extend({
id: (i) => `managed-groups-id-${i}`,
type: (i) => types[i % types.length],
authorized_actions: () =>
@@ -16,6 +16,8 @@ export default factory.extend({
'delete',
],
id: () => generateId('mg_'),
attributes() {
switch (this.type) {
case 'oidc':
+3
View File
@@ -1,6 +1,7 @@
import factory from '../generated/factories/role';
import { trait } from 'ember-cli-mirage';
import permissions from '../helpers/permissions';
import generateId from '../helpers/id';
export default factory.extend({
authorized_actions: () =>
@@ -19,6 +20,8 @@ export default factory.extend({
'id=*;type=host-catalog;actions=create,read',
],
id: () => generateId('r_'),
/**
* Adds principals to the role.
*/
+2 -9
View File
@@ -1,6 +1,7 @@
import factory from '../generated/factories/scope';
import { trait } from 'ember-cli-mirage';
import permissions from '../helpers/permissions';
import generateId from '../helpers/id';
export default factory.extend({
type: 'global',
@@ -27,15 +28,7 @@ export default factory.extend({
};
},
/**
* Generates realistic-ish IDs while still being deterministic.
*/
id(i) {
let id = 'tv6fv3yz8p';
if (i % 3) id = 'xk1i4dk50v';
if (i % 2) id = 's9n819zgko';
return `s_${id}${i}`;
},
id: () => generateId('s_'),
withChildren: trait({
afterCreate(record, server) {
+3 -1
View File
@@ -1,13 +1,15 @@
import factory from '../generated/factories/session';
import { trait } from 'ember-cli-mirage';
import { random } from 'faker';
import generateId from '../helpers/id';
const statusStrings = ['pending', 'active', 'canceling', 'terminated'];
export const pickRandomStatusString = () => random.arrayElement(statusStrings);
export default factory.extend({
id: (i) => `session-id-${i}`,
id: () => generateId('ss_'),
status: pickRandomStatusString,
/**
+4
View File
@@ -2,6 +2,7 @@ import factory from '../generated/factories/target';
import { trait } from 'ember-cli-mirage';
import { random, datatype } from 'faker';
import permissions from '../helpers/permissions';
import generateId from '../helpers/id';
const randomBoolean = (chance = 0.5) => Math.random() < chance;
const hostSetChance = 0.3;
@@ -21,10 +22,13 @@ export default factory.extend({
'remove-credential-sources',
],
id: () => generateId('t_'),
/**
* -1 means "unlimited" and we want to generate these on occasion.
*/
session_connection_limit: () => random.arrayElement([-1, datatype.number()]),
worker_filter: (i) => (i % 2 === 0 ? random.words() : null),
type: (i) => types[i % types.length],
/**
* Generates attributes fields by type.
+2 -1
View File
@@ -1,5 +1,6 @@
import factory from '../generated/factories/user';
import permissions from '../helpers/permissions';
import generateId from '../helpers/id';
export default factory.extend({
authorized_actions: () =>
@@ -11,5 +12,5 @@ export default factory.extend({
'add-accounts',
'remove-accounts',
],
id: (i) => `user-${i}`,
id: () => generateId('u_'),
});
@@ -9,6 +9,7 @@ export default Factory.extend({
name: () => random.words(),
session_max_seconds: () => datatype.number(),
session_connection_limit: () => datatype.number(),
worker_filter: () => random.words(),
description: () => random.words(),
created_time: () => date.recent(),
updated_time: () => date.recent(),
+41
View File
@@ -0,0 +1,41 @@
const characters = 'abcdefghijklmnopqrstuvwxyz0123456789';
/**
* The Mulberry32 PRNG, JavaScript implementation. This is a seedable PRNG,
* which we need in order to deterministically generate IDs which are stable
* across reloads. Unfortunately, the built-in `Math.random` function
* is not seedable.
*
* Source:
* https://github.com/bryc/code/blob/master/jshash/PRNGs.md#mulberry32
*
* @param {number} a
* @return {number}
*/
function mulberry32(a = 0) {
return function () {
a += 0x6d2b79f5 | 0;
var t = Math.imul(a ^ (a >>> 15), 1 | a);
t = (t + Math.imul(t ^ (t >>> 7), 61 | t)) ^ t;
return ((t ^ (t >>> 14)) >>> 0) / 4294967296;
};
}
const random = mulberry32();
/**
* Generates a random ID string at least 10 characters long with the
* specified prefix.
*
* @param {string} prefix
* @return {string}
*/
export default function (prefix = '') {
let result = '';
for (let i = 0; i < 10; i++) {
result = result.concat(
characters[Math.floor(random() * characters.length)]
);
}
return prefix.concat(result);
}
+2 -1
View File
@@ -1,4 +1,5 @@
import { Model, belongsTo } from 'ember-cli-mirage';
import { belongsTo } from 'ember-cli-mirage';
import Model from './base';
export default Model.extend({
scope: belongsTo(),
+2 -1
View File
@@ -1,4 +1,5 @@
import { Model, belongsTo } from 'ember-cli-mirage';
import { belongsTo } from 'ember-cli-mirage';
import Model from './base';
export default Model.extend({
scope: belongsTo(),
+20
View File
@@ -0,0 +1,20 @@
import { Model } from 'ember-cli-mirage';
export default Model.extend({
assignDefaults(defaultAttrs, attrs) {
Object.entries(defaultAttrs).map(([key, value]) => {
if (!attrs[key]) {
attrs[key] = value;
}
});
},
defaultAttrs: () => ({
version: 1,
authorized_actions: ['no-op', 'read', 'update', 'delete'],
created_time: new Date(),
}),
save() {
this.assignDefaults(this.defaultAttrs(), this.attrs);
return Model.prototype.save.apply(this, arguments);
},
});
@@ -1,4 +1,5 @@
import { Model, belongsTo } from 'ember-cli-mirage';
import { belongsTo } from 'ember-cli-mirage';
import Model from './base';
export default Model.extend({
scope: belongsTo(),
+2 -1
View File
@@ -1,4 +1,5 @@
import { Model, belongsTo } from 'ember-cli-mirage';
import { belongsTo } from 'ember-cli-mirage';
import Model from './base';
export default Model.extend({
scope: belongsTo(),
+2 -1
View File
@@ -1,4 +1,5 @@
import { Model, belongsTo, hasMany } from 'ember-cli-mirage';
import { belongsTo, hasMany } from 'ember-cli-mirage';
import Model from './base';
export default Model.extend({
scope: belongsTo(),
+2 -1
View File
@@ -1,4 +1,5 @@
import { Model, belongsTo, hasMany } from 'ember-cli-mirage';
import { belongsTo, hasMany } from 'ember-cli-mirage';
import Model from './base';
export default Model.extend({
scope: belongsTo(),
+2 -1
View File
@@ -1,4 +1,5 @@
import { Model, belongsTo, hasMany } from 'ember-cli-mirage';
import { belongsTo, hasMany } from 'ember-cli-mirage';
import Model from './base';
export default Model.extend({
scope: belongsTo(),
+2 -1
View File
@@ -1,4 +1,5 @@
import { Model, belongsTo } from 'ember-cli-mirage';
import { belongsTo } from 'ember-cli-mirage';
import Model from './base';
export default Model.extend({
scope: belongsTo(),
+2 -1
View File
@@ -1,4 +1,5 @@
import { Model, belongsTo } from 'ember-cli-mirage';
import { belongsTo } from 'ember-cli-mirage';
import Model from './base';
export default Model.extend({
scope: belongsTo(),
+2 -1
View File
@@ -1,4 +1,5 @@
import { Model, belongsTo, hasMany } from 'ember-cli-mirage';
import { belongsTo, hasMany } from 'ember-cli-mirage';
import Model from './base';
export default Model.extend({
scope: belongsTo(),
+2 -1
View File
@@ -1,4 +1,5 @@
import { Model, belongsTo } from 'ember-cli-mirage';
import { belongsTo } from 'ember-cli-mirage';
import Model from './base';
export default Model.extend({
scope: belongsTo(),
+2 -1
View File
@@ -1,4 +1,5 @@
import { Model, belongsTo, hasMany } from 'ember-cli-mirage';
import Model from './base';
import { belongsTo, hasMany } from 'ember-cli-mirage';
export default Model.extend({
scope: belongsTo(),
+2 -1
View File
@@ -1,4 +1,5 @@
import { Model, belongsTo, hasMany } from 'ember-cli-mirage';
import { belongsTo, hasMany } from 'ember-cli-mirage';
import Model from './base';
export default Model.extend({
scope: belongsTo(),
+12 -12
View File
@@ -66,10 +66,10 @@ export default function initializeMockIPC(server, config) {
session_id: newSession.id,
credentials: [
{
credential_library: {
credential_source: {
id: 'clvlt_4cvscMTl0N',
name: 'Library Name',
description: 'Library Description',
name: 'Source Name',
description: 'Source Description',
credential_store_id: 'csvlt_Q1HFGt7Jpm',
type: 'vault',
},
@@ -78,10 +78,10 @@ export default function initializeMockIPC(server, config) {
},
},
{
credential_library: {
credential_source: {
id: 'clvlt_4cvscMTl0N',
name: 'Library Name',
description: 'Library Description',
name: 'Source Name',
description: 'Source Description',
credential_store_id: 'csvlt_Q1HFGt7Jpm',
type: 'vault',
},
@@ -91,10 +91,10 @@ export default function initializeMockIPC(server, config) {
},
},
{
credential_library: {
credential_source: {
id: 'clvlt_9KWscxpcY7',
name: 'Library Name',
description: 'Library Description',
name: 'Source Name',
description: 'Source Description',
credential_store_id: 'csvlt_Q1HFGt7Jpm',
type: 'vault',
},
@@ -103,10 +103,10 @@ export default function initializeMockIPC(server, config) {
},
},
{
credential_library: {
credential_source: {
id: 'clvlt_9KWscxpcY7',
name: 'Library Name',
description: 'Library Description',
name: 'Source Name',
description: 'Source Description',
credential_store_id: 'csvlt_Q1HFGt7Jpm',
type: 'vault',
},
+17 -11
View File
@@ -16,11 +16,12 @@
"lint:hbs:fix": "ember-template-lint . --fix",
"lint:js": "eslint .",
"lint:js:fix": "eslint . --fix",
"format": "npm run format:js",
"format": "yarn run format:js",
"format:js": "prettier --write '{addon,app,config,stories,tests,mirage}/**/*.js' *.js",
"start": "ember serve",
"test": "ember test",
"test:ember-compatibility": "ember try:each",
"precommit": "yarn lint && yarn format && yarn test",
"doc:toc": "doctoc README.md"
},
"dependencies": {
@@ -33,15 +34,15 @@
"ember-fetch": "^8.1.1"
},
"devDependencies": {
"js-bexpr": "hashicorp/js-bexpr#9b4a4b54d85eba67fdfc0990133d1518d890b1e1",
"@babel/core": "^7.16.5",
"@babel/core": "^7.18.5",
"@babel/eslint-parser": "^7.18.2",
"@babel/plugin-proposal-decorators": "^7.18.6",
"@ember/optional-features": "^2.0.0",
"@ember/test-helpers": "^2.6.0",
"@glimmer/component": "^1.0.4",
"@glimmer/tracking": "^1.0.4",
"babel-eslint": "^10.1.0",
"@ember/test-helpers": "^2.8.1",
"@glimmer/component": "^1.1.2",
"@glimmer/tracking": "^1.1.2",
"broccoli-asset-rev": "^3.0.0",
"doctoc": "^2.1.0",
"doctoc": "^2.2.0",
"ember-auto-import": "^1.12.0",
"ember-cli": "~4.1.0",
"ember-cli-dependency-checker": "^3.2.0",
@@ -58,12 +59,12 @@
"ember-resolver": "^8.0.3",
"ember-source": "~3.28.4",
"ember-template-lint": "^3.7.0",
"eslint": "^7.32.0",
"eslint": "^8.12.0",
"eslint-config-prettier": "^8.3.0",
"eslint-plugin-ember": "^10.5.4",
"eslint-plugin-ember": "^10.5.9",
"eslint-plugin-node": "^11.1.0",
"eslint-plugin-prettier": "^4.0.0",
"eslint-plugin-qunit": "^6.2.0",
"js-bexpr": "hashicorp/js-bexpr#9b4a4b54d85eba67fdfc0990133d1518d890b1e1",
"loader.js": "^4.7.0",
"npm-run-all": "^4.1.5",
"prettier": "^2.4.0",
@@ -78,5 +79,10 @@
},
"ember-addon": {
"configPath": "tests/dummy/config"
},
"lint-staged": {
"*.js": "eslint --fix",
"*.hbs": "ember-template-lint --fix",
"*.{js,scss}": "prettier --write"
}
}
+1 -1
View File
@@ -17,7 +17,7 @@ module('Unit | Model | account', function (hooks) {
type: 'password',
});
assert.notOk(model.accountName);
model.attributes.login_name = 'foobar';
model.login_name = 'foobar';
assert.equal(model.accountName, 'foobar');
});
});
@@ -1,19 +0,0 @@
import { module, test } from 'qunit';
import { setupTest } from 'ember-qunit';
module(
'Unit | Model | fragment credential library attributes',
function (hooks) {
setupTest(hooks);
// Replace this with your real tests.
test('it exists', function (assert) {
let store = this.owner.lookup('service:store');
let model = store.createRecord(
'fragment-credential-library-attributes',
{}
);
assert.ok(model);
});
}
);
@@ -1,13 +0,0 @@
import { module, test } from 'qunit';
import { setupTest } from 'ember-qunit';
module('Unit | Model | fragment credential store attributes', function (hooks) {
setupTest(hooks);
// Replace this with your real tests.
test('it exists', function (assert) {
let store = this.owner.lookup('service:store');
let model = store.createRecord('fragment-credential-store-attributes', {});
assert.ok(model);
});
});
@@ -1,13 +0,0 @@
import { module, test } from 'qunit';
import { setupTest } from 'ember-qunit';
module('Unit | Model | fragment managed group attributes', function (hooks) {
setupTest(hooks);
// Replace this with your real tests.
test('it exists', function (assert) {
let store = this.owner.lookup('service:store');
let model = store.createRecord('fragment-managed-group-attributes', {});
assert.ok(model);
});
});
+35
View File
@@ -115,4 +115,39 @@ module('Unit | Model | user', function (hooks) {
'User has empty account_ids by default'
);
});
test('it defaults to null for readonly attributes when response does not have fields', async function (assert) {
assert.expect(3);
this.server.post('/v1/users/123abc:remove-accounts', (schema, request) => {
const body = JSON.parse(request.requestBody);
assert.deepEqual(body, {
account_ids: ['3'],
version: 1,
});
return { id: '123abc', name: 'newName' };
});
const store = this.owner.lookup('service:store');
store.push({
data: {
id: '123abc',
type: 'user',
attributes: {
name: 'user',
description: 'Description',
account_ids: ['3'],
version: 1,
login_name: 'zed',
scope: {
scope_id: 'o_1',
type: 'scope',
},
},
},
});
const model = store.peekRecord('user', '123abc');
await model.removeAccount('3');
assert.equal(model.login_name, null);
assert.equal(model.name, 'newName');
});
});
@@ -13,12 +13,10 @@ module('Unit | Serializer | account', function (hooks) {
name: 'Name',
auth_method_id: '1',
description: 'Description',
attributes: {
issuer: 'issuer',
subject: 'sub',
full_name: 'full_name',
email: 'email',
},
issuer: 'issuer',
subject: 'sub',
full_name: 'full_name',
email: 'email',
version: 1,
});
const snapshot = record._createSnapshot();
@@ -49,12 +47,10 @@ module('Unit | Serializer | account', function (hooks) {
name: 'Name',
auth_method_id: '1',
description: 'Description',
attributes: {
issuer: 'issuer',
subject: 'sub',
full_name: 'full_name',
email: 'email',
},
issuer: 'issuer',
subject: 'sub',
full_name: 'full_name',
email: 'email',
version: 1,
},
},
@@ -81,9 +77,7 @@ module('Unit | Serializer | account', function (hooks) {
name: 'Name',
auth_method_id: '1',
description: 'Description',
attributes: {
login_name: 'Login Name',
},
login_name: 'Login Name',
version: 1,
});
const snapshot = record._createSnapshot();
@@ -109,9 +103,7 @@ module('Unit | Serializer | account', function (hooks) {
name: 'Name',
auth_method_id: '1',
description: 'Description',
attributes: {
login_name: 'Login Name',
},
login_name: 'Login Name',
version: 1,
});
const snapshot = record._createSnapshot();
@@ -144,9 +136,7 @@ module('Unit | Serializer | account', function (hooks) {
type: 'password',
name: 'Name',
description: 'Description',
attributes: {
login_name: 'Login Name',
},
login_name: 'Login Name',
auth_method_id: '1',
version: 1,
});
@@ -170,9 +160,7 @@ module('Unit | Serializer | account', function (hooks) {
type: 'password',
name: 'Name',
description: 'Description',
attributes: {
login_name: 'Login Name',
},
login_name: 'Login Name',
auth_method_id: '1',
version: 1,
});
@@ -211,4 +211,41 @@ module('Unit | Serializer | application', function (hooks) {
},
});
});
test('it normalizes removed fields correctly', function (assert) {
assert.expect(1);
const store = this.owner.lookup('service:store');
const serializer = store.serializerFor('user');
const user = store.createRecord('user').constructor;
const payload = {
id: '1',
name: 'user 1',
scope: { id: 'o_123' },
};
const normalized = serializer.normalizeUpdateRecordResponse(
store,
user,
payload
);
assert.deepEqual(normalized, {
included: [],
data: {
id: '1',
type: 'user',
attributes: {
authorized_actions: [],
name: 'user 1',
scope: { scope_id: 'o_123' },
account_ids: [],
authorized_collection_actions: null,
created_time: null,
email: null,
full_name: null,
login_name: null,
updated_time: null,
},
relationships: {},
},
});
});
});
@@ -12,10 +12,8 @@ module('Unit | Serializer | credential library', function (hooks) {
type: 'vault',
name: 'Name',
description: 'Description',
attributes: {
path: '/vault/path',
http_method: 'GET',
},
path: '/vault/path',
http_method: 'GET',
version: 1,
});
const snapshot = record._createSnapshot();
@@ -45,10 +43,8 @@ module('Unit | Serializer | credential library', function (hooks) {
type: 'vault',
name: 'Name',
description: 'Description',
attributes: {
path: '/vault/path',
http_method: 'GET',
},
path: '/vault/path',
http_method: 'GET',
version: 1,
},
},
@@ -68,4 +64,66 @@ module('Unit | Serializer | credential library', function (hooks) {
version: 1,
});
});
test('it serializes empty strings to null', function (assert) {
assert.expect(1);
const store = this.owner.lookup('service:store');
const record = store.createRecord('credential-library', {
http_method: '',
path: null,
});
let serializedRecord = record.serialize();
assert.deepEqual(serializedRecord, {
attributes: {
http_method: null,
path: null,
},
credential_store_id: null,
description: null,
name: null,
type: null,
});
});
test('it does not serialize http_request_body unless http_method is set to POST', function (assert) {
assert.expect(2);
const store = this.owner.lookup('service:store');
const record = store.createRecord('credential-library', {
http_method: 'GET',
http_request_body: 'body',
});
let serializedRecord = record.serialize();
assert.deepEqual(
serializedRecord,
{
attributes: {
http_method: 'GET',
path: null,
},
credential_store_id: null,
description: null,
name: null,
type: null,
},
'http_request_body attribute is not expected'
);
record.http_method = 'POST';
serializedRecord = record.serialize();
assert.deepEqual(
serializedRecord,
{
attributes: {
http_method: 'POST',
http_request_body: 'body',
path: null,
},
credential_store_id: null,
description: null,
name: null,
type: null,
},
'http_request_body attribute is expected'
);
});
});
@@ -12,16 +12,14 @@ module('Unit | Serializer | credential store', function (hooks) {
type: 'vault',
name: 'Name',
description: 'Description',
attributes: {
address: 'http://localhost:5000',
ca_cert: 'ca-cert-123',
client_certificate: 'client-cert-123',
client_certificate_key: 'client-cert-key-456',
namespace: 'foobar',
tls_server_name: 'yes',
tls_skip_verify: false,
token: 'foo',
},
address: 'http://localhost:5000',
ca_cert: 'ca-cert-123',
client_certificate: 'client-cert-123',
client_certificate_key: 'client-cert-key-456',
namespace: 'foobar',
tls_server_name: 'yes',
tls_skip_verify: false,
token: 'foo',
version: 1,
});
const snapshot = record._createSnapshot();
@@ -56,16 +54,14 @@ module('Unit | Serializer | credential store', function (hooks) {
type: 'vault',
name: 'Name',
description: 'Description',
attributes: {
address: 'http://localhost:5000',
ca_cert: 'ca-cert-123',
client_certificate: 'client-cert-123',
client_certificate_key: 'client-cert-key-456',
namespace: 'foobar',
tls_server_name: 'yes',
tls_skip_verify: false,
token: 'foo',
},
address: 'http://localhost:5000',
ca_cert: 'ca-cert-123',
client_certificate: 'client-cert-123',
client_certificate_key: 'client-cert-key-456',
namespace: 'foobar',
tls_server_name: 'yes',
tls_skip_verify: false,
token: 'foo',
version: 1,
},
},
@@ -90,4 +86,123 @@ module('Unit | Serializer | credential store', function (hooks) {
version: 1,
});
});
test('it serializes empty strings to null', function (assert) {
assert.expect(1);
const store = this.owner.lookup('service:store');
const record = store.createRecord('credential-store', {
address: '',
ca_cert: '',
client_certificate: '',
client_certificate_key: '',
namespace: '',
tls_server_name: '',
tls_skip_verify: false,
});
let serializedRecord = record.serialize();
assert.deepEqual(serializedRecord, {
attributes: {
address: null,
ca_cert: null,
client_certificate: null,
client_certificate_key: null,
namespace: null,
tls_server_name: null,
tls_skip_verify: false,
},
description: null,
name: null,
type: null,
});
});
test('it does not serialize token if present but falsy', function (assert) {
assert.expect(1);
const store = this.owner.lookup('service:store');
const record = store.createRecord('credential-store', {
token: null,
address: 'http://localhost:5000',
ca_cert: 'ca-cert-123',
client_certificate: 'client-cert-123',
client_certificate_key: 'client-cert-key-456',
namespace: 'foobar',
tls_server_name: 'yes',
tls_skip_verify: false,
});
let serializedRecord = record.serialize();
assert.deepEqual(
serializedRecord,
{
attributes: {
address: 'http://localhost:5000',
ca_cert: 'ca-cert-123',
client_certificate: 'client-cert-123',
client_certificate_key: 'client-cert-key-456',
namespace: 'foobar',
tls_server_name: 'yes',
tls_skip_verify: false,
},
description: null,
name: null,
type: null,
},
'token attribute is not expected'
);
});
test('it does not serialize client certificate key if present but falsy when client certificate is present', function (assert) {
assert.expect(2);
const store = this.owner.lookup('service:store');
const record = store.createRecord('credential-store', {
client_certificate: 'client-cert-123',
client_certificate_key: '',
address: 'http://localhost:5000',
token: 'foo',
ca_cert: 'ca-cert-123',
namespace: 'foobar',
tls_server_name: 'yes',
tls_skip_verify: false,
});
let serializedRecord = record.serialize();
assert.deepEqual(
serializedRecord,
{
attributes: {
client_certificate: 'client-cert-123',
address: 'http://localhost:5000',
token: 'foo',
ca_cert: 'ca-cert-123',
namespace: 'foobar',
tls_server_name: 'yes',
tls_skip_verify: false,
},
description: null,
name: null,
type: null,
},
'client certificate key attribute is not expected'
);
record.client_certificate_key = 'client-cert-key-456';
serializedRecord = record.serialize();
assert.deepEqual(
serializedRecord,
{
attributes: {
client_certificate: 'client-cert-123',
client_certificate_key: 'client-cert-key-456',
address: 'http://localhost:5000',
token: 'foo',
ca_cert: 'ca-cert-123',
namespace: 'foobar',
tls_server_name: 'yes',
tls_skip_verify: false,
},
description: null,
name: null,
type: null,
},
'client certificate key attribute is expected'
);
});
});
@@ -1,23 +0,0 @@
import { module, test } from 'qunit';
import { setupTest } from 'ember-qunit';
module('Unit | Serializer | fragment account attributes', function (hooks) {
setupTest(hooks);
// Replace this with your real tests.
test('it exists', function (assert) {
let store = this.owner.lookup('service:store');
let serializer = store.serializerFor('fragment-account-attributes');
assert.ok(serializer);
});
test('it serializes records', function (assert) {
let store = this.owner.lookup('service:store');
let record = store.createRecord('fragment-account-attributes', {});
let serializedRecord = record.serialize();
assert.ok(serializedRecord);
});
});
@@ -1,59 +0,0 @@
import { module, test } from 'qunit';
import { setupTest } from 'ember-qunit';
module(
'Unit | Serializer | fragment credential library attributes',
function (hooks) {
setupTest(hooks);
test('it serializes empty strings to null', function (assert) {
assert.expect(1);
const store = this.owner.lookup('service:store');
const record = store.createRecord(
'fragment-credential-library-attributes',
{
http_method: '',
path: null,
}
);
let serializedRecord = record.serialize();
assert.deepEqual(serializedRecord, {
http_method: null,
path: null,
});
});
test('it does not serialize http_request_body unless http_method is set to POST', function (assert) {
assert.expect(2);
const store = this.owner.lookup('service:store');
const record = store.createRecord(
'fragment-credential-library-attributes',
{
http_method: 'GET',
http_request_body: 'body',
}
);
let serializedRecord = record.serialize();
assert.deepEqual(
serializedRecord,
{
http_method: 'GET',
path: null,
},
'http_request_body attribute is not expected'
);
record.http_method = 'POST';
serializedRecord = record.serialize();
assert.deepEqual(
serializedRecord,
{
http_method: 'POST',
http_request_body: 'body',
path: null,
},
'http_request_body attribute is expected'
);
});
}
);
@@ -1,117 +0,0 @@
import { module, test } from 'qunit';
import { setupTest } from 'ember-qunit';
module(
'Unit | Serializer | fragment credential store attributes',
function (hooks) {
setupTest(hooks);
test('it serializes empty strings to null', function (assert) {
assert.expect(1);
const store = this.owner.lookup('service:store');
const record = store.createRecord(
'fragment-credential-store-attributes',
{
address: '',
ca_cert: '',
client_certificate: '',
client_certificate_key: '',
namespace: '',
tls_server_name: '',
tls_skip_verify: false,
}
);
let serializedRecord = record.serialize();
assert.deepEqual(serializedRecord, {
address: null,
ca_cert: null,
client_certificate: null,
client_certificate_key: null,
namespace: null,
tls_server_name: null,
tls_skip_verify: false,
});
});
test('it does not serialize token if present but falsy', function (assert) {
assert.expect(1);
const store = this.owner.lookup('service:store');
const record = store.createRecord(
'fragment-credential-store-attributes',
{
token: null,
address: 'http://localhost:5000',
ca_cert: 'ca-cert-123',
client_certificate: 'client-cert-123',
client_certificate_key: 'client-cert-key-456',
namespace: 'foobar',
tls_server_name: 'yes',
tls_skip_verify: false,
}
);
let serializedRecord = record.serialize();
assert.deepEqual(
serializedRecord,
{
address: 'http://localhost:5000',
ca_cert: 'ca-cert-123',
client_certificate: 'client-cert-123',
client_certificate_key: 'client-cert-key-456',
namespace: 'foobar',
tls_server_name: 'yes',
tls_skip_verify: false,
},
'token attribute is not expected'
);
});
test('it does not serialize client certificate key if present but falsy when client certificate is present', function (assert) {
assert.expect(2);
const store = this.owner.lookup('service:store');
const record = store.createRecord(
'fragment-credential-store-attributes',
{
client_certificate: 'client-cert-123',
client_certificate_key: '',
address: 'http://localhost:5000',
token: 'foo',
ca_cert: 'ca-cert-123',
namespace: 'foobar',
tls_server_name: 'yes',
tls_skip_verify: false,
}
);
let serializedRecord = record.serialize();
assert.deepEqual(
serializedRecord,
{
client_certificate: 'client-cert-123',
address: 'http://localhost:5000',
token: 'foo',
ca_cert: 'ca-cert-123',
namespace: 'foobar',
tls_server_name: 'yes',
tls_skip_verify: false,
},
'client certificate key attribute is not expected'
);
record.client_certificate_key = 'client-cert-key-456';
serializedRecord = record.serialize();
assert.deepEqual(
serializedRecord,
{
client_certificate: 'client-cert-123',
client_certificate_key: 'client-cert-key-456',
address: 'http://localhost:5000',
token: 'foo',
ca_cert: 'ca-cert-123',
namespace: 'foobar',
tls_server_name: 'yes',
tls_skip_verify: false,
},
'client certificate key attribute is expected'
);
});
}
);
@@ -1,21 +0,0 @@
import { module, test } from 'qunit';
import { setupTest } from 'ember-qunit';
module(
'Unit | Serializer | fragment managed groups attributes',
function (hooks) {
setupTest(hooks);
test('it serializes empty string to null', function (assert) {
assert.expect(1);
const store = this.owner.lookup('service:store');
const record = store.createRecord('fragment-managed-group-attributes', {
filter: '',
});
const serializedRecord = record.serialize();
assert.deepEqual(serializedRecord, {
filter: null,
});
});
}
);
@@ -41,9 +41,7 @@ module('Unit | Serializer | Managed group', function (hooks) {
version: 1,
auth_method_id: '1234',
type: 'oidc',
attributes: {
filter: 'key=value',
},
filter: 'key=value',
});
const snapshot = record._createSnapshot();
snapshot.adapterOptions = {};
@@ -75,9 +73,7 @@ module('Unit | Serializer | Managed group', function (hooks) {
version: undefined,
auth_method_id: '1234',
type: 'oidc',
attributes: {
filter: 'key=value',
},
filter: 'key=value',
},
},
});
@@ -138,9 +134,7 @@ module('Unit | Serializer | Managed group', function (hooks) {
version: 1,
auth_method_id: '1234',
type: 'oidc',
attributes: {
filter: 'key=value',
},
filter: 'key=value',
},
},
});
@@ -35,6 +35,7 @@ module('Unit | Serializer | target', function (hooks) {
scope_id: 'org_1',
session_max_seconds: 28800,
session_connection_limit: 1,
worker_filter: null,
attributes: {
default_port: 1234,
},
@@ -86,6 +87,38 @@ module('Unit | Serializer | target', function (hooks) {
});
});
test('it serializes the worker_filter attribute if present', function (assert) {
assert.expect(1);
const store = this.owner.lookup('service:store');
const serializer = store.serializerFor('target');
const record = store.createRecord('target', {
name: 'User',
description: 'Description',
version: 1,
type: 'ssh',
worker_filter: 'worker',
default_port: 1234,
scope: {
scope_id: 'org_1',
},
});
const snapshot = record._createSnapshot();
const serializedRecord = serializer.serialize(snapshot);
assert.deepEqual(serializedRecord, {
name: 'User',
description: 'Description',
version: 1,
type: 'ssh',
scope_id: 'org_1',
session_max_seconds: 28800,
session_connection_limit: 1,
worker_filter: 'worker',
attributes: {
default_port: 1234,
},
});
});
test('it normalizes records with array fields', function (assert) {
assert.expect(1);
const store = this.owner.lookup('service:store');
@@ -189,4 +222,36 @@ module('Unit | Serializer | target', function (hooks) {
},
});
});
test('it normalizes the worker_filter attribute if present', function (assert) {
assert.expect(1);
const store = this.owner.lookup('service:store');
const serializer = store.serializerFor('target');
const target = store.createRecord('target').constructor;
const payload = {
id: '1',
name: 'Target 1',
worker_filter: 'worker',
};
const normalized = serializer.normalizeSingleResponse(
store,
target,
payload
);
assert.deepEqual(normalized, {
included: [],
data: {
id: '1',
type: 'target',
attributes: {
authorized_actions: [],
name: 'Target 1',
host_sources: [],
application_credential_source_ids: [],
worker_filter: 'worker',
},
relationships: {},
},
});
});
});
+7 -8
View File
@@ -2,20 +2,19 @@
module.exports = {
root: true,
parser: 'babel-eslint',
parser: '@babel/eslint-parser',
parserOptions: {
ecmaVersion: 2018,
sourceType: 'module',
ecmaFeatures: {
legacyDecorators: true,
// This is specific babel-config. If grows consider creating a babel config file
requireConfigFile: false,
babelOptions: {
plugins: [['@babel/plugin-proposal-decorators', { legacy: true }]],
},
// end of babel-config
},
plugins: ['ember'],
extends: [
'eslint:recommended',
'plugin:ember/recommended',
'plugin:prettier/recommended',
],
extends: ['eslint:recommended', 'plugin:ember/recommended', 'prettier'],
env: {
browser: true,
},
+3 -1
View File
@@ -34,19 +34,21 @@ List of available project commands. `yarn run <command-name>`
| Command | Description |
| ------- | ----------- |
| lint | Runs all lint commands. |
| lint:fix | Runs automatic lint fixes for all files. |
| lint:js | Lints `js` files. |
| lint:js:fix | Runs automatic lint fixes for `js` files. |
| format | Runs all auto-formatters. |
| format:js | Auto-formats `js` files using Prettier. |
| start | Runs the dummy app local server. |
| test | Runs all tests. |
| test:all | Runs tests across multiple Ember versions with ember-try. |
| precommit | Runs all lint, format and tests. |
| doc:toc | Automatically generates a table of contents for this README file. |
Additional commands in the monorepo package may affect this projects.
## Linting
* `yarn lint:hbs`
* `yarn lint:js`
* `yarn lint:js --fix`
+16 -11
View File
@@ -10,14 +10,14 @@
"scripts": {
"lint": "npm-run-all --aggregate-output --continue-on-error --parallel 'lint:!(fix)'",
"lint:fix": "npm-run-all --aggregate-output --continue-on-error --parallel lint:*:fix",
"lint:hbs:fix": "ember-template-lint . --fix",
"lint:js": "eslint .",
"format": "npm run format:js",
"format:js": "prettier --write '{addon,app,config,stories,tests}/**/*.js' *.js",
"lint:js:fix": "eslint . --fix",
"format": "yarn run format:js",
"format:js": "prettier --write '{addon,app,config,stories,tests}/**/*.js' *.js",
"start": "ember serve",
"test": "ember test",
"test:ember-compatibility": "ember try:each",
"precommit": "yarn lint && yarn format && yarn test",
"doc:toc": "doctoc README.md"
},
"dependencies": {
@@ -27,14 +27,15 @@
"ember-simple-auth": "^4.0.0"
},
"devDependencies": {
"@babel/eslint-parser": "^7.18.2",
"@babel/plugin-proposal-decorators": "^7.18.6",
"@ember/optional-features": "^2.0.0",
"@ember/test-helpers": "^2.6.0",
"@glimmer/component": "^1.0.4",
"@glimmer/tracking": "^1.0.4",
"babel-eslint": "^10.1.0",
"@ember/test-helpers": "^2.8.1",
"@glimmer/component": "^1.1.2",
"@glimmer/tracking": "^1.1.2",
"broccoli-asset-rev": "^3.0.0",
"core": "*",
"doctoc": "^2.1.0",
"doctoc": "^2.2.0",
"ember-auto-import": "^1.12.0",
"ember-cli": "~4.1.0",
"ember-cli-dependency-checker": "^3.2.0",
@@ -51,11 +52,10 @@
"ember-resolver": "^8.0.3",
"ember-source": "~3.28.4",
"ember-template-lint": "^3.7.0",
"eslint": "^7.32.0",
"eslint": "^8.12.0",
"eslint-config-prettier": "^8.3.0",
"eslint-plugin-ember": "^10.5.4",
"eslint-plugin-ember": "^10.5.9",
"eslint-plugin-node": "^11.1.0",
"eslint-plugin-prettier": "^4.0.0",
"eslint-plugin-qunit": "^6.2.0",
"loader.js": "^4.7.0",
"npm-run-all": "^4.1.5",
@@ -71,5 +71,10 @@
},
"ember-addon": {
"configPath": "tests/dummy/config"
},
"lint-staged": {
"*.js": "eslint --fix",
"*.hbs": "ember-template-lint --fix",
"*.{js,scss}": "prettier --write"
}
}
+7 -8
View File
@@ -2,20 +2,19 @@
module.exports = {
root: true,
parser: 'babel-eslint',
parser: '@babel/eslint-parser',
parserOptions: {
ecmaVersion: 2018,
sourceType: 'module',
ecmaFeatures: {
legacyDecorators: true,
// This is specific babel-config. If grows consider creating a babel config file
requireConfigFile: false,
babelOptions: {
plugins: [['@babel/plugin-proposal-decorators', { legacy: true }]],
},
// end of babel-config
},
plugins: ['ember'],
extends: [
'eslint:recommended',
'plugin:ember/recommended',
'plugin:prettier/recommended',
],
extends: ['eslint:recommended', 'plugin:ember/recommended', 'prettier'],
env: {
browser: true,
},
+7 -14
View File
@@ -5,7 +5,6 @@ helpers.
<!-- START doctoc generated TOC please keep comment here to allow auto update -->
<!-- DON'T EDIT THIS SECTION, INSTEAD RE-RUN doctoc TO UPDATE -->
<!-- END doctoc generated TOC please keep comment here to allow auto update -->
- [Add core to an App](#add-core-to-an-app)
- [Installation](#installation)
@@ -26,18 +25,6 @@ helpers.
<!-- END doctoc generated TOC please keep comment here to allow auto update -->
- [Add core to an App](#add-core-to-an-app)
- [Installation](#installation)
- [Yarn Commands](#yarn-commands)
- [Linting](#linting)
- [Formatting](#formatting)
- [Running tests](#running-tests)
- [Running the dummy application](#running-the-dummy-application)
- [Contributing](#contributing)
- [Building ToC](#building-toc)
<!-- END doctoc generated TOC please keep comment here to allow auto update -->
## Add core to an App
Add this addon to an Ember application's `devDependencies` as:
@@ -154,11 +141,16 @@ List of available project commands. `yarn run <command-name>`
| build | Builds the dummy app for production. |
| lint | Runs all lint commands. |
| lint:js | Lints `js` files. |
| lint:js:fix | Runs automatic lint fixes for `js` files. |
| lint:hbs | Runs lint for `hbs` template files. |
| lint:hbs:fix | Runs automatic lint fixes for `hbs` template files. |
| format | Runs all auto-formatters. |
| format:js | Auto-formats `js` files using Prettier. |
| format:hbs | Auto-formats `hbs` files using Prettier. |
| start | Runs the dummy app local server. |
| test | Runs all tests. |
| test:all | Runs tests across multiple Ember versions with ember-try. |
| test:ember-compatibility | Runs tests across multiple Ember versions with ember-try. |
| precommit | Runs all lint, format and tests. |
| doc:toc | Automatically generates a table of contents for this README file. |
Additional commands in the monorepo package may affect this projects.
@@ -166,6 +158,7 @@ Additional commands in the monorepo package may affect this projects.
## Linting
* `yarn lint:hbs`
* `yarn lint:hbs --fix`
* `yarn lint:js`
* `yarn lint:js --fix`
@@ -1,3 +1,5 @@
{{!-- //TODO fix the issue and delete disabling the rule --}}
{{!-- template-lint-disable no-passed-in-event-handlers --}}
{{#if @model.type}}
{{component (concat "form/authenticate/" @model.type)
submit=@submit
@@ -0,0 +1,3 @@
<span ...attributes class='image-container'>
{{inline-svg @name}}
</span>
@@ -0,0 +1,18 @@
<Rose::Button
...attributes
@style='inline-link-action'
@iconLeft={{if
this.isLoading
'flight-icons/svg/loading-16'
'flight-icons/svg/reload-16'
}}
class={{if
this.isLoading
'loading-button is-loading'
'loading-button'
}}
@disabled={{this.isLoading}}
{{on 'click' this.toggleRefresh}}
>
{{yield}}
</Rose::Button>
@@ -0,0 +1,20 @@
import Component from '@glimmer/component';
import { tracked } from '@glimmer/tracking';
import { action } from '@ember/object';
import { later } from '@ember/runloop';
export default class LoadingButton extends Component {
// =actions
@tracked isLoading = false;
@action
async toggleRefresh() {
this.isLoading = true;
try {
await this.args.onClick();
} catch (e) {
console.error('Error while loading data', e);
}
later(() => (this.isLoading = false), 1000);
}
}
Loaded 100 of 292 files, more files were not shown because too many files have changed in this diff. Show more