Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add inline menu basics #221

Merged
merged 14 commits into from
Jul 31, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions apps/browser/src/_locales/en/messages.json
Original file line number Diff line number Diff line change
Expand Up @@ -4011,5 +4011,17 @@
},
"cipherContactMe": {
"message": "me"
},
"contactSearch": {
"message": "Search\u2026"
},
"empty_ambiguous_email": {
"message": "No email found"
},
"empty_ambiguous_phone": {
"message": "No phone found"
},
"empty_ambiguous_address": {
"message": "No address found"
}
}
12 changes: 12 additions & 0 deletions apps/browser/src/_locales/fr/messages.json
Original file line number Diff line number Diff line change
Expand Up @@ -3973,5 +3973,17 @@
},
"cipherContactMe": {
"message": "moi"
},
"contactSearch": {
"message": "Recherche\u2026"
},
"empty_ambiguous_email": {
"message": "Aucun email trouvé"
},
"empty_ambiguous_phone": {
"message": "Aucun téléphone trouvé"
},
"empty_ambiguous_address": {
"message": "Aucune adresse trouvée"
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import { LockedVaultPendingNotificationsData } from "./notification.background";
/* start Cozy imports */
/* eslint-disable */
import { AutofillFieldQualifierType } from "src/autofill/enums/autofill-field.enums";
import { AmbiguousContactFieldValue } from "src/autofill/types";
/* eslint-enable */
/* end Cozy imports */

Expand Down Expand Up @@ -139,6 +140,10 @@ export type OverlayPortMessage = {
direction?: string;
inlineMenuCipherId?: string;
addNewCipherType?: CipherType;
// Cozy customization;
fieldQualifier?: AutofillFieldQualifierType;
ambiguousValue?: AmbiguousContactFieldValue[0];
// Cozy customization end
};

export type InlineMenuCipherData = {
Expand Down Expand Up @@ -244,6 +249,13 @@ export type InlineMenuListPortMessageHandlers = {
autofillInlineMenuBlurred: () => void;
unlockVault: ({ port }: PortConnectionParam) => void;
fillAutofillInlineMenuCipher: ({ message, port }: PortOnMessageHandlerParams) => void;
// Cozy customization; fill ambiguous contact
handleContactClick: ({ message, port }: PortOnMessageHandlerParams) => void;
fillAutofillInlineMenuCipherWithAmbiguousField: ({
message,
port,
}: PortOnMessageHandlerParams) => void;
// Cozy customization end
addNewVaultItem: ({ message, port }: PortOnMessageHandlerParams) => void;
viewSelectedCipher: ({ message, port }: PortOnMessageHandlerParams) => void;
redirectAutofillInlineMenuFocusOut: ({ message, port }: PortOnMessageHandlerParams) => void;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ import { CipherView } from "@bitwarden/common/vault/models/view/cipher.view";

import { BrowserApi } from "../../platform/browser/browser-api";
import { BrowserPlatformUtilsService } from "../../platform/services/platform-utils/browser-platform-utils.service";
import { CozyClientService } from "../../popup/services/cozyClient.service";
import {
AutofillOverlayElement,
AutofillOverlayPort,
Expand Down Expand Up @@ -87,6 +88,7 @@ describe("OverlayBackground", () => {
let platformUtilsService: MockProxy<BrowserPlatformUtilsService>;
let selectedThemeMock$: BehaviorSubject<ThemeType>;
let themeStateService: MockProxy<ThemeStateService>;
let cozyClientService: MockProxy<CozyClientService>;
let overlayBackground: OverlayBackground;
let portKeyForTabSpy: Record<number, string>;
let pageDetailsForTabSpy: PageDetailsForTab;
Expand Down Expand Up @@ -165,6 +167,7 @@ describe("OverlayBackground", () => {
i18nService,
platformUtilsService,
themeStateService,
cozyClientService,
);
portKeyForTabSpy = overlayBackground["portKeyForTab"];
pageDetailsForTabSpy = overlayBackground["pageDetailsForTab"];
Expand Down
107 changes: 106 additions & 1 deletion apps/browser/src/autofill/background/overlay.background.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,12 @@ import {
MAX_SUB_FRAME_DEPTH,
} from "../enums/autofill-overlay.enum";
import { AutofillService } from "../services/abstractions/autofill.service";
import { generateRandomChars } from "../utils";
import {
ambiguousContactFieldNames,
bitwardenToCozy,
generateRandomChars,
getAmbiguousFieldsContact,
} from "../utils";

import { LockedVaultPendingNotificationsData } from "./abstractions/notification.background";
import {
Expand All @@ -64,7 +69,13 @@ import {

/* start Cozy imports */
/* eslint-disable */
import { Q } from "cozy-client";
import { IOCozyContact } from "cozy-client/types/types";
// @ts-ignore
import { CONTACTS_DOCTYPE } from "cozy-client/dist/models/contact";
import { nameToColor } from "cozy-ui/transpiled/react/Avatar/helpers";
import { CozyClientService } from "../../popup/services/cozyClient.service";
import { AmbiguousContactFieldValue } from "src/autofill/types";
/* eslint-enable */
/* end Cozy imports */

Expand Down Expand Up @@ -149,6 +160,11 @@ export class OverlayBackground implements OverlayBackgroundInterface {
autofillInlineMenuBlurred: () => this.checkInlineMenuButtonFocused(),
unlockVault: ({ port }) => this.unlockVault(port),
fillAutofillInlineMenuCipher: ({ message, port }) => this.fillInlineMenuCipher(message, port),
// Cozy customization
handleContactClick: ({ message, port }) => this.handleContactClick(message, port),
fillAutofillInlineMenuCipherWithAmbiguousField: ({ message, port }) =>
this.fillAutofillInlineMenuCipherWithAmbiguousField(message, port),
// Cozy customization end
addNewVaultItem: ({ message, port }) => this.getNewVaultItemDetails(message, port),
viewSelectedCipher: ({ message, port }) => this.viewSelectedCipher(message, port),
redirectAutofillInlineMenuFocusOut: ({ message, port }) =>
Expand All @@ -167,6 +183,7 @@ export class OverlayBackground implements OverlayBackgroundInterface {
private i18nService: I18nService,
private platformUtilsService: PlatformUtilsService,
private themeStateService: ThemeStateService,
private cozyClientService: CozyClientService,
) {
this.initOverlayEventObservables();
}
Expand Down Expand Up @@ -775,6 +792,8 @@ export class OverlayBackground implements OverlayBackgroundInterface {
private async fillInlineMenuCipher(
{ inlineMenuCipherId }: OverlayPortMessage,
{ sender }: chrome.runtime.Port,
ambiguousValue?: AmbiguousContactFieldValue[0],
fieldHtmlIDToFill?: string,
) {
const pageDetails = this.pageDetailsForTab[sender.tab.id];
if (!inlineMenuCipherId || !pageDetails?.size) {
Expand All @@ -792,6 +811,8 @@ export class OverlayBackground implements OverlayBackgroundInterface {
pageDetails: Array.from(pageDetails.values()),
fillNewPassword: true,
allowTotpAutofill: true,
...(ambiguousValue ? { cozyProfile: ambiguousValue } : {}),
...(fieldHtmlIDToFill ? { fillOnlyThisFieldHtmlID: fieldHtmlIDToFill } : {}),
});

// Cozy customization
Expand All @@ -805,6 +826,83 @@ export class OverlayBackground implements OverlayBackgroundInterface {
this.inlineMenuCiphers = new Map([[inlineMenuCipherId, cipher], ...this.inlineMenuCiphers]);
}

private async fillAutofillInlineMenuCipherWithAmbiguousField(
message: OverlayPortMessage,
port: chrome.runtime.Port,
) {
const { ambiguousValue, fieldHtmlIDToFill } = message;
this.fillInlineMenuCipher(message, port, ambiguousValue, fieldHtmlIDToFill);
}

/**
* @param inlineMenuCipherId - Cipher ID corresponding to the inlineMenuCiphers map. Does not correspond to the actual cipher's ID.
* @param sender - The sender of the port message
*/
private async handleContactClick(message: OverlayPortMessage, port: chrome.runtime.Port) {
const { inlineMenuCipherId, fieldHtmlIDToFill } = message;
const client = await this.cozyClientService.getClientInstance();
const cipher = this.inlineMenuCiphers.get(inlineMenuCipherId);

// FIXME: Temporary way to query data. We want to avoid online request.
const { data: contact } = (await client.fetchQueryAndGetFromState({
Merkur39 marked this conversation as resolved.
Show resolved Hide resolved
definition: Q(CONTACTS_DOCTYPE).getById(cipher.id),
options: {
as: `${CONTACTS_DOCTYPE}/${cipher.id}`,
singleDocData: true,
},
})) as { data: IOCozyContact };

const ambiguousContactFields = getAmbiguousFieldsContact(ambiguousContactFieldNames, contact);

const isFocusedFieldAmbigous = ambiguousContactFieldNames.includes(
bitwardenToCozy[this.focusedFieldData?.fieldQualifier],
);
const hasMultipleAmbiguousValueInSameField = Object.values(ambiguousContactFields).some(
(item) => item.length > 1,
);
const currentAmbiguousFieldValue =
ambiguousContactFields[bitwardenToCozy[this.focusedFieldData?.fieldQualifier]];

// On an ambiguous form field, the associated contact values are kept.
const ambiguousFormFieldsOfFocusedField = Object.fromEntries(
Object.entries(ambiguousContactFields).filter(
([fieldName]) => fieldName === bitwardenToCozy[this.focusedFieldData?.fieldQualifier],
),
);
// On an unambiguous form field, we keep only the multiple values of an ambiguous contact field.
const unambiguousFormFieldsOfFocusedField = Object.fromEntries(
Object.entries(ambiguousContactFields).filter(
([, fieldValue]) => Array.isArray(fieldValue) && fieldValue.length > 1,
),
);

/*
On a form field other than ambiguous(phone/address/email):
- If the contact has one or less ambiguous value: autofill everything.
- If the contact has more than one ambiguous values: display a menu to choose which one.
On the ambiguous(phone/address/email) form field:
- If contact has one or less ambiguous value: display list with phone/address/email.
- If the contact has more than one ambiguous values: display list with the phone/address/email.
*/
if (
(!isFocusedFieldAmbigous && hasMultipleAmbiguousValueInSameField) ||
(isFocusedFieldAmbigous && currentAmbiguousFieldValue?.length > 0) // TODO Part_2 Remove "currentAmbiguousFieldValue?.length > 0" condition
) {
this.inlineMenuListPort?.postMessage({
command: "ambiguousFieldList",
inlineMenuCipherId,
contactName: contact.displayName,
ambiguousFields: isFocusedFieldAmbigous
? ambiguousFormFieldsOfFocusedField
: unambiguousFormFieldsOfFocusedField,
isFocusedFieldAmbigous,
fieldHtmlIDToFill,
});
} else {
this.fillInlineMenuCipher(message, port);
}
}

/**
* Checks if the inline menu is focused. Will check the inline menu list
* if it is open, otherwise it will check the inline menu button.
Expand Down Expand Up @@ -1377,6 +1475,13 @@ export class OverlayBackground implements OverlayBackgroundInterface {
addNewIdentityItem: this.i18nService.translate("addNewIdentityItem"),
cardNumberEndsWith: this.i18nService.translate("cardNumberEndsWith"),
cipherContactMe: this.i18nService.translate("cipherContactMe"),
home: this.i18nService.translate("home"),
work: this.i18nService.translate("work"),
cell: this.i18nService.translate("cell"),
contactSearch: this.i18nService.translate("contactSearch"),
empty_ambiguous_email: this.i18nService.translate("empty_ambiguous_email"),
empty_ambiguous_phone: this.i18nService.translate("empty_ambiguous_phone"),
empty_ambiguous_address: this.i18nService.translate("empty_ambiguous_address"),
};
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { InlineMenuCipherData } from "../../../background/abstractions/overlay.b

/* start Cozy imports */
/* eslint-disable */
import { AmbiguousContactFields } from "src/autofill/types";
import { AutofillFieldQualifierType } from "src/autofill/enums/autofill-field.enums";
/* eslint-enable */
/* end Cozy imports */
Expand All @@ -16,6 +17,16 @@ export type UpdateAutofillInlineMenuListCiphersMessage = AutofillInlineMenuListM
showInlineMenuAccountCreation?: boolean;
};

// Cozy customization
export type UpdateAutofillInlineMenuListAmbiguousMessage = AutofillInlineMenuListMessage & {
inlineMenuCipherId: string;
contactName: string;
ambiguousFields: AmbiguousContactFields;
isFocusedFieldAmbigous: boolean;
fieldHtmlIDToFill: string;
};
// Cozy customization end

export type InitAutofillInlineMenuListMessage = AutofillInlineMenuListMessage & {
authStatus: AuthenticationStatus;
styleSheetUrl: string;
Expand All @@ -42,5 +53,12 @@ export type AutofillInlineMenuListWindowMessageHandlers = {
}: {
message: UpdateAutofillInlineMenuListCiphersMessage;
}) => void;
// Cozy customization
ambiguousFieldList: ({
message,
}: {
message: UpdateAutofillInlineMenuListAmbiguousMessage;
}) => void;
// Cozy customization end
focusAutofillInlineMenuList: () => void;
};
Loading
Loading