diff --git a/apps/browser/src/_locales/en/messages.json b/apps/browser/src/_locales/en/messages.json index 5b306fdb2a7..63d5f9eb9cb 100644 --- a/apps/browser/src/_locales/en/messages.json +++ b/apps/browser/src/_locales/en/messages.json @@ -1996,6 +1996,9 @@ "passwordProtected": { "message": "Password protected" }, + "copyLink": { + "message": "Copy link" + }, "copySendLink": { "message": "Copy Send link", "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." diff --git a/apps/browser/src/tools/popup/send/send-v2.component.html b/apps/browser/src/tools/popup/send/send-v2.component.html index 3499f8c32ef..52f7c3ed8ff 100644 --- a/apps/browser/src/tools/popup/send/send-v2.component.html +++ b/apps/browser/src/tools/popup/send/send-v2.component.html @@ -8,14 +8,12 @@ -
+
{{ "sendsNoItemsTitle" | i18n }} {{ "sendsNoItemsMessage" | i18n }}
+ diff --git a/apps/browser/src/tools/popup/send/send-v2.component.ts b/apps/browser/src/tools/popup/send/send-v2.component.ts index fba14b762b1..c720a27ffb0 100644 --- a/apps/browser/src/tools/popup/send/send-v2.component.ts +++ b/apps/browser/src/tools/popup/send/send-v2.component.ts @@ -1,21 +1,24 @@ import { CommonModule } from "@angular/common"; import { Component, OnDestroy, OnInit } from "@angular/core"; import { RouterLink } from "@angular/router"; +import { mergeMap, Subject, takeUntil } from "rxjs"; import { JslibModule } from "@bitwarden/angular/jslib.module"; import { SendType } from "@bitwarden/common/tools/send/enums/send-type"; +import { SendView } from "@bitwarden/common/tools/send/models/view/send.view"; +import { SendService } from "@bitwarden/common/tools/send/services/send.service.abstraction"; import { ButtonModule, NoItemsModule } from "@bitwarden/components"; -import { NoSendsIcon, NewSendDropdownComponent } from "@bitwarden/send-ui"; +import { + NoSendsIcon, + NewSendDropdownComponent, + SendListItemsContainerComponent, +} from "@bitwarden/send-ui"; import { CurrentAccountComponent } from "../../../auth/popup/account-switching/current-account.component"; import { PopOutComponent } from "../../../platform/popup/components/pop-out.component"; import { PopupHeaderComponent } from "../../../platform/popup/layout/popup-header.component"; import { PopupPageComponent } from "../../../platform/popup/layout/popup-page.component"; -enum SendsListState { - Empty, -} - @Component({ templateUrl: "send-v2.component.html", standalone: true, @@ -30,23 +33,30 @@ enum SendsListState { ButtonModule, RouterLink, NewSendDropdownComponent, + SendListItemsContainerComponent, ], }) export class SendV2Component implements OnInit, OnDestroy { sendType = SendType; - /** Visual state of the Sends list */ - protected sendsListState: SendsListState | null = null; + protected sends: SendView[] = []; + + private destroy$ = new Subject(); protected noItemIcon = NoSendsIcon; - protected SendsListStateEnum = SendsListState; + constructor(protected sendService: SendService) {} - constructor() { - this.sendsListState = SendsListState.Empty; + async ngOnInit() { + this.sendService.sendViews$ + .pipe( + mergeMap(async (sends) => { + this.sends = sends.sort((a, b) => a.name.localeCompare(b.name)); + }), + takeUntil(this.destroy$), + ) + .subscribe(); } - ngOnInit(): void {} - ngOnDestroy(): void {} } diff --git a/apps/desktop/src/locales/en/messages.json b/apps/desktop/src/locales/en/messages.json index c0ce5c17ee2..31de4095827 100644 --- a/apps/desktop/src/locales/en/messages.json +++ b/apps/desktop/src/locales/en/messages.json @@ -1368,7 +1368,7 @@ }, "exportPasswordDescription": { "message": "This password will be used to export and import this file" - }, + }, "accountRestrictedOptionDescription": { "message": "Use your account encryption key, derived from your account's username and Master Password, to encrypt the export and restrict import to only the current Bitwarden account." }, diff --git a/apps/web/src/locales/en/messages.json b/apps/web/src/locales/en/messages.json index 73396c39c16..560803c87e0 100644 --- a/apps/web/src/locales/en/messages.json +++ b/apps/web/src/locales/en/messages.json @@ -4350,6 +4350,9 @@ "message": "Send link", "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." }, + "copyLink": { + "message": "Copy link" + }, "copySendLink": { "message": "Copy Send link", "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." diff --git a/libs/common/src/platform/services/config/default-config.service.ts b/libs/common/src/platform/services/config/default-config.service.ts index 16878a72832..7bdf79f409b 100644 --- a/libs/common/src/platform/services/config/default-config.service.ts +++ b/libs/common/src/platform/services/config/default-config.service.ts @@ -115,6 +115,7 @@ export class DefaultConfigService implements ConfigService { return DefaultFeatureFlagValue[key]; } + serverConfig.featureStates[FeatureFlag.ExtensionRefresh] = true; return serverConfig.featureStates[key] as FeatureFlagValueType; }), ); diff --git a/libs/common/src/vault/models/view/send.view.ts b/libs/common/src/vault/models/view/send.view.ts new file mode 100644 index 00000000000..e69de29bb2d diff --git a/libs/tools/send/send-ui/src/index.ts b/libs/tools/send/send-ui/src/index.ts index fc7c87449dd..2bb0a3e942d 100644 --- a/libs/tools/send/send-ui/src/index.ts +++ b/libs/tools/send/send-ui/src/index.ts @@ -1,2 +1,3 @@ export * from "./icons"; export { NewSendDropdownComponent } from "./new-send-dropdown/new-send-dropdown.component"; +export { SendListItemsContainerComponent } from "./send-list-items-container/send-list-items-container.component"; diff --git a/libs/tools/send/send-ui/src/send-list-items-container/send-list-items-container.component.html b/libs/tools/send/send-ui/src/send-list-items-container/send-list-items-container.component.html new file mode 100644 index 00000000000..6a4c6a308ed --- /dev/null +++ b/libs/tools/send/send-ui/src/send-list-items-container/send-list-items-container.component.html @@ -0,0 +1,54 @@ + + +

+ {{ "allSends" | i18n }} +

+ {{ sends.length }} +
+ + + + + + + + + + + +
diff --git a/libs/tools/send/send-ui/src/send-list-items-container/send-list-items-container.component.ts b/libs/tools/send/send-ui/src/send-list-items-container/send-list-items-container.component.ts new file mode 100644 index 00000000000..ef7232e97a0 --- /dev/null +++ b/libs/tools/send/send-ui/src/send-list-items-container/send-list-items-container.component.ts @@ -0,0 +1,95 @@ +import { CommonModule } from "@angular/common"; +import { Component, Input } from "@angular/core"; +import { RouterLink } from "@angular/router"; +import { firstValueFrom } from "rxjs"; + +import { JslibModule } from "@bitwarden/angular/jslib.module"; +import { EnvironmentService } from "@bitwarden/common/platform/abstractions/environment.service"; +import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service"; +import { LogService } from "@bitwarden/common/platform/abstractions/log.service"; +import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service"; +import { SendType } from "@bitwarden/common/tools/send/enums/send-type"; +import { SendView } from "@bitwarden/common/tools/send/models/view/send.view"; +import { SendApiService } from "@bitwarden/common/tools/send/services/send-api.service.abstraction"; +import { + BadgeModule, + ButtonModule, + DialogService, + IconButtonModule, + ItemModule, + SectionComponent, + SectionHeaderComponent, + ToastService, + TypographyModule, +} from "@bitwarden/components"; + +@Component({ + imports: [ + CommonModule, + ItemModule, + ButtonModule, + BadgeModule, + IconButtonModule, + SectionComponent, + TypographyModule, + JslibModule, + SectionHeaderComponent, + RouterLink, + ], + selector: "app-send-list-items-container", + templateUrl: "send-list-items-container.component.html", + standalone: true, +}) +export class SendListItemsContainerComponent { + sendType = SendType; + /** + * The list of sends to display. + */ + @Input() + sends: SendView[] = []; + + constructor( + protected dialogService: DialogService, + protected environmentService: EnvironmentService, + protected i18nService: I18nService, + protected logService: LogService, + protected platformUtilsService: PlatformUtilsService, + protected sendApiService: SendApiService, + protected toastService: ToastService, + ) {} + + async deleteSend(s: SendView): Promise { + const confirmed = await this.dialogService.openSimpleDialog({ + title: { key: "deleteSend" }, + content: { key: "deleteSendConfirmation" }, + type: "warning", + }); + + if (!confirmed) { + return false; + } + + await this.sendApiService.delete(s.id); + + try { + this.toastService.showToast({ + variant: "success", + title: null, + message: this.i18nService.t("deletedSend"), + }); + } catch (e) { + this.logService.error(e); + } + } + + async copySendLink(s: SendView) { + const env = await firstValueFrom(this.environmentService.environment$); + const link = env.getSendUrl() + s.accessId + "/" + s.urlB64Key; + this.platformUtilsService.copyToClipboard(link); + this.toastService.showToast({ + variant: "success", + title: null, + message: this.i18nService.t("valueCopied", this.i18nService.t("sendLink")), + }); + } +}