mirror of
https://github.com/bitwarden/browser
synced 2025-12-10 13:23:34 +00:00
Add ability to create project during the secret creation flow (#5159)
* Add ability to create project during the secret creation flow * Removing unused code * Thoma's suggested changes * requested Changes by Thomas * Thoma's requested changes * lint fix after merge
This commit is contained in:
@@ -27,12 +27,21 @@
|
|||||||
|
|
||||||
<bit-form-field class="tw-mt-3 tw-mb-0">
|
<bit-form-field class="tw-mt-3 tw-mb-0">
|
||||||
<bit-label>{{ "project" | i18n }}</bit-label>
|
<bit-label>{{ "project" | i18n }}</bit-label>
|
||||||
<select bitInput name="project" formControlName="project">
|
<bit-select bitInput name="project" formControlName="project">
|
||||||
<option value="">{{ "selectPlaceholder" | i18n }}</option>
|
<bit-option value="" [label]="'selectPlaceholder' | i18n"></bit-option>
|
||||||
<option *ngFor="let f of projects" [value]="f.id">
|
<bit-option
|
||||||
{{ f.name }}
|
*ngFor="let p of projects"
|
||||||
</option>
|
[icon]="p.id === this.newProjectGuid ? 'bwi-plus-circle' : ''"
|
||||||
</select>
|
[value]="p.id"
|
||||||
|
[label]="p.name"
|
||||||
|
>
|
||||||
|
</bit-option>
|
||||||
|
</bit-select>
|
||||||
|
</bit-form-field>
|
||||||
|
|
||||||
|
<bit-form-field *ngIf="addNewProject == true">
|
||||||
|
<bit-label>{{ "projectName" | i18n }}</bit-label>
|
||||||
|
<input formControlName="newProjectName" maxlength="1000" bitInput />
|
||||||
</bit-form-field>
|
</bit-form-field>
|
||||||
</div>
|
</div>
|
||||||
<div bitDialogFooter class="tw-flex tw-gap-2">
|
<div bitDialogFooter class="tw-flex tw-gap-2">
|
||||||
|
|||||||
@@ -1,14 +1,16 @@
|
|||||||
import { DialogRef, DIALOG_DATA } from "@angular/cdk/dialog";
|
import { DialogRef, DIALOG_DATA } from "@angular/cdk/dialog";
|
||||||
import { Component, Inject, OnInit } from "@angular/core";
|
import { Component, Inject, OnInit } from "@angular/core";
|
||||||
import { FormControl, FormGroup, Validators } from "@angular/forms";
|
import { FormControl, FormGroup, Validators } from "@angular/forms";
|
||||||
import { lastValueFrom, Subject } from "rxjs";
|
import { lastValueFrom, Subject, takeUntil } from "rxjs";
|
||||||
|
|
||||||
import { I18nService } from "@bitwarden/common/abstractions/i18n.service";
|
import { I18nService } from "@bitwarden/common/abstractions/i18n.service";
|
||||||
import { PlatformUtilsService } from "@bitwarden/common/abstractions/platformUtils.service";
|
import { PlatformUtilsService } from "@bitwarden/common/abstractions/platformUtils.service";
|
||||||
import { OrganizationService } from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction";
|
import { OrganizationService } from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction";
|
||||||
|
import { Utils } from "@bitwarden/common/misc/utils";
|
||||||
import { DialogService } from "@bitwarden/components";
|
import { DialogService } from "@bitwarden/components";
|
||||||
|
|
||||||
import { ProjectListView } from "../../models/view/project-list.view";
|
import { ProjectListView } from "../../models/view/project-list.view";
|
||||||
|
import { ProjectView } from "../../models/view/project.view";
|
||||||
import { SecretListView } from "../../models/view/secret-list.view";
|
import { SecretListView } from "../../models/view/secret-list.view";
|
||||||
import { SecretProjectView } from "../../models/view/secret-project.view";
|
import { SecretProjectView } from "../../models/view/secret-project.view";
|
||||||
import { SecretView } from "../../models/view/secret.view";
|
import { SecretView } from "../../models/view/secret.view";
|
||||||
@@ -39,11 +41,14 @@ export class SecretDialogComponent implements OnInit {
|
|||||||
value: new FormControl("", [Validators.required]),
|
value: new FormControl("", [Validators.required]),
|
||||||
notes: new FormControl(""),
|
notes: new FormControl(""),
|
||||||
project: new FormControl("", [Validators.required]),
|
project: new FormControl("", [Validators.required]),
|
||||||
|
newProjectName: new FormControl(""),
|
||||||
});
|
});
|
||||||
|
|
||||||
private destroy$ = new Subject<void>();
|
private destroy$ = new Subject<void>();
|
||||||
private loading = true;
|
private loading = true;
|
||||||
projects: ProjectListView[];
|
projects: ProjectListView[];
|
||||||
|
addNewProject = false;
|
||||||
|
newProjectGuid = Utils.newGuid();
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
public dialogRef: DialogRef,
|
public dialogRef: DialogRef,
|
||||||
@@ -74,6 +79,10 @@ export class SecretDialogComponent implements OnInit {
|
|||||||
this.formGroup.get("project").removeValidators(Validators.required);
|
this.formGroup.get("project").removeValidators(Validators.required);
|
||||||
this.formGroup.get("project").updateValueAndValidity();
|
this.formGroup.get("project").updateValueAndValidity();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (this.data.projectId == null || this.data.projectId == "") {
|
||||||
|
this.addNewProjectOptionToProjectsDropDown();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async loadData() {
|
async loadData() {
|
||||||
@@ -87,6 +96,7 @@ export class SecretDialogComponent implements OnInit {
|
|||||||
value: secret.value,
|
value: secret.value,
|
||||||
notes: secret.note,
|
notes: secret.note,
|
||||||
project: secret.projects[0]?.id ?? "",
|
project: secret.projects[0]?.id ?? "",
|
||||||
|
newProjectName: "",
|
||||||
});
|
});
|
||||||
|
|
||||||
this.loading = false;
|
this.loading = false;
|
||||||
@@ -111,6 +121,32 @@ export class SecretDialogComponent implements OnInit {
|
|||||||
this.destroy$.complete();
|
this.destroy$.complete();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private addNewProjectOptionToProjectsDropDown() {
|
||||||
|
this.formGroup
|
||||||
|
.get("project")
|
||||||
|
.valueChanges.pipe(takeUntil(this.destroy$))
|
||||||
|
.subscribe((val: string) => {
|
||||||
|
this.dropDownSelected(val);
|
||||||
|
});
|
||||||
|
|
||||||
|
const addNewProject = new ProjectListView();
|
||||||
|
addNewProject.name = this.i18nService.t("newProject");
|
||||||
|
addNewProject.id = this.newProjectGuid;
|
||||||
|
this.projects.unshift(addNewProject);
|
||||||
|
}
|
||||||
|
|
||||||
|
private dropDownSelected(val: string) {
|
||||||
|
this.addNewProject = val == this.newProjectGuid;
|
||||||
|
|
||||||
|
if (this.addNewProject) {
|
||||||
|
this.formGroup.get("newProjectName").addValidators([Validators.required]);
|
||||||
|
} else {
|
||||||
|
this.formGroup.get("newProjectName").clearValidators();
|
||||||
|
}
|
||||||
|
|
||||||
|
this.formGroup.updateValueAndValidity();
|
||||||
|
}
|
||||||
|
|
||||||
get title() {
|
get title() {
|
||||||
return this.data.operation === OperationType.Add ? "newSecret" : "editSecret";
|
return this.data.operation === OperationType.Add ? "newSecret" : "editSecret";
|
||||||
}
|
}
|
||||||
@@ -127,6 +163,12 @@ export class SecretDialogComponent implements OnInit {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const secretView = this.getSecretView();
|
const secretView = this.getSecretView();
|
||||||
|
|
||||||
|
if (this.addNewProject) {
|
||||||
|
const newProject = await this.createProject(this.getNewProjectView());
|
||||||
|
secretView.projects = [newProject];
|
||||||
|
}
|
||||||
|
|
||||||
if (this.data.operation === OperationType.Add) {
|
if (this.data.operation === OperationType.Add) {
|
||||||
await this.createSecret(secretView);
|
await this.createSecret(secretView);
|
||||||
} else {
|
} else {
|
||||||
@@ -140,6 +182,10 @@ export class SecretDialogComponent implements OnInit {
|
|||||||
return this.data.operation === OperationType.Edit;
|
return this.data.operation === OperationType.Edit;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private async createProject(projectView: ProjectView) {
|
||||||
|
return await this.projectService.create(this.data.organizationId, projectView);
|
||||||
|
}
|
||||||
|
|
||||||
protected openDeleteSecretDialog() {
|
protected openDeleteSecretDialog() {
|
||||||
const secretListView: SecretListView[] = this.getSecretListView();
|
const secretListView: SecretListView[] = this.getSecretListView();
|
||||||
|
|
||||||
@@ -163,6 +209,13 @@ export class SecretDialogComponent implements OnInit {
|
|||||||
this.platformUtilsService.showToast("success", null, this.i18nService.t("secretCreated"));
|
this.platformUtilsService.showToast("success", null, this.i18nService.t("secretCreated"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private getNewProjectView() {
|
||||||
|
const projectView = new ProjectView();
|
||||||
|
projectView.organizationId = this.data.organizationId;
|
||||||
|
projectView.name = this.formGroup.value.newProjectName;
|
||||||
|
return projectView;
|
||||||
|
}
|
||||||
|
|
||||||
private async updateSecret(secretView: SecretView) {
|
private async updateSecret(secretView: SecretView) {
|
||||||
await this.secretService.update(this.data.organizationId, secretView);
|
await this.secretService.update(this.data.organizationId, secretView);
|
||||||
this.platformUtilsService.showToast("success", null, this.i18nService.t("secretEdited"));
|
this.platformUtilsService.showToast("success", null, this.i18nService.t("secretEdited"));
|
||||||
|
|||||||
@@ -1,6 +1,11 @@
|
|||||||
import { NgModule } from "@angular/core";
|
import { NgModule } from "@angular/core";
|
||||||
|
|
||||||
import { MultiSelectModule, SearchModule, NoItemsModule } from "@bitwarden/components";
|
import {
|
||||||
|
MultiSelectModule,
|
||||||
|
SearchModule,
|
||||||
|
SelectModule,
|
||||||
|
NoItemsModule,
|
||||||
|
} from "@bitwarden/components";
|
||||||
import { CoreOrganizationModule } from "@bitwarden/web-vault/app/admin-console/organizations/core";
|
import { CoreOrganizationModule } from "@bitwarden/web-vault/app/admin-console/organizations/core";
|
||||||
import { DynamicAvatarComponent } from "@bitwarden/web-vault/app/components/dynamic-avatar.component";
|
import { DynamicAvatarComponent } from "@bitwarden/web-vault/app/components/dynamic-avatar.component";
|
||||||
import { ProductSwitcherModule } from "@bitwarden/web-vault/app/layouts/product-switcher/product-switcher.module";
|
import { ProductSwitcherModule } from "@bitwarden/web-vault/app/layouts/product-switcher/product-switcher.module";
|
||||||
@@ -22,6 +27,7 @@ import { SecretsListComponent } from "./secrets-list.component";
|
|||||||
MultiSelectModule,
|
MultiSelectModule,
|
||||||
CoreOrganizationModule,
|
CoreOrganizationModule,
|
||||||
NoItemsModule,
|
NoItemsModule,
|
||||||
|
SelectModule,
|
||||||
DynamicAvatarComponent,
|
DynamicAvatarComponent,
|
||||||
SearchModule,
|
SearchModule,
|
||||||
],
|
],
|
||||||
@@ -37,6 +43,7 @@ import { SecretsListComponent } from "./secrets-list.component";
|
|||||||
ProjectsListComponent,
|
ProjectsListComponent,
|
||||||
SearchModule,
|
SearchModule,
|
||||||
SecretsListComponent,
|
SecretsListComponent,
|
||||||
|
SelectModule,
|
||||||
SharedModule,
|
SharedModule,
|
||||||
],
|
],
|
||||||
declarations: [
|
declarations: [
|
||||||
|
|||||||
Reference in New Issue
Block a user