1
0
mirror of https://github.com/bitwarden/browser.git synced 2024-12-21 16:18:28 +01:00

[SM-401] Adding the ability to edit service account name (#4845)

* Adding the ability to edit service account name

* Update bitwarden_license/bit-web/src/app/secrets-manager/service-accounts/service-accounts-list.component.html

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

* Suggested Updates

* removing unecessary messages

* Adding back messages.json entry, updating API Call

* fix

* Update bitwarden_license/bit-web/src/app/secrets-manager/service-accounts/service-account.service.ts

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

* Update bitwarden_license/bit-web/src/app/secrets-manager/service-accounts/models/requests/service-account-update.request.ts

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

* Update bitwarden_license/bit-web/src/app/secrets-manager/service-accounts/dialog/service-account-dialog.component.ts

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

* Fixing endpoints after Server side change

* changes

* updates

* adding loading notification

* adding description to message

* Update bitwarden_license/bit-web/src/app/secrets-manager/service-accounts/service-accounts-list.component.html

Co-authored-by: Thomas Avery <43214426+Thomas-Avery@users.noreply.github.com>

* Thomas's suggested changes

* reorder list

---------

Co-authored-by: Oscar Hinton <Hinton@users.noreply.github.com>
Co-authored-by: Thomas Avery <43214426+Thomas-Avery@users.noreply.github.com>
This commit is contained in:
cd-bitwarden 2023-03-08 15:50:23 -05:00 committed by GitHub
parent da9210b551
commit 6971c3dca2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 118 additions and 11 deletions

View File

@ -5876,6 +5876,10 @@
"message": "Search service accounts", "message": "Search service accounts",
"description": "Placeholder text for searching service accounts." "description": "Placeholder text for searching service accounts."
}, },
"editServiceAccount":{
"message":"Edit service account",
"description" : "Title for editing a service account."
},
"addProject": { "addProject": {
"message": "Add project", "message": "Add project",
"description": "Title for creating a new project." "description": "Title for creating a new project."
@ -5933,6 +5937,10 @@
"message": "Service account created", "message": "Service account created",
"description": "Notifies that a new service account has been created" "description": "Notifies that a new service account has been created"
}, },
"serviceAccountUpdated": {
"message": "Service account updated",
"description": "Notifies that a service account has been updated"
},
"newSaSelectAccess": { "newSaSelectAccess": {
"message": "Type or select projects or secrets", "message": "Type or select projects or secrets",
"description": "Instructions for selecting projects or secrets for a new service account" "description": "Instructions for selecting projects or secrets for a new service account"

View File

@ -225,6 +225,7 @@ export class OverviewComponent implements OnInit, OnDestroy {
this.dialogService.open<unknown, ServiceAccountOperation>(ServiceAccountDialogComponent, { this.dialogService.open<unknown, ServiceAccountOperation>(ServiceAccountDialogComponent, {
data: { data: {
organizationId: this.organizationId, organizationId: this.organizationId,
operation: OperationType.Add,
}, },
}); });
} }

View File

@ -1,12 +1,17 @@
<form [formGroup]="formGroup" [bitSubmit]="submit"> <form [formGroup]="formGroup" [bitSubmit]="submit">
<bit-dialog dialogSize="small"> <bit-dialog dialogSize="small">
<ng-container bitDialogTitle>{{ "newServiceAccount" | i18n }}</ng-container> <ng-container bitDialogTitle>{{ title | i18n }}</ng-container>
<div bitDialogContent> <div bitDialogContent>
<div *ngIf="loading" class="tw-text-center">
<i class="bwi bwi-spinner bwi-spin bwi-3x"></i>
</div>
<div *ngIf="!loading">
<bit-form-field> <bit-form-field>
<bit-label>{{ "serviceAccountName" | i18n }}</bit-label> <bit-label>{{ "serviceAccountName" | i18n }}</bit-label>
<input formControlName="name" bitInput /> <input formControlName="name" maxlength="1000" bitInput />
</bit-form-field> </bit-form-field>
</div> </div>
</div>
<div bitDialogFooter class="tw-flex tw-gap-2"> <div bitDialogFooter class="tw-flex tw-gap-2">
<button type="submit" bitButton buttonType="primary" bitFormButton> <button type="submit" bitButton buttonType="primary" bitFormButton>
{{ "save" | i18n }} {{ "save" | i18n }}

View File

@ -8,8 +8,15 @@ import { PlatformUtilsService } from "@bitwarden/common/abstractions/platformUti
import { ServiceAccountView } from "../../models/view/service-account.view"; import { ServiceAccountView } from "../../models/view/service-account.view";
import { ServiceAccountService } from "../service-account.service"; import { ServiceAccountService } from "../service-account.service";
export enum OperationType {
Add,
Edit,
}
export interface ServiceAccountOperation { export interface ServiceAccountOperation {
organizationId: string; organizationId: string;
serviceAccountId?: string;
operation: OperationType;
} }
@Component({ @Component({
@ -21,6 +28,8 @@ export class ServiceAccountDialogComponent {
name: new FormControl("", [Validators.required]), name: new FormControl("", [Validators.required]),
}); });
protected loading = false;
constructor( constructor(
public dialogRef: DialogRef, public dialogRef: DialogRef,
@Inject(DIALOG_DATA) private data: ServiceAccountOperation, @Inject(DIALOG_DATA) private data: ServiceAccountOperation,
@ -29,6 +38,23 @@ export class ServiceAccountDialogComponent {
private platformUtilsService: PlatformUtilsService private platformUtilsService: PlatformUtilsService
) {} ) {}
async ngOnInit() {
if (this.data.operation == OperationType.Edit) {
this.loadData();
}
}
async loadData() {
this.loading = true;
const serviceAccount: ServiceAccountView =
await this.serviceAccountService.getByServiceAccountId(
this.data.serviceAccountId,
this.data.organizationId
);
this.formGroup.patchValue({ name: serviceAccount.name });
this.loading = false;
}
submit = async () => { submit = async () => {
this.formGroup.markAllAsTouched(); this.formGroup.markAllAsTouched();
@ -37,12 +63,21 @@ export class ServiceAccountDialogComponent {
} }
const serviceAccountView = this.getServiceAccountView(); const serviceAccountView = this.getServiceAccountView();
let serviceAccountMessage: string;
if (this.data.operation == OperationType.Add) {
await this.serviceAccountService.create(this.data.organizationId, serviceAccountView); await this.serviceAccountService.create(this.data.organizationId, serviceAccountView);
this.platformUtilsService.showToast( serviceAccountMessage = this.i18nService.t("serviceAccountCreated");
"success", } else {
null, await this.serviceAccountService.update(
this.i18nService.t("serviceAccountCreated") this.data.serviceAccountId,
this.data.organizationId,
serviceAccountView
); );
serviceAccountMessage = this.i18nService.t("serviceAccountUpdated");
}
this.platformUtilsService.showToast("success", null, serviceAccountMessage);
this.dialogRef.close(); this.dialogRef.close();
}; };
@ -52,4 +87,8 @@ export class ServiceAccountDialogComponent {
serviceAccountView.name = this.formGroup.value.name; serviceAccountView.name = this.formGroup.value.name;
return serviceAccountView; return serviceAccountView;
} }
get title() {
return this.data.operation === OperationType.Add ? "newServiceAccount" : "editServiceAccount";
}
} }

View File

@ -40,6 +40,41 @@ export class ServiceAccountService {
return await this.createServiceAccountViews(organizationId, results.data); return await this.createServiceAccountViews(organizationId, results.data);
} }
async getByServiceAccountId(
serviceAccountId: string,
organizationId: string
): Promise<ServiceAccountView> {
const orgKey = await this.getOrganizationKey(organizationId);
const r = await this.apiService.send(
"GET",
"/service-accounts/" + serviceAccountId,
null,
true,
true
);
return await this.createServiceAccountView(orgKey, new ServiceAccountResponse(r));
}
async update(
serviceAccountId: string,
organizationId: string,
serviceAccountView: ServiceAccountView
) {
const orgKey = await this.getOrganizationKey(organizationId);
const request = await this.getServiceAccountRequest(orgKey, serviceAccountView);
const r = await this.apiService.send(
"PUT",
"/service-accounts/" + serviceAccountId,
request,
true,
true
);
this._serviceAccount.next(
await this.createServiceAccountView(orgKey, new ServiceAccountResponse(r))
);
}
async create(organizationId: string, serviceAccountView: ServiceAccountView) { async create(organizationId: string, serviceAccountView: ServiceAccountView) {
const orgKey = await this.getOrganizationKey(organizationId); const orgKey = await this.getOrganizationKey(organizationId);
const request = await this.getServiceAccountRequest(orgKey, serviceAccountView); const request = await this.getServiceAccountRequest(orgKey, serviceAccountView);

View File

@ -83,6 +83,10 @@
<i class="bwi bwi-fw bwi-eye" aria-hidden="true"></i> <i class="bwi bwi-fw bwi-eye" aria-hidden="true"></i>
{{ "viewServiceAccount" | i18n }} {{ "viewServiceAccount" | i18n }}
</a> </a>
<button type="button" bitMenuItem (click)="editServiceAccountEvent.emit(serviceAccount.id)">
<i class="bwi bwi-fw bwi-pencil" aria-hidden="true"></i>
{{ "editServiceAccount" | i18n }}
</button>
<button type="button" bitMenuItem (click)="delete(serviceAccount)"> <button type="button" bitMenuItem (click)="delete(serviceAccount)">
<i class="bwi bwi-fw bwi-trash tw-text-danger" aria-hidden="true"></i> <i class="bwi bwi-fw bwi-trash tw-text-danger" aria-hidden="true"></i>
<span class="tw-text-danger"> <span class="tw-text-danger">

View File

@ -32,6 +32,7 @@ export class ServiceAccountsListComponent implements OnDestroy {
@Output() newServiceAccountEvent = new EventEmitter(); @Output() newServiceAccountEvent = new EventEmitter();
@Output() deleteServiceAccountsEvent = new EventEmitter<ServiceAccountView[]>(); @Output() deleteServiceAccountsEvent = new EventEmitter<ServiceAccountView[]>();
@Output() onServiceAccountCheckedEvent = new EventEmitter<string[]>(); @Output() onServiceAccountCheckedEvent = new EventEmitter<string[]>();
@Output() editServiceAccountEvent = new EventEmitter<string>();
private destroy$: Subject<void> = new Subject<void>(); private destroy$: Subject<void> = new Subject<void>();

View File

@ -5,6 +5,7 @@
<sm-service-accounts-list <sm-service-accounts-list
[serviceAccounts]="serviceAccounts$ | async" [serviceAccounts]="serviceAccounts$ | async"
(newServiceAccountEvent)="openNewServiceAccountDialog()" (newServiceAccountEvent)="openNewServiceAccountDialog()"
(editServiceAccountEvent)="openEditServiceAccountDialog($event)"
(deleteServiceAccountsEvent)="openDeleteDialog($event)" (deleteServiceAccountsEvent)="openDeleteDialog($event)"
[search]="search" [search]="search"
></sm-service-accounts-list> ></sm-service-accounts-list>

View File

@ -12,6 +12,7 @@ import {
ServiceAccountDeleteOperation, ServiceAccountDeleteOperation,
} from "./dialog/service-account-delete-dialog.component"; } from "./dialog/service-account-delete-dialog.component";
import { import {
OperationType,
ServiceAccountDialogComponent, ServiceAccountDialogComponent,
ServiceAccountOperation, ServiceAccountOperation,
} from "./dialog/service-account-dialog.component"; } from "./dialog/service-account-dialog.component";
@ -51,6 +52,17 @@ export class ServiceAccountsComponent implements OnInit {
this.dialogService.open<unknown, ServiceAccountOperation>(ServiceAccountDialogComponent, { this.dialogService.open<unknown, ServiceAccountOperation>(ServiceAccountDialogComponent, {
data: { data: {
organizationId: this.organizationId, organizationId: this.organizationId,
operation: OperationType.Add,
},
});
}
openEditServiceAccountDialog(serviceAccountId: string) {
this.dialogService.open<unknown, ServiceAccountOperation>(ServiceAccountDialogComponent, {
data: {
organizationId: this.organizationId,
serviceAccountId: serviceAccountId,
operation: OperationType.Edit,
}, },
}); });
} }

View File

@ -61,6 +61,7 @@ export class NewMenuComponent implements OnInit, OnDestroy {
this.dialogService.open<unknown, ServiceAccountOperation>(ServiceAccountDialogComponent, { this.dialogService.open<unknown, ServiceAccountOperation>(ServiceAccountDialogComponent, {
data: { data: {
organizationId: this.organizationId, organizationId: this.organizationId,
operation: OperationType.Add,
}, },
}); });
} }