mirror of
https://github.com/bitwarden/browser
synced 2025-12-16 00:03:56 +00:00
[PM-16091] Add SsoExternalId to the member dialog and hide ExternalId if there is no value to display (#14126)
* Add ssoExternalId to OrganizationUserAdminView and OrganizationUserDetailsResponse - Updated OrganizationUserAdminView to include ssoExternalId property. - Enhanced OrganizationUserDetailsResponse constructor to initialize ssoExternalId from response data. * Add SSO External ID copy to messages.json * Implement SSO External ID field in member dialog - Added a new input field for ssoExternalId in the member dialog component. - Introduced visibility logic for both externalId and ssoExternalId based on feature flags. - Updated form control initialization to include ssoExternalId.
This commit is contained in:
@@ -17,6 +17,7 @@ export class OrganizationUserAdminView {
|
|||||||
type: OrganizationUserType;
|
type: OrganizationUserType;
|
||||||
status: OrganizationUserStatusType;
|
status: OrganizationUserStatusType;
|
||||||
externalId: string;
|
externalId: string;
|
||||||
|
ssoExternalId: string;
|
||||||
permissions: PermissionsApi;
|
permissions: PermissionsApi;
|
||||||
resetPasswordEnrolled: boolean;
|
resetPasswordEnrolled: boolean;
|
||||||
hasMasterPassword: boolean;
|
hasMasterPassword: boolean;
|
||||||
@@ -39,6 +40,7 @@ export class OrganizationUserAdminView {
|
|||||||
view.type = response.type;
|
view.type = response.type;
|
||||||
view.status = response.status;
|
view.status = response.status;
|
||||||
view.externalId = response.externalId;
|
view.externalId = response.externalId;
|
||||||
|
view.ssoExternalId = response.ssoExternalId;
|
||||||
view.permissions = response.permissions;
|
view.permissions = response.permissions;
|
||||||
view.resetPasswordEnrolled = response.resetPasswordEnrolled;
|
view.resetPasswordEnrolled = response.resetPasswordEnrolled;
|
||||||
view.collections = response.collections.map((c) => ({
|
view.collections = response.collections.map((c) => ({
|
||||||
|
|||||||
@@ -177,11 +177,17 @@
|
|||||||
</bit-label>
|
</bit-label>
|
||||||
</bit-form-control>
|
</bit-form-control>
|
||||||
</ng-container>
|
</ng-container>
|
||||||
<bit-form-field>
|
<bit-form-field *ngIf="isExternalIdVisible$ | async">
|
||||||
<bit-label>{{ "externalId" | i18n }}</bit-label>
|
<bit-label>{{ "externalId" | i18n }}</bit-label>
|
||||||
<input bitInput type="text" formControlName="externalId" />
|
<input bitInput type="text" formControlName="externalId" />
|
||||||
<bit-hint>{{ "externalIdDesc" | i18n }}</bit-hint>
|
<bit-hint>{{ "externalIdDesc" | i18n }}</bit-hint>
|
||||||
</bit-form-field>
|
</bit-form-field>
|
||||||
|
|
||||||
|
<bit-form-field *ngIf="isSsoExternalIdVisible$ | async">
|
||||||
|
<bit-label>{{ "ssoExternalId" | i18n }}</bit-label>
|
||||||
|
<input bitInput type="text" formControlName="ssoExternalId" />
|
||||||
|
<bit-hint>{{ "ssoExternalIdDesc" | i18n }}</bit-hint>
|
||||||
|
</bit-form-field>
|
||||||
</bit-tab>
|
</bit-tab>
|
||||||
<bit-tab *ngIf="organization.useGroups" [label]="'groups' | i18n">
|
<bit-tab *ngIf="organization.useGroups" [label]="'groups' | i18n">
|
||||||
<div class="tw-mb-6">
|
<div class="tw-mb-6">
|
||||||
|
|||||||
@@ -125,6 +125,7 @@ export class MemberDialogComponent implements OnDestroy {
|
|||||||
emails: [""],
|
emails: [""],
|
||||||
type: OrganizationUserType.User,
|
type: OrganizationUserType.User,
|
||||||
externalId: this.formBuilder.control({ value: "", disabled: true }),
|
externalId: this.formBuilder.control({ value: "", disabled: true }),
|
||||||
|
ssoExternalId: this.formBuilder.control({ value: "", disabled: true }),
|
||||||
accessSecretsManager: false,
|
accessSecretsManager: false,
|
||||||
access: [[] as AccessItemValue[]],
|
access: [[] as AccessItemValue[]],
|
||||||
groups: [[] as AccessItemValue[]],
|
groups: [[] as AccessItemValue[]],
|
||||||
@@ -155,6 +156,22 @@ export class MemberDialogComponent implements OnDestroy {
|
|||||||
FeatureFlag.AccountDeprovisioning,
|
FeatureFlag.AccountDeprovisioning,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
protected isExternalIdVisible$ = this.configService
|
||||||
|
.getFeatureFlag$(FeatureFlag.SsoExternalIdVisibility)
|
||||||
|
.pipe(
|
||||||
|
map((isEnabled) => {
|
||||||
|
return !isEnabled || !!this.formGroup.get("externalId")?.value;
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
|
||||||
|
protected isSsoExternalIdVisible$ = this.configService
|
||||||
|
.getFeatureFlag$(FeatureFlag.SsoExternalIdVisibility)
|
||||||
|
.pipe(
|
||||||
|
map((isEnabled) => {
|
||||||
|
return isEnabled && !!this.formGroup.get("ssoExternalId")?.value;
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
|
||||||
private destroy$ = new Subject<void>();
|
private destroy$ = new Subject<void>();
|
||||||
|
|
||||||
get customUserTypeSelected(): boolean {
|
get customUserTypeSelected(): boolean {
|
||||||
@@ -402,6 +419,7 @@ export class MemberDialogComponent implements OnDestroy {
|
|||||||
this.formGroup.patchValue({
|
this.formGroup.patchValue({
|
||||||
type: userDetails.type,
|
type: userDetails.type,
|
||||||
externalId: userDetails.externalId,
|
externalId: userDetails.externalId,
|
||||||
|
ssoExternalId: userDetails.ssoExternalId,
|
||||||
access: accessSelections,
|
access: accessSelections,
|
||||||
accessSecretsManager: userDetails.accessSecretsManager,
|
accessSecretsManager: userDetails.accessSecretsManager,
|
||||||
groups: groupAccessSelections,
|
groups: groupAccessSelections,
|
||||||
|
|||||||
@@ -3345,6 +3345,12 @@
|
|||||||
"externalIdDesc": {
|
"externalIdDesc": {
|
||||||
"message": "External ID is an unencrypted reference used by the Bitwarden Directory Connector and API."
|
"message": "External ID is an unencrypted reference used by the Bitwarden Directory Connector and API."
|
||||||
},
|
},
|
||||||
|
"ssoExternalId": {
|
||||||
|
"message": "SSO External ID"
|
||||||
|
},
|
||||||
|
"ssoExternalIdDesc": {
|
||||||
|
"message": "SSO External ID is an unencrypted reference between Bitwarden and your configured SSO provider."
|
||||||
|
},
|
||||||
"nestCollectionUnder": {
|
"nestCollectionUnder": {
|
||||||
"message": "Nest collection under"
|
"message": "Nest collection under"
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -64,10 +64,12 @@ export class OrganizationUserUserDetailsResponse extends OrganizationUserRespons
|
|||||||
|
|
||||||
export class OrganizationUserDetailsResponse extends OrganizationUserResponse {
|
export class OrganizationUserDetailsResponse extends OrganizationUserResponse {
|
||||||
managedByOrganization: boolean;
|
managedByOrganization: boolean;
|
||||||
|
ssoExternalId: string;
|
||||||
|
|
||||||
constructor(response: any) {
|
constructor(response: any) {
|
||||||
super(response);
|
super(response);
|
||||||
this.managedByOrganization = this.getResponseProperty("ManagedByOrganization") ?? false;
|
this.managedByOrganization = this.getResponseProperty("ManagedByOrganization") ?? false;
|
||||||
|
this.ssoExternalId = this.getResponseProperty("SsoExternalId");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user