diff --git a/apps/client/src/widgets/bulk_actions/label/delete_label.ts b/apps/client/src/widgets/bulk_actions/label/delete_label.ts
deleted file mode 100644
index 351d43ccb..000000000
--- a/apps/client/src/widgets/bulk_actions/label/delete_label.ts
+++ /dev/null
@@ -1,43 +0,0 @@
-import { t } from "../../../services/i18n.js";
-import SpacedUpdate from "../../../services/spaced_update.js";
-import AbstractBulkAction from "../abstract_bulk_action.js";
-
-const TPL = /*html*/`
-
- |
- ${t("delete_label.delete_label")}
- |
-
-
- |
-
-
- |
-
`;
-
-export default class DeleteLabelBulkAction extends AbstractBulkAction {
- static get actionName() {
- return "deleteLabel";
- }
- static get actionTitle() {
- return t("delete_label.delete_label");
- }
-
- doRender() {
- const $action = $(TPL);
- const $labelName = $action.find(".label-name");
- $labelName.val(this.actionDef.labelName || "");
-
- const spacedUpdate = new SpacedUpdate(async () => {
- await this.saveAction({ labelName: $labelName.val() });
- }, 1000);
-
- $labelName.on("input", () => spacedUpdate.scheduleUpdate());
-
- return $action;
- }
-}
diff --git a/apps/client/src/widgets/bulk_actions/label/delete_label.tsx b/apps/client/src/widgets/bulk_actions/label/delete_label.tsx
new file mode 100644
index 000000000..50942a568
--- /dev/null
+++ b/apps/client/src/widgets/bulk_actions/label/delete_label.tsx
@@ -0,0 +1,38 @@
+import { useEffect, useState } from "preact/hooks";
+import { t } from "../../../services/i18n.js";
+import FormTextBox from "../../react/FormTextBox.jsx";
+import AbstractBulkAction, { ActionDefinition } from "../abstract_bulk_action.js";
+import { useSpacedUpdate } from "../../react/hooks.jsx";
+import BulkAction from "../BulkAction.jsx";
+
+function DeleteLabelBulkActionComponent({ bulkAction, actionDef }: { bulkAction: AbstractBulkAction, actionDef: ActionDefinition}) {
+ const [ labelName, setLabelName ] = useState(actionDef.labelName ?? "");
+ const spacedUpdate = useSpacedUpdate(() => bulkAction.saveAction({ labelName }));
+ useEffect(() => spacedUpdate.scheduleUpdate(), [labelName]);
+
+ return (
+
+
+
+ );
+}
+
+export default class DeleteLabelBulkAction extends AbstractBulkAction {
+ static get actionName() {
+ return "deleteLabel";
+ }
+ static get actionTitle() {
+ return t("delete_label.delete_label");
+ }
+
+ doRender() {
+ return
+ }
+}
diff --git a/apps/client/src/widgets/bulk_actions/label/rename_label.ts b/apps/client/src/widgets/bulk_actions/label/rename_label.ts
deleted file mode 100644
index 1bcebd272..000000000
--- a/apps/client/src/widgets/bulk_actions/label/rename_label.ts
+++ /dev/null
@@ -1,60 +0,0 @@
-import { t } from "../../../services/i18n.js";
-import SpacedUpdate from "../../../services/spaced_update.js";
-import AbstractBulkAction from "../abstract_bulk_action.js";
-
-const TPL = /*html*/`
-
-
-
- ${t("rename_label.rename_label_from")}
-
-
-
- ${t("rename_label.to")}
-
-
-
- |
-
-
- |
-
`;
-
-export default class RenameLabelBulkAction extends AbstractBulkAction {
- static get actionName() {
- return "renameLabel";
- }
- static get actionTitle() {
- return t("rename_label.rename_label");
- }
-
- doRender() {
- const $action = $(TPL);
-
- const $oldLabelName = $action.find(".old-label-name");
- $oldLabelName.val(this.actionDef.oldLabelName || "");
-
- const $newLabelName = $action.find(".new-label-name");
- $newLabelName.val(this.actionDef.newLabelName || "");
-
- const spacedUpdate = new SpacedUpdate(async () => {
- await this.saveAction({
- oldLabelName: $oldLabelName.val(),
- newLabelName: $newLabelName.val()
- });
- }, 1000);
-
- $oldLabelName.on("input", () => spacedUpdate.scheduleUpdate());
- $newLabelName.on("input", () => spacedUpdate.scheduleUpdate());
-
- return $action;
- }
-}
diff --git a/apps/client/src/widgets/bulk_actions/label/rename_label.tsx b/apps/client/src/widgets/bulk_actions/label/rename_label.tsx
new file mode 100644
index 000000000..b3fa10c5a
--- /dev/null
+++ b/apps/client/src/widgets/bulk_actions/label/rename_label.tsx
@@ -0,0 +1,48 @@
+import { useEffect, useState } from "preact/hooks";
+import { t } from "../../../services/i18n.js";
+import FormTextBox from "../../react/FormTextBox.jsx";
+import AbstractBulkAction, { ActionDefinition } from "../abstract_bulk_action.js";
+import BulkAction, { BulkActionText } from "../BulkAction.jsx";
+import { useSpacedUpdate } from "../../react/hooks.jsx";
+
+function RenameLabelBulkActionComponent({ bulkAction, actionDef }: { bulkAction: AbstractBulkAction, actionDef: ActionDefinition}) {
+ const [ oldLabelName, setOldLabelName ] = useState(actionDef.oldLabelName);
+ const [ newLabelName, setNewLabelName ] = useState(actionDef.newLabelName);
+ const spacedUpdate = useSpacedUpdate(() => bulkAction.saveAction({ oldLabelName, newLabelName }));
+ useEffect(() => spacedUpdate.scheduleUpdate(), [ oldLabelName, newLabelName ]);
+
+ return (
+
+
+
+
+
+
+
+ )
+}
+
+export default class RenameLabelBulkAction extends AbstractBulkAction {
+ static get actionName() {
+ return "renameLabel";
+ }
+ static get actionTitle() {
+ return t("rename_label.rename_label");
+ }
+
+ doRender() {
+ return
+ }
+}