1
0
mirror of https://github.com/bitwarden/browser synced 2025-12-12 06:13:38 +00:00

Full headers (#16184)

Co-authored-by: Daniel James Smith <2670567+djsmith85@users.noreply.github.com>
This commit is contained in:
Konrad
2025-09-16 16:53:36 +02:00
committed by GitHub
parent 59396f0262
commit d06d47e26a
12 changed files with 231 additions and 163 deletions

View File

@@ -1934,32 +1934,81 @@
"typeNote": { "typeNote": {
"message": "Note" "message": "Note"
}, },
"newItemHeader": { "newItemHeaderLogin": {
"message": "New $TYPE$", "message": "New Login",
"placeholders": { "description": "Header for new login item type"
"type": {
"content": "$1",
"example": "Login"
}
}
}, },
"editItemHeader": { "newItemHeaderCard": {
"message": "Edit $TYPE$", "message": "New Card",
"placeholders": { "description": "Header for new card item type"
"type": {
"content": "$1",
"example": "Login"
}
}
}, },
"viewItemHeader": { "newItemHeaderIdentity": {
"message": "View $TYPE$", "message": "New Identity",
"placeholders": { "description": "Header for new identity item type"
"type": { },
"content": "$1", "newItemHeaderNote": {
"example": "Login" "message": "New Note",
} "description": "Header for new note item type"
} },
"newItemHeaderSshKey": {
"message": "New SSH key",
"description": "Header for new SSH key item type"
},
"newItemHeaderTextSend": {
"message": "New Text Send",
"description": "Header for new text send"
},
"newItemHeaderFileSend": {
"message": "New File Send",
"description": "Header for new file send"
},
"editItemHeaderLogin": {
"message": "Edit Login",
"description": "Header for edit login item type"
},
"editItemHeaderCard": {
"message": "Edit Card",
"description": "Header for edit card item type"
},
"editItemHeaderIdentity": {
"message": "Edit Identity",
"description": "Header for edit identity item type"
},
"editItemHeaderNote": {
"message": "Edit Note",
"description": "Header for edit note item type"
},
"editItemHeaderSshKey": {
"message": "Edit SSH key",
"description": "Header for edit SSH key item type"
},
"editItemHeaderTextSend": {
"message": "Edit Text Send",
"description": "Header for edit text send"
},
"editItemHeaderFileSend": {
"message": "Edit File Send",
"description": "Header for edit file send"
},
"viewItemHeaderLogin": {
"message": "View Login",
"description": "Header for view login item type"
},
"viewItemHeaderCard": {
"message": "View Card",
"description": "Header for view card item type"
},
"viewItemHeaderIdentity": {
"message": "View Identity",
"description": "Header for view identity item type"
},
"viewItemHeaderNote": {
"message": "View Note",
"description": "Header for view note item type"
},
"viewItemHeaderSshKey": {
"message": "View SSH key",
"description": "Header for view SSH key item type"
}, },
"passwordHistory": { "passwordHistory": {
"message": "Password history" "message": "Password history"
@@ -5092,15 +5141,9 @@
"itemLocation": { "itemLocation": {
"message": "Item Location" "message": "Item Location"
}, },
"fileSend": {
"message": "File Send"
},
"fileSends": { "fileSends": {
"message": "File Sends" "message": "File Sends"
}, },
"textSend": {
"message": "Text Send"
},
"textSends": { "textSends": {
"message": "Text Sends" "message": "Text Sends"
}, },

View File

@@ -188,14 +188,11 @@ export class SendAddEditComponent {
* @returns The header text. * @returns The header text.
*/ */
private getHeaderText(mode: SendFormMode, type: SendType) { private getHeaderText(mode: SendFormMode, type: SendType) {
const headerKey = const isEditMode = mode === "edit" || mode === "partial-edit";
mode === "edit" || mode === "partial-edit" ? "editItemHeader" : "newItemHeader"; const translation = {
[SendType.Text]: isEditMode ? "editItemHeaderTextSend" : "newItemHeaderTextSend",
switch (type) { [SendType.File]: isEditMode ? "editItemHeaderFileSend" : "newItemHeaderFileSend",
case SendType.Text: };
return this.i18nService.t(headerKey, this.i18nService.t("textSend")); return this.i18nService.t(translation[type]);
case SendType.File:
return this.i18nService.t(headerKey, this.i18nService.t("fileSend"));
}
} }
} }

View File

@@ -368,20 +368,15 @@ export class AddEditV2Component implements OnInit {
} }
setHeader(mode: CipherFormMode, type: CipherType) { setHeader(mode: CipherFormMode, type: CipherType) {
const partOne = mode === "edit" || mode === "partial-edit" ? "editItemHeader" : "newItemHeader"; const isEditMode = mode === "edit" || mode === "partial-edit";
const translation = {
switch (type) { [CipherType.Login]: isEditMode ? "editItemHeaderLogin" : "newItemHeaderLogin",
case CipherType.Login: [CipherType.Card]: isEditMode ? "editItemHeaderCard" : "newItemHeaderCard",
return this.i18nService.t(partOne, this.i18nService.t("typeLogin")); [CipherType.Identity]: isEditMode ? "editItemHeaderIdentity" : "newItemHeaderIdentity",
case CipherType.Card: [CipherType.SecureNote]: isEditMode ? "editItemHeaderNote" : "newItemHeaderNote",
return this.i18nService.t(partOne, this.i18nService.t("typeCard")); [CipherType.SshKey]: isEditMode ? "editItemHeaderSshKey" : "newItemHeaderSshKey",
case CipherType.Identity: };
return this.i18nService.t(partOne, this.i18nService.t("typeIdentity")); return this.i18nService.t(translation[type]);
case CipherType.SecureNote:
return this.i18nService.t(partOne, this.i18nService.t("note"));
case CipherType.SshKey:
return this.i18nService.t(partOne, this.i18nService.t("typeSshKey"));
}
} }
delete = async () => { delete = async () => {

View File

@@ -172,28 +172,28 @@ describe("ViewV2Component", () => {
params$.next({ cipherId: mockCipher.id }); params$.next({ cipherId: mockCipher.id });
flush(); // Resolve all promises flush(); // Resolve all promises
expect(component.headerText).toEqual("viewItemHeader typeLogin"); expect(component.headerText).toEqual("viewItemHeaderLogin");
// Set header text for a card // Set header text for a card
mockCipher.type = CipherType.Card; mockCipher.type = CipherType.Card;
params$.next({ cipherId: mockCipher.id }); params$.next({ cipherId: mockCipher.id });
flush(); // Resolve all promises flush(); // Resolve all promises
expect(component.headerText).toEqual("viewItemHeader typeCard"); expect(component.headerText).toEqual("viewItemHeaderCard");
// Set header text for an identity // Set header text for an identity
mockCipher.type = CipherType.Identity; mockCipher.type = CipherType.Identity;
params$.next({ cipherId: mockCipher.id }); params$.next({ cipherId: mockCipher.id });
flush(); // Resolve all promises flush(); // Resolve all promises
expect(component.headerText).toEqual("viewItemHeader typeIdentity"); expect(component.headerText).toEqual("viewItemHeaderIdentity");
// Set header text for a secure note // Set header text for a secure note
mockCipher.type = CipherType.SecureNote; mockCipher.type = CipherType.SecureNote;
params$.next({ cipherId: mockCipher.id }); params$.next({ cipherId: mockCipher.id });
flush(); // Resolve all promises flush(); // Resolve all promises
expect(component.headerText).toEqual("viewItemHeader note"); expect(component.headerText).toEqual("viewItemHeaderNote");
})); }));
it("sends viewed event", fakeAsync(() => { it("sends viewed event", fakeAsync(() => {

View File

@@ -194,18 +194,14 @@ export class ViewV2Component {
} }
setHeader(type: CipherType) { setHeader(type: CipherType) {
switch (type) { const translation = {
case CipherType.Login: [CipherType.Login]: "viewItemHeaderLogin",
return this.i18nService.t("viewItemHeader", this.i18nService.t("typeLogin")); [CipherType.Card]: "viewItemHeaderCard",
case CipherType.Card: [CipherType.Identity]: "viewItemHeaderIdentity",
return this.i18nService.t("viewItemHeader", this.i18nService.t("typeCard")); [CipherType.SecureNote]: "viewItemHeaderNote",
case CipherType.Identity: [CipherType.SshKey]: "viewItemHeaderSshKey",
return this.i18nService.t("viewItemHeader", this.i18nService.t("typeIdentity")); };
case CipherType.SecureNote: return this.i18nService.t(translation[type]);
return this.i18nService.t("viewItemHeader", this.i18nService.t("note"));
case CipherType.SshKey:
return this.i18nService.t("viewItemHeader", this.i18nService.t("typeSshkey"));
}
} }
async getCipherData(id: string, userId: UserId) { async getCipherData(id: string, userId: UserId) {

View File

@@ -134,7 +134,7 @@ describe("EmergencyViewDialogComponent", () => {
component["updateTitle"](); component["updateTitle"]();
expect(component["title"]).toBe("viewItemType typelogin"); expect(component["title"]).toBe("viewItemHeaderLogin");
}); });
it("sets card title", () => { it("sets card title", () => {
@@ -142,7 +142,7 @@ describe("EmergencyViewDialogComponent", () => {
component["updateTitle"](); component["updateTitle"]();
expect(component["title"]).toBe("viewItemType typecard"); expect(component["title"]).toBe("viewItemHeaderCard");
}); });
it("sets identity title", () => { it("sets identity title", () => {
@@ -150,7 +150,7 @@ describe("EmergencyViewDialogComponent", () => {
component["updateTitle"](); component["updateTitle"]();
expect(component["title"]).toBe("viewItemType typeidentity"); expect(component["title"]).toBe("viewItemHeaderIdentity");
}); });
it("sets note title", () => { it("sets note title", () => {
@@ -158,7 +158,7 @@ describe("EmergencyViewDialogComponent", () => {
component["updateTitle"](); component["updateTitle"]();
expect(component["title"]).toBe("viewItemType note"); expect(component["title"]).toBe("viewItemHeaderNote");
}); });
}); });
}); });

View File

@@ -73,22 +73,20 @@ export class EmergencyViewDialogComponent {
}; };
private updateTitle() { private updateTitle() {
const partOne = "viewItemType";
const type = this.cipher.type; const type = this.cipher.type;
switch (type) { switch (type) {
case CipherType.Login: case CipherType.Login:
this.title = this.i18nService.t(partOne, this.i18nService.t("typeLogin").toLowerCase()); this.title = this.i18nService.t("viewItemHeaderLogin");
break; break;
case CipherType.Card: case CipherType.Card:
this.title = this.i18nService.t(partOne, this.i18nService.t("typeCard").toLowerCase()); this.title = this.i18nService.t("viewItemHeaderCard");
break; break;
case CipherType.Identity: case CipherType.Identity:
this.title = this.i18nService.t(partOne, this.i18nService.t("typeIdentity").toLowerCase()); this.title = this.i18nService.t("viewItemHeaderIdentity");
break; break;
case CipherType.SecureNote: case CipherType.SecureNote:
this.title = this.i18nService.t(partOne, this.i18nService.t("note").toLowerCase()); this.title = this.i18nService.t("viewItemHeaderNote");
break; break;
} }
} }

View File

@@ -521,36 +521,39 @@ export class VaultItemDialogComponent implements OnInit, OnDestroy {
return await this.cipherService.decrypt(config.originalCipher, activeUserId); return await this.cipherService.decrypt(config.originalCipher, activeUserId);
} }
private updateTitle() { private updateTitle(): void {
let partOne: string; const mode = this.formConfig.mode || this.params.mode;
const type = this.cipher?.type ?? this.formConfig.cipherType;
const translation: { [key: string]: { [key: number]: string } } = {
view: {
[CipherType.Login]: "viewItemHeaderLogin",
[CipherType.Card]: "viewItemHeaderCard",
[CipherType.Identity]: "viewItemHeaderIdentity",
[CipherType.SecureNote]: "viewItemHeaderNote",
[CipherType.SshKey]: "viewItemHeaderSshKey",
},
new: {
[CipherType.Login]: "newItemHeaderLogin",
[CipherType.Card]: "newItemHeaderCard",
[CipherType.Identity]: "newItemHeaderIdentity",
[CipherType.SecureNote]: "newItemHeaderNote",
[CipherType.SshKey]: "newItemHeaderSshKey",
},
edit: {
[CipherType.Login]: "editItemHeaderLogin",
[CipherType.Card]: "editItemHeaderCard",
[CipherType.Identity]: "editItemHeaderIdentity",
[CipherType.SecureNote]: "editItemHeaderNote",
[CipherType.SshKey]: "editItemHeaderSshKey",
},
};
if (this.params.mode === "view") { const effectiveMode =
partOne = "viewItemType"; mode === "partial-edit" || mode === "edit" ? "edit" : translation[mode] ? mode : "new";
} else if (this.formConfig.mode === "edit" || this.formConfig.mode === "partial-edit") {
partOne = "editItemHeader";
} else {
partOne = "newItemHeader";
}
const type = this.cipher?.type ?? this.formConfig.cipherType ?? CipherType.Login; const fullTranslation = translation[effectiveMode][type];
switch (type) { this.title = this.i18nService.t(fullTranslation);
case CipherType.Login:
this.title = this.i18nService.t(partOne, this.i18nService.t("typeLogin"));
break;
case CipherType.Card:
this.title = this.i18nService.t(partOne, this.i18nService.t("typeCard"));
break;
case CipherType.Identity:
this.title = this.i18nService.t(partOne, this.i18nService.t("typeIdentity"));
break;
case CipherType.SecureNote:
this.title = this.i18nService.t(partOne, this.i18nService.t("note"));
break;
case CipherType.SshKey:
this.title = this.i18nService.t(partOne, this.i18nService.t("typeSshKey"));
break;
}
} }
/** /**

View File

@@ -138,19 +138,15 @@ export class AddEditComponentV2 implements OnInit {
* @returns The header text. * @returns The header text.
*/ */
setHeader(mode: CipherFormMode, type: CipherType) { setHeader(mode: CipherFormMode, type: CipherType) {
const partOne = mode === "edit" || mode === "partial-edit" ? "editItemHeader" : "newItemHeader"; const isEditMode = mode === "edit" || mode === "partial-edit";
switch (type) { const translation = {
case CipherType.Login: [CipherType.Login]: isEditMode ? "editItemHeaderLogin" : "newItemHeaderLogin",
return this.i18nService.t(partOne, this.i18nService.t("typeLogin").toLowerCase()); [CipherType.Card]: isEditMode ? "editItemHeaderCard" : "newItemHeaderCard",
case CipherType.Card: [CipherType.Identity]: isEditMode ? "editItemHeaderIdentity" : "newItemHeaderIdentity",
return this.i18nService.t(partOne, this.i18nService.t("typeCard").toLowerCase()); [CipherType.SecureNote]: isEditMode ? "editItemHeaderNote" : "newItemHeaderNote",
case CipherType.Identity: [CipherType.SshKey]: isEditMode ? "editItemHeaderSshKey" : "newItemHeaderSshKey",
return this.i18nService.t(partOne, this.i18nService.t("typeIdentity").toLowerCase()); };
case CipherType.SecureNote: return this.i18nService.t(translation[type]);
return this.i18nService.t(partOne, this.i18nService.t("note").toLowerCase());
case CipherType.SshKey:
return this.i18nService.t(partOne, this.i18nService.t("typeSshKey").toLowerCase());
}
} }
/** /**

View File

@@ -194,15 +194,15 @@ export class ViewComponent implements OnInit {
switch (this.cipher.type) { switch (this.cipher.type) {
case CipherType.Login: case CipherType.Login:
return this.i18nService.t("viewItemType", this.i18nService.t("typeLogin").toLowerCase()); return this.i18nService.t("viewItemHeaderLogin");
case CipherType.SecureNote: case CipherType.SecureNote:
return this.i18nService.t("viewItemType", this.i18nService.t("note").toLowerCase()); return this.i18nService.t("viewItemHeaderCard");
case CipherType.Card: case CipherType.Card:
return this.i18nService.t("viewItemType", this.i18nService.t("typeCard").toLowerCase()); return this.i18nService.t("viewItemHeaderIdentity");
case CipherType.Identity: case CipherType.Identity:
return this.i18nService.t("viewItemType", this.i18nService.t("typeIdentity").toLowerCase()); return this.i18nService.t("viewItemHeaderNote");
case CipherType.SshKey: case CipherType.SshKey:
return this.i18nService.t("viewItemType", this.i18nService.t("typeSshKey").toLowerCase()); return this.i18nService.t("viewItemHeaderSshKey");
default: default:
return null; return null;
} }

View File

@@ -734,32 +734,81 @@
"viewItem": { "viewItem": {
"message": "View item" "message": "View item"
}, },
"newItemHeader": { "newItemHeaderLogin": {
"message": "New $TYPE$", "message": "New Login",
"placeholders": { "description": "Header for new login item type"
"type": {
"content": "$1",
"example": "login"
}
}
}, },
"editItemHeader": { "newItemHeaderCard": {
"message": "Edit $TYPE$", "message": "New Card",
"placeholders": { "description": "Header for new card item type"
"type": {
"content": "$1",
"example": "login"
}
}
}, },
"viewItemType": { "newItemHeaderIdentity": {
"message": "View $ITEMTYPE$", "message": "New Identity",
"placeholders": { "description": "Header for new identity item type"
"itemtype": { },
"content": "$1", "newItemHeaderNote": {
"example": "login" "message": "New Note",
} "description": "Header for new note item type"
} },
"newItemHeaderSshKey": {
"message": "New SSH key",
"description": "Header for new SSH key item type"
},
"newItemHeaderTextSend": {
"message": "New Text Send",
"description": "Header for new text send"
},
"newItemHeaderFileSend": {
"message": "New File Send",
"description": "Header for new file send"
},
"editItemHeaderLogin": {
"message": "Edit Login",
"description": "Header for edit login item type"
},
"editItemHeaderCard": {
"message": "Edit Card",
"description": "Header for edit card item type"
},
"editItemHeaderIdentity": {
"message": "Edit Identity",
"description": "Header for edit identity item type"
},
"editItemHeaderNote": {
"message": "Edit Note",
"description": "Header for edit note item type"
},
"editItemHeaderSshKey": {
"message": "Edit SSH key",
"description": "Header for edit SSH key item type"
},
"editItemHeaderTextSend": {
"message": "Edit Text Send",
"description": "Header for edit text send"
},
"editItemHeaderFileSend": {
"message": "Edit File Send",
"description": "Header for edit file send"
},
"viewItemHeaderLogin": {
"message": "View Login",
"description": "Header for view login item type"
},
"viewItemHeaderCard": {
"message": "View Card",
"description": "Header for view card item type"
},
"viewItemHeaderIdentity": {
"message": "View Identity",
"description": "Header for view identity item type"
},
"viewItemHeaderNote": {
"message": "View Note",
"description": "Header for view note item type"
},
"viewItemHeaderSshKey": {
"message": "View SSH key",
"description": "Header for view SSH key item type"
}, },
"new": { "new": {
"message": "New", "message": "New",
@@ -10217,15 +10266,9 @@
"learnMoreAboutApi": { "learnMoreAboutApi": {
"message": "Learn more about Bitwarden's API" "message": "Learn more about Bitwarden's API"
}, },
"fileSend": {
"message": "File Send"
},
"fileSends": { "fileSends": {
"message": "File Sends" "message": "File Sends"
}, },
"textSend": {
"message": "Text Send"
},
"textSends": { "textSends": {
"message": "Text Sends" "message": "Text Sends"
}, },

View File

@@ -153,15 +153,12 @@ export class SendAddEditDialogComponent {
* @returns The header text. * @returns The header text.
*/ */
private getHeaderText(mode: SendFormMode, type: SendType) { private getHeaderText(mode: SendFormMode, type: SendType) {
const headerKey = const isEditMode = mode === "edit" || mode === "partial-edit";
mode === "edit" || mode === "partial-edit" ? "editItemHeader" : "newItemHeader"; const translation = {
[SendType.Text]: isEditMode ? "editItemHeaderTextSend" : "newItemHeaderTextSend",
switch (type) { [SendType.File]: isEditMode ? "editItemHeaderFileSend" : "newItemHeaderFileSend",
case SendType.Text: };
return this.i18nService.t(headerKey, this.i18nService.t("textSend")); return this.i18nService.t(translation[type]);
case SendType.File:
return this.i18nService.t(headerKey, this.i18nService.t("fileSend"));
}
} }
/** /**