mirror of
https://github.com/bitwarden/browser.git
synced 2024-12-22 16:29:09 +01:00
[SM-579] Prevent creating secret without project (#4892)
* Change project select to simple dropdown * Handle null
This commit is contained in:
parent
9fe79afa13
commit
f2276227aa
@ -1,14 +1,11 @@
|
|||||||
<!-- Please remove this disable statement when editing this file! -->
|
|
||||||
<!-- eslint-disable tailwindcss/no-custom-classname -->
|
|
||||||
<form [formGroup]="formGroup" [bitSubmit]="submit">
|
<form [formGroup]="formGroup" [bitSubmit]="submit">
|
||||||
<bit-dialog dialogSize="default" disablePadding>
|
<bit-dialog dialogSize="default">
|
||||||
<ng-container bitDialogTitle>{{ title | i18n }}</ng-container>
|
<ng-container bitDialogTitle>{{ title | i18n }}</ng-container>
|
||||||
<div bitDialogContent>
|
<div bitDialogContent>
|
||||||
<div *ngIf="loading" class="tw-text-center">
|
<div *ngIf="loading" class="tw-text-center">
|
||||||
<i class="bwi bwi-spinner bwi-spin bwi-3x"></i>
|
<i class="bwi bwi-spinner bwi-spin bwi-3x"></i>
|
||||||
</div>
|
</div>
|
||||||
<bit-tab-group *ngIf="!loading">
|
<ng-container *ngIf="!loading">
|
||||||
<bit-tab [label]="'nameValuePair' | i18n">
|
|
||||||
<div class="tw-flex tw-gap-4 tw-pt-4">
|
<div class="tw-flex tw-gap-4 tw-pt-4">
|
||||||
<bit-form-field class="tw-w-1/3">
|
<bit-form-field class="tw-w-1/3">
|
||||||
<bit-label for="secret-name">{{ "name" | i18n }}</bit-label>
|
<bit-label for="secret-name">{{ "name" | i18n }}</bit-label>
|
||||||
@ -23,49 +20,19 @@
|
|||||||
<bit-label>{{ "notes" | i18n }}</bit-label>
|
<bit-label>{{ "notes" | i18n }}</bit-label>
|
||||||
<textarea bitInput rows="4" formControlName="notes"></textarea>
|
<textarea bitInput rows="4" formControlName="notes"></textarea>
|
||||||
</bit-form-field>
|
</bit-form-field>
|
||||||
</bit-tab>
|
|
||||||
<bit-tab [label]="'projects' | i18n">
|
<hr />
|
||||||
<bit-label class="tw-text-md">{{
|
|
||||||
"secretProjectAssociationDescription" | i18n
|
|
||||||
}}</bit-label>
|
|
||||||
<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">
|
<select bitInput name="project" formControlName="project">
|
||||||
<option value="">{{ "selectPlaceholder" | i18n }}</option>
|
<option value="">{{ "selectPlaceholder" | i18n }}</option>
|
||||||
<option *ngFor="let f of projects" [value]="f.id" (change)="updateProjectList()">
|
<option *ngFor="let f of projects" [value]="f.id">
|
||||||
{{ f.name }}
|
{{ f.name }}
|
||||||
</option>
|
</option>
|
||||||
</select>
|
</select>
|
||||||
</bit-form-field>
|
</bit-form-field>
|
||||||
<small class="form-text text-muted tw-mb-6">{{ "selectProjects" | i18n }}</small>
|
|
||||||
|
|
||||||
<bit-table>
|
|
||||||
<ng-container header>
|
|
||||||
<tr>
|
|
||||||
<th bitCell>{{ "project" | i18n }}</th>
|
|
||||||
<th bitCell></th>
|
|
||||||
</tr>
|
|
||||||
</ng-container>
|
</ng-container>
|
||||||
<ng-template body *ngIf="selectedProjects != null">
|
|
||||||
<tr bitRow *ngFor="let e of selectedProjects">
|
|
||||||
<td bitCell class="tw-overflow-hidden tw-break-words tw-text-sm">
|
|
||||||
{{ e.name }}
|
|
||||||
</td>
|
|
||||||
<td bitCell class="tw-w-0">
|
|
||||||
<button
|
|
||||||
type="button"
|
|
||||||
(click)="removeProjectAssociation(e.id)"
|
|
||||||
bitIconButton="bwi-close"
|
|
||||||
buttonType="main"
|
|
||||||
[title]="'options' | i18n"
|
|
||||||
[attr.aria-label]="'options' | i18n"
|
|
||||||
></button>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
</ng-template>
|
|
||||||
</bit-table>
|
|
||||||
</bit-tab>
|
|
||||||
</bit-tab-group>
|
|
||||||
</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>
|
||||||
|
@ -1,14 +1,13 @@
|
|||||||
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, takeUntil } from "rxjs";
|
import { lastValueFrom, Subject } 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 { 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 { SecretProjectView } from "../../models/view/secret-project.view";
|
|
||||||
import { SecretView } from "../../models/view/secret.view";
|
import { SecretView } from "../../models/view/secret.view";
|
||||||
import { ProjectService } from "../../projects/project.service";
|
import { ProjectService } from "../../projects/project.service";
|
||||||
import { SecretService } from "../secret.service";
|
import { SecretService } from "../secret.service";
|
||||||
@ -36,12 +35,11 @@ export class SecretDialogComponent implements OnInit {
|
|||||||
name: new FormControl("", [Validators.required]),
|
name: new FormControl("", [Validators.required]),
|
||||||
value: new FormControl("", [Validators.required]),
|
value: new FormControl("", [Validators.required]),
|
||||||
notes: new FormControl(""),
|
notes: new FormControl(""),
|
||||||
project: new FormControl(""),
|
project: new FormControl("", [Validators.required]),
|
||||||
});
|
});
|
||||||
|
|
||||||
protected loading = false;
|
protected loading = false;
|
||||||
projects: ProjectListView[];
|
projects: ProjectListView[];
|
||||||
selectedProjects: SecretProjectView[] = [];
|
|
||||||
|
|
||||||
private destroy$ = new Subject<void>();
|
private destroy$ = new Subject<void>();
|
||||||
constructor(
|
constructor(
|
||||||
@ -66,11 +64,6 @@ export class SecretDialogComponent implements OnInit {
|
|||||||
throw new Error(`The secret dialog was not called with the appropriate operation values.`);
|
throw new Error(`The secret dialog was not called with the appropriate operation values.`);
|
||||||
}
|
}
|
||||||
|
|
||||||
this.formGroup
|
|
||||||
.get("project")
|
|
||||||
.valueChanges.pipe(takeUntil(this.destroy$))
|
|
||||||
.subscribe(() => this.updateProjectList());
|
|
||||||
|
|
||||||
if (this.data.projectId) {
|
if (this.data.projectId) {
|
||||||
this.formGroup.get("project").setValue(this.data.projectId);
|
this.formGroup.get("project").setValue(this.data.projectId);
|
||||||
}
|
}
|
||||||
@ -79,15 +72,13 @@ export class SecretDialogComponent implements OnInit {
|
|||||||
async loadData() {
|
async loadData() {
|
||||||
this.loading = true;
|
this.loading = true;
|
||||||
const secret: SecretView = await this.secretService.getBySecretId(this.data.secretId);
|
const secret: SecretView = await this.secretService.getBySecretId(this.data.secretId);
|
||||||
this.loading = false;
|
|
||||||
this.selectedProjects = secret.projects;
|
|
||||||
this.loading = false;
|
|
||||||
this.formGroup.setValue({
|
this.formGroup.setValue({
|
||||||
name: secret.name,
|
name: secret.name,
|
||||||
value: secret.value,
|
value: secret.value,
|
||||||
notes: secret.note,
|
notes: secret.note,
|
||||||
project: "",
|
project: secret.projects[0]?.id,
|
||||||
});
|
});
|
||||||
|
this.loading = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
ngOnDestroy(): void {
|
ngOnDestroy(): void {
|
||||||
@ -99,31 +90,6 @@ export class SecretDialogComponent implements OnInit {
|
|||||||
return this.data.operation === OperationType.Add ? "newSecret" : "editSecret";
|
return this.data.operation === OperationType.Add ? "newSecret" : "editSecret";
|
||||||
}
|
}
|
||||||
|
|
||||||
async removeProjectAssociation(id: string) {
|
|
||||||
this.selectedProjects = this.selectedProjects.filter((e) => e.id != id);
|
|
||||||
this.formGroup.get("project").setValue("");
|
|
||||||
}
|
|
||||||
|
|
||||||
updateProjectList() {
|
|
||||||
const newList: SecretProjectView[] = [];
|
|
||||||
const projectId = this.formGroup.get("project").value;
|
|
||||||
|
|
||||||
if (projectId) {
|
|
||||||
const selectedProject = this.projects?.filter((p) => p.id == projectId)[0];
|
|
||||||
|
|
||||||
if (selectedProject != undefined) {
|
|
||||||
const projectSecretView = new SecretProjectView();
|
|
||||||
|
|
||||||
projectSecretView.id = selectedProject.id;
|
|
||||||
projectSecretView.name = selectedProject.name;
|
|
||||||
|
|
||||||
newList.push(projectSecretView);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
this.selectedProjects = newList;
|
|
||||||
}
|
|
||||||
|
|
||||||
submit = async () => {
|
submit = async () => {
|
||||||
this.formGroup.markAllAsTouched();
|
this.formGroup.markAllAsTouched();
|
||||||
|
|
||||||
@ -172,14 +138,12 @@ export class SecretDialogComponent implements OnInit {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private getSecretView() {
|
private getSecretView() {
|
||||||
const emptyProjects: SecretProjectView[] = [];
|
|
||||||
|
|
||||||
const secretView = new SecretView();
|
const secretView = new SecretView();
|
||||||
secretView.organizationId = this.data.organizationId;
|
secretView.organizationId = this.data.organizationId;
|
||||||
secretView.name = this.formGroup.value.name;
|
secretView.name = this.formGroup.value.name;
|
||||||
secretView.value = this.formGroup.value.value;
|
secretView.value = this.formGroup.value.value;
|
||||||
secretView.note = this.formGroup.value.notes;
|
secretView.note = this.formGroup.value.notes;
|
||||||
secretView.projects = this.selectedProjects ? this.selectedProjects : emptyProjects;
|
secretView.projects = [this.projects.find((p) => p.id == this.formGroup.value.project)];
|
||||||
return secretView;
|
return secretView;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user