-
Notifications
You must be signed in to change notification settings - Fork 4.2k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
UI Hide Secrets Sync from nav if not on license and/or no policy permissions #27262
Changes from all commits
64c2fd0
931a926
ac6b262
b1ad18f
09162c4
e67076e
e69075b
27df01a
7fc2fd7
36fbb78
1f2a88b
462d258
9f1ab09
e4e1080
3ec1646
628ea6b
dccc476
22ce68a
6fd9b21
51bf477
e6b9811
8f0fed0
0e598d8
e8bf2c4
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
```release-note:improvement | ||
ui/secrets-sync: Hide Secrets Sync from the sidebar nav if user does not have access to the feature. | ||
``` |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -10,6 +10,7 @@ import { DEBUG } from '@glimmer/env'; | |
import lazyCapabilities, { apiPath } from 'vault/macros/lazy-capabilities'; | ||
import type StoreService from 'vault/services/store'; | ||
import type VersionService from 'vault/services/version'; | ||
import type PermissionsService from 'vault/services/permissions'; | ||
|
||
const FLAGS = { | ||
vaultCloudNamespace: 'VAULT_CLOUD_ADMIN_NAMESPACE', | ||
|
@@ -24,6 +25,7 @@ const FLAGS = { | |
export default class flagsService extends Service { | ||
@service declare readonly version: VersionService; | ||
@service declare readonly store: StoreService; | ||
@service declare readonly permissions: PermissionsService; | ||
|
||
@tracked activatedFlags: string[] = []; | ||
@tracked featureFlags: string[] = []; | ||
|
@@ -60,9 +62,9 @@ export default class flagsService extends Service { | |
} | ||
|
||
getActivatedFlags = keepLatestTask(async () => { | ||
if (this.version.isCommunity) return; | ||
// Response could change between user sessions. | ||
// Fire off endpoint without checking if activated features are already set. | ||
if (this.version.isCommunity) return; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Edge case question - if a customer downgrades from enterprise, are their activated flags preserved? (Not necessary for this PR, mostly just curious) There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think I've asked Robert this, and more or less no. I think because there's a conditional wrapping that endpoint which is checking for enterprise, so it would return nothing. That being said I haven't tested this workflow. |
||
try { | ||
const response = await this.store | ||
.adapterFor('application') | ||
|
@@ -86,4 +88,21 @@ export default class flagsService extends Service { | |
this.secretsSyncActivatePath.get('canUpdate') !== false | ||
); | ||
} | ||
|
||
get showSecretsSync() { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Could you explain your reasoning for putting this getter here? Since it's compiling logic from flags, permissions and versions services for just secret sync, it feels a little arbitrary living in the flag service, which I understood to be just for returning info about cluster flags. Though looking at the other getter here I realize we're limited on time for this PR, but want to suggest that a future improvement is maybe separating or clarifying concerns here. Perhaps that means having another service (auth service?) responsible for managing user state related logic There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Noelle and I chatted about this. Because we're using it in more than one places, and the concept is to keep access to this route consistent in both clients and sidebar nav we opted to leave it in the service. But yes agree, flags (similar to what has happened to version service) is growing past it's original scope. |
||
const isHvdManaged = this.isHvdManaged; | ||
const onLicense = this.version.hasSecretsSync; | ||
const isEnterprise = this.version.isEnterprise; | ||
const isActivated = this.secretsSyncIsActivated; | ||
|
||
if (!isEnterprise) return false; | ||
if (isHvdManaged) return true; | ||
Comment on lines
+98
to
+99
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Are HVD clusters enterprise? ~ til ~ I was going to suggest rearranging this order, but disregard if HVD clusters are enterprise There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. they sure are 🙂 |
||
if (isEnterprise && !onLicense) return false; | ||
if (isActivated) { | ||
// if the feature is activated but the user does not have permissions on the `sys/sync` endpoint, hide navigation link. | ||
return this.permissions.hasNavPermission('sync'); | ||
} | ||
// only remaining option is Enterprise with Secrets Sync on the license but the feature is not activated. In this case, we want to show the upsell page and message about either activating or having an admin activate. | ||
return true; | ||
} | ||
} |
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The list here came from me scanning through the sync API. We should test lots of policies to make sure I've gotten all the options. |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -49,6 +49,12 @@ const API_PATHS = { | |
settings: { | ||
customMessages: 'sys/config/ui/custom-messages', | ||
}, | ||
sync: { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm still learning out this service works...but do you know why just having sync: 'sys/sync/', which ends in a There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. nope! 🙃 This is what I pinged Chelsea about in the dev channel. The logic of comparison is backwards from what you'd think they be comparing. I'll ping you on that thread which has links, etc. But it's also something that I can more easily clarify in standup. |
||
destinations: 'sys/sync/destinations', | ||
associations: 'sys/sync/associations', | ||
config: 'sys/sync/config', | ||
github: 'sys/sync/github-apps', | ||
Monkeychip marked this conversation as resolved.
Show resolved
Hide resolved
|
||
}, | ||
}; | ||
|
||
const API_PATHS_TO_ROUTE_PARAMS = { | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -43,7 +43,7 @@ export default class SyncActivationModal extends Component<Args> { | |
.adapterFor('application') | ||
.ajax('/v1/sys/activation-flags/secrets-sync/activate', 'POST', { namespace }); | ||
// must refresh and not transition because transition does not refresh the model from within a namespace | ||
yield this.router.refresh(); | ||
yield this.router.refresh('vault.cluster'); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. you can probably take this or leave it, but i tried explicitly passing in the parent route that we want refreshed here to see if it'd help us assert that the get activated features was successfully re-fetched. i tried this based on the docs i read here: doing this works fine in the UI, and after adding a bunch of |
||
} catch (error) { | ||
this.args.onError(errorMessage(error)); | ||
this.flashMessages.danger(`Error enabling feature \n ${errorMessage(error)}`); | ||
|
Monkeychip marked this conversation as resolved.
Show resolved
Hide resolved
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -13,13 +13,8 @@ export default class SyncSecretsRoute extends Route { | |
@service declare readonly router: RouterService; | ||
@service declare readonly flags: FlagService; | ||
|
||
beforeModel() { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Commented in slack about refresh ramifications removing this fetch to only happen in the cluster.js route |
||
return this.flags.fetchActivatedFlags(); | ||
} | ||
|
||
model() { | ||
return { | ||
// TODO will modify when we use the persona service. | ||
activatedFeatures: this.flags.activatedFlags, | ||
}; | ||
} | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I've done this several times now on the destination vs destinations test, I stumble over what the heck makes these test names different. I clarified it for myself 😬 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thank you for this comment!