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

PM-22143 Refactor TS enums to be const objects (Send specific enums) (#16399)

This commit is contained in:
John Harrington
2025-11-26 15:08:59 -07:00
committed by GitHub
parent 8522b6b87a
commit 6f5491f7dc
9 changed files with 126 additions and 48 deletions

View File

@@ -41,7 +41,12 @@ import { SendFilePopoutDialogContainerComponent } from "../send-file-popout-dial
class QueryParams {
constructor(params: Params) {
this.sendId = params.sendId;
this.type = parseInt(params.type, 10);
const sendTypeValue = parseInt(params.type, 10);
if (sendTypeValue === SendType.Text || sendTypeValue === SendType.File) {
this.type = sendTypeValue;
} else {
throw new Error(`Invalid SendType: ${params.type}`);
}
}
/**

View File

@@ -37,7 +37,7 @@ import { PopupHeaderComponent } from "../../../platform/popup/layout/popup-heade
import { PopupPageComponent } from "../../../platform/popup/layout/popup-page.component";
import { PopupRouterCacheService } from "../../../platform/popup/view-cache/popup-router-cache.service";
import { SendV2Component, SendState } from "./send-v2.component";
import { SendState, SendV2Component } from "./send-v2.component";
describe("SendV2Component", () => {
let component: SendV2Component;

View File

@@ -38,12 +38,16 @@ import { PopupHeaderComponent } from "../../../platform/popup/layout/popup-heade
import { PopupPageComponent } from "../../../platform/popup/layout/popup-page.component";
import { VaultFadeInOutSkeletonComponent } from "../../../vault/popup/components/vault-fade-in-out-skeleton/vault-fade-in-out-skeleton.component";
// FIXME: update to use a const object instead of a typescript enum
// eslint-disable-next-line @bitwarden/platform/no-enums
export enum SendState {
Empty,
NoResults,
}
/** A state of the Send list UI. */
export const SendState = Object.freeze({
/** No sends exist for the current filter (file or text). */
Empty: "Empty",
/** Sends exist, but none match the current filter/search. */
NoResults: "NoResults",
} as const);
/** A state of the Send list UI. */
export type SendState = (typeof SendState)[keyof typeof SendState];
// FIXME(https://bitwarden.atlassian.net/browse/CL-764): Migrate to OnPush
// eslint-disable-next-line @angular-eslint/prefer-on-push-component-change-detection
@@ -114,6 +118,11 @@ export class SendV2Component implements OnDestroy {
protected sendsDisabled = false;
private readonly sendTypeTitles: Record<SendType, string> = {
[SendType.File]: "fileSends",
[SendType.Text]: "textSends",
};
constructor(
protected sendItemsService: SendItemsService,
protected sendListFiltersService: SendListFiltersService,
@@ -130,7 +139,7 @@ export class SendV2Component implements OnDestroy {
.pipe(takeUntilDestroyed())
.subscribe(([emptyList, noFilteredResults, currentFilter]) => {
if (currentFilter?.sendType !== null) {
this.title = `${this.sendType[currentFilter.sendType].toLowerCase()}Sends`;
this.title = this.sendTypeTitles[currentFilter.sendType] ?? "allSends";
} else {
this.title = "allSends";
}

View File

@@ -308,7 +308,7 @@ export class SendProgram extends BaseProgram {
let sendFile = null;
let sendText = null;
let name = Utils.newGuid();
let type = SendType.Text;
let type: SendType = SendType.Text;
if (options.file != null) {
data = path.resolve(data);
if (!fs.existsSync(data)) {

View File

@@ -25,13 +25,16 @@ import { SearchBarService } from "../../layout/search/search-bar.service";
import { AddEditComponent } from "./add-edit.component";
// FIXME: update to use a const object instead of a typescript enum
// eslint-disable-next-line @bitwarden/platform/no-enums
enum Action {
None = "",
Add = "add",
Edit = "edit",
}
const Action = Object.freeze({
/** No action is currently active. */
None: "",
/** The user is adding a new Send. */
Add: "add",
/** The user is editing an existing Send. */
Edit: "edit",
} as const);
type Action = (typeof Action)[keyof typeof Action];
const BroadcasterSubscriptionId = "SendComponent";

View File

@@ -1,6 +1,10 @@
// FIXME: update to use a const object instead of a typescript enum
// eslint-disable-next-line @bitwarden/platform/no-enums
export enum SendType {
Text = 0,
File = 1,
}
/** A type of Send. */
export const SendType = Object.freeze({
/** Send contains plain text. */
Text: 0,
/** Send contains a file. */
File: 1,
} as const);
/** A type of Send. */
export type SendType = (typeof SendType)[keyof typeof SendType];

View File

@@ -35,19 +35,16 @@ export interface SendItemDialogParams {
disableForm?: boolean;
}
// FIXME: update to use a const object instead of a typescript enum
// eslint-disable-next-line @bitwarden/platform/no-enums
export enum SendItemDialogResult {
/**
* A Send was saved (created or updated).
*/
Saved = "saved",
/** A result of the Send add/edit dialog. */
export const SendItemDialogResult = Object.freeze({
/** The send item was created or updated. */
Saved: "saved",
/** The send item was deleted. */
Deleted: "deleted",
} as const);
/**
* A Send was deleted.
*/
Deleted = "deleted",
}
/** A result of the Send add/edit dialog. */
export type SendItemDialogResult = (typeof SendItemDialogResult)[keyof typeof SendItemDialogResult];
/**
* Component for adding or editing a send item.

View File

@@ -0,0 +1,27 @@
import { DatePreset, isDatePreset, asDatePreset } from "./send-details.component";
describe("SendDetails DatePreset utilities", () => {
it("accepts all defined numeric presets", () => {
const presets: Array<any> = [
DatePreset.OneHour,
DatePreset.OneDay,
DatePreset.TwoDays,
DatePreset.ThreeDays,
DatePreset.SevenDays,
DatePreset.FourteenDays,
DatePreset.ThirtyDays,
];
presets.forEach((p) => {
expect(isDatePreset(p)).toBe(true);
expect(asDatePreset(p)).toBe(p);
});
});
it("rejects invalid numbers and non-numeric values", () => {
const invalid: Array<any> = [5, -1, 0.5, 0, 9999, "never", "foo", null, undefined, {}, []];
invalid.forEach((v) => {
expect(isDatePreset(v)).toBe(false);
expect(asDatePreset(v)).toBeUndefined();
});
});
});

View File

@@ -29,24 +29,50 @@ import { SendOptionsComponent } from "../options/send-options.component";
import { SendFileDetailsComponent } from "./send-file-details.component";
import { SendTextDetailsComponent } from "./send-text-details.component";
// Value = hours
// FIXME: update to use a const object instead of a typescript enum
// eslint-disable-next-line @bitwarden/platform/no-enums
export enum DatePreset {
OneHour = 1,
OneDay = 24,
TwoDays = 48,
ThreeDays = 72,
SevenDays = 168,
FourteenDays = 336,
ThirtyDays = 720,
}
/** A preset duration (in hours) for deletion. */
export const DatePreset = Object.freeze({
/** One-hour duration. */
OneHour: 1,
/** One-day duration (24 hours). */
OneDay: 24,
/** Two-day duration (48 hours). */
TwoDays: 48,
/** Three-day duration (72 hours). */
ThreeDays: 72,
/** Seven-day duration (168 hours). */
SevenDays: 168,
/** Fourteen-day duration (336 hours). */
FourteenDays: 336,
/** Thirty-day duration (720 hours). */
ThirtyDays: 720,
} as const);
/** A preset duration (in hours) for deletion. */
export type DatePreset = (typeof DatePreset)[keyof typeof DatePreset];
export interface DatePresetSelectOption {
name: string;
value: DatePreset | string;
}
const namesByDatePreset = new Map<DatePreset, keyof typeof DatePreset>(
Object.entries(DatePreset).map(([k, v]) => [v as DatePreset, k as keyof typeof DatePreset]),
);
/**
* Runtime type guard to verify a value is a valid DatePreset.
*/
export function isDatePreset(value: unknown): value is DatePreset {
return namesByDatePreset.has(value as DatePreset);
}
/**
* Safe converter to DatePreset (numeric preset), returns undefined for invalid inputs.
*/
export function asDatePreset(value: unknown): DatePreset | undefined {
return isDatePreset(value) ? (value as DatePreset) : undefined;
}
// FIXME(https://bitwarden.atlassian.net/browse/CL-764): Migrate to OnPush
// eslint-disable-next-line @angular-eslint/prefer-on-push-component-change-detection
@Component({
@@ -153,11 +179,18 @@ export class SendDetailsComponent implements OnInit {
const now = new Date();
const selectedValue = this.sendDetailsForm.controls.selectedDeletionDatePreset.value;
// The form allows for custom date strings, if such is used, return it without worrying about DatePreset validation
if (typeof selectedValue === "string") {
return selectedValue;
}
const milliseconds = now.setTime(now.getTime() + (selectedValue as number) * 60 * 60 * 1000);
// Otherwise, treat it as a preset and validate at runtime
const preset = asDatePreset(selectedValue);
if (!isDatePreset(preset)) {
return new Date(now).toString();
}
const milliseconds = now.setTime(now.getTime() + preset * 60 * 60 * 1000);
return new Date(milliseconds).toString();
}
}