From: Marcel Werk Date: Wed, 18 Dec 2024 15:24:05 +0000 (+0100) Subject: Add action for RPC calls X-Git-Url: https://git.stricted.de/?a=commitdiff_plain;h=3a3d77b4ba8eb2ead4182a555336ea2ddf72e64d;p=GitHub%2FWoltLab%2FWCF.git Add action for RPC calls --- diff --git a/ts/WoltLabSuite/Core/Api/PostObject.ts b/ts/WoltLabSuite/Core/Api/PostObject.ts index f5e47c9973..7d2365b897 100644 --- a/ts/WoltLabSuite/Core/Api/PostObject.ts +++ b/ts/WoltLabSuite/Core/Api/PostObject.ts @@ -11,9 +11,11 @@ import { prepareRequest } from "WoltLabSuite/Core/Ajax/Backend"; import { ApiResult, apiResultFromError, apiResultFromValue } from "./Result"; -export async function postObject(endpoint: string): Promise> { +type Payload = Blob | FormData | Record; + +export async function postObject(endpoint: string, payload?: Payload): Promise> { try { - await prepareRequest(endpoint).post().fetchAsJson(); + await prepareRequest(endpoint).post(payload).fetchAsJson(); } catch (e) { return apiResultFromError(e); } diff --git a/ts/WoltLabSuite/Core/Component/GridView/Action/Confirmation.ts b/ts/WoltLabSuite/Core/Component/GridView/Action/Confirmation.ts new file mode 100644 index 0000000000..69e5943b78 --- /dev/null +++ b/ts/WoltLabSuite/Core/Component/GridView/Action/Confirmation.ts @@ -0,0 +1,51 @@ +import { confirmationFactory } from "WoltLabSuite/Core/Component/Confirmation"; + +export enum ConfirmationType { + None = "None", + SoftDelete = "SoftDelete", + SoftDeleteWithReason = "SoftDeleteWithReason", + Restore = "Restore", + Delete = "Delete", + Custom = "Custom", +} + +type ResultConfirmationWithReason = { + result: boolean; + reason?: string; +}; + +export async function handleConfirmation( + objectName: string, + confirmationType: ConfirmationType, + customMessage: string = "", +): Promise { + if (confirmationType == ConfirmationType.SoftDelete) { + return await confirmationFactory().softDelete(objectName); + } + + if (confirmationType == ConfirmationType.SoftDeleteWithReason) { + return await confirmationFactory().softDelete(objectName, true); + } + + if (confirmationType == ConfirmationType.Restore) { + return { + result: await confirmationFactory().restore(objectName ? objectName : undefined), + }; + } + + if (confirmationType == ConfirmationType.Delete) { + return { + result: await confirmationFactory().delete(objectName ? objectName : undefined), + }; + } + + if (confirmationType == ConfirmationType.Custom) { + return { + result: await confirmationFactory().custom(customMessage).withoutMessage(), + }; + } + + return { + result: true, + }; +} diff --git a/ts/WoltLabSuite/Core/Component/GridView/Action/Rpc.ts b/ts/WoltLabSuite/Core/Component/GridView/Action/Rpc.ts new file mode 100644 index 0000000000..6c09a62bfc --- /dev/null +++ b/ts/WoltLabSuite/Core/Component/GridView/Action/Rpc.ts @@ -0,0 +1,59 @@ +import { deleteObject } from "WoltLabSuite/Core/Api/DeleteObject"; +import { postObject } from "WoltLabSuite/Core/Api/PostObject"; +import { show as showNotification } from "WoltLabSuite/Core/Ui/Notification"; +import { ConfirmationType, handleConfirmation } from "./Confirmation"; + +async function handleRpcAction( + row: HTMLTableRowElement, + objectName: string, + endpoint: string, + confirmationType: ConfirmationType, + customConfirmationMessage: string = "", +): Promise { + const confirmationResult = await handleConfirmation(objectName, confirmationType, customConfirmationMessage); + if (!confirmationResult.result) { + return; + } + + if (confirmationType == ConfirmationType.Delete) { + const result = await deleteObject(endpoint); + if (!result.ok) { + return; + } + } else { + const result = await postObject( + endpoint, + confirmationResult.reason ? { reason: confirmationResult.reason } : undefined, + ); + if (!result.ok) { + return; + } + } + + if (confirmationType == ConfirmationType.Delete) { + row.remove(); + } else { + row.dispatchEvent( + new CustomEvent("refresh", { + bubbles: true, + }), + ); + + // TODO: This shows a generic success message and should be replaced with a more specific message. + showNotification(); + } +} + +export function setup(table: HTMLTableElement): void { + table.addEventListener("action", (event: CustomEvent) => { + if (event.detail.action === "rpc") { + void handleRpcAction( + event.target as HTMLTableRowElement, + event.detail.objectName, + event.detail.endpoint, + event.detail.confirmationType, + event.detail.confirmationMessage, + ); + } + }); +} diff --git a/wcfsetup/install/files/js/WoltLabSuite/Core/Api/PostObject.js b/wcfsetup/install/files/js/WoltLabSuite/Core/Api/PostObject.js index 364e46f736..16316e806d 100644 --- a/wcfsetup/install/files/js/WoltLabSuite/Core/Api/PostObject.js +++ b/wcfsetup/install/files/js/WoltLabSuite/Core/Api/PostObject.js @@ -11,9 +11,9 @@ define(["require", "exports", "WoltLabSuite/Core/Ajax/Backend", "./Result"], fun "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.postObject = postObject; - async function postObject(endpoint) { + async function postObject(endpoint, payload) { try { - await (0, Backend_1.prepareRequest)(endpoint).post().fetchAsJson(); + await (0, Backend_1.prepareRequest)(endpoint).post(payload).fetchAsJson(); } catch (e) { return (0, Result_1.apiResultFromError)(e); diff --git a/wcfsetup/install/files/js/WoltLabSuite/Core/Component/GridView/Action/Confirmation.js b/wcfsetup/install/files/js/WoltLabSuite/Core/Component/GridView/Action/Confirmation.js new file mode 100644 index 0000000000..7920ecc273 --- /dev/null +++ b/wcfsetup/install/files/js/WoltLabSuite/Core/Component/GridView/Action/Confirmation.js @@ -0,0 +1,41 @@ +define(["require", "exports", "WoltLabSuite/Core/Component/Confirmation"], function (require, exports, Confirmation_1) { + "use strict"; + Object.defineProperty(exports, "__esModule", { value: true }); + exports.ConfirmationType = void 0; + exports.handleConfirmation = handleConfirmation; + var ConfirmationType; + (function (ConfirmationType) { + ConfirmationType["None"] = "None"; + ConfirmationType["SoftDelete"] = "SoftDelete"; + ConfirmationType["SoftDeleteWithReason"] = "SoftDeleteWithReason"; + ConfirmationType["Restore"] = "Restore"; + ConfirmationType["Delete"] = "Delete"; + ConfirmationType["Custom"] = "Custom"; + })(ConfirmationType || (exports.ConfirmationType = ConfirmationType = {})); + async function handleConfirmation(objectName, confirmationType, customMessage = "") { + if (confirmationType == ConfirmationType.SoftDelete) { + return await (0, Confirmation_1.confirmationFactory)().softDelete(objectName); + } + if (confirmationType == ConfirmationType.SoftDeleteWithReason) { + return await (0, Confirmation_1.confirmationFactory)().softDelete(objectName, true); + } + if (confirmationType == ConfirmationType.Restore) { + return { + result: await (0, Confirmation_1.confirmationFactory)().restore(objectName ? objectName : undefined), + }; + } + if (confirmationType == ConfirmationType.Delete) { + return { + result: await (0, Confirmation_1.confirmationFactory)().delete(objectName ? objectName : undefined), + }; + } + if (confirmationType == ConfirmationType.Custom) { + return { + result: await (0, Confirmation_1.confirmationFactory)().custom(customMessage).withoutMessage(), + }; + } + return { + result: true, + }; + } +}); diff --git a/wcfsetup/install/files/js/WoltLabSuite/Core/Component/GridView/Action/Rpc.js b/wcfsetup/install/files/js/WoltLabSuite/Core/Component/GridView/Action/Rpc.js new file mode 100644 index 0000000000..4cf316af53 --- /dev/null +++ b/wcfsetup/install/files/js/WoltLabSuite/Core/Component/GridView/Action/Rpc.js @@ -0,0 +1,40 @@ +define(["require", "exports", "WoltLabSuite/Core/Api/DeleteObject", "WoltLabSuite/Core/Api/PostObject", "WoltLabSuite/Core/Ui/Notification", "./Confirmation"], function (require, exports, DeleteObject_1, PostObject_1, Notification_1, Confirmation_1) { + "use strict"; + Object.defineProperty(exports, "__esModule", { value: true }); + exports.setup = setup; + async function handleRpcAction(row, objectName, endpoint, confirmationType, customConfirmationMessage = "") { + const confirmationResult = await (0, Confirmation_1.handleConfirmation)(objectName, confirmationType, customConfirmationMessage); + if (!confirmationResult.result) { + return; + } + if (confirmationType == Confirmation_1.ConfirmationType.Delete) { + const result = await (0, DeleteObject_1.deleteObject)(endpoint); + if (!result.ok) { + return; + } + } + else { + const result = await (0, PostObject_1.postObject)(endpoint, confirmationResult.reason ? { reason: confirmationResult.reason } : undefined); + if (!result.ok) { + return; + } + } + if (confirmationType == Confirmation_1.ConfirmationType.Delete) { + row.remove(); + } + else { + row.dispatchEvent(new CustomEvent("refresh", { + bubbles: true, + })); + // TODO: This shows a generic success message and should be replaced with a more specific message. + (0, Notification_1.show)(); + } + } + function setup(table) { + table.addEventListener("action", (event) => { + if (event.detail.action === "rpc") { + void handleRpcAction(event.target, event.detail.objectName, event.detail.endpoint, event.detail.confirmationType, event.detail.confirmationMessage); + } + }); + } +}); diff --git a/wcfsetup/install/files/lib/system/gridView/action/ActionConfirmationType.class.php b/wcfsetup/install/files/lib/system/gridView/action/ActionConfirmationType.class.php new file mode 100644 index 0000000000..7bc5e9998c --- /dev/null +++ b/wcfsetup/install/files/lib/system/gridView/action/ActionConfirmationType.class.php @@ -0,0 +1,25 @@ + 'None', + self::SoftDelete => 'SoftDelete', + self::SoftDeleteWithReason => 'SoftDeleteWithReason', + self::Restore => 'Restore', + self::Delete => 'Delete', + self::Custom => 'Custom', + }; + } +} diff --git a/wcfsetup/install/files/lib/system/gridView/action/RpcAction.class.php b/wcfsetup/install/files/lib/system/gridView/action/RpcAction.class.php new file mode 100644 index 0000000000..ba02b0a336 --- /dev/null +++ b/wcfsetup/install/files/lib/system/gridView/action/RpcAction.class.php @@ -0,0 +1,89 @@ + + * @since 6.2 + */ +class RpcAction extends AbstractAction +{ + public function __construct( + protected readonly string $endpoint, + protected readonly string|Closure $languageItem, + protected readonly ActionConfirmationType $confirmationType = ActionConfirmationType::None, + protected readonly string|Closure $confirmationMessage = '', + ?Closure $isAvailableCallback = null + ) { + parent::__construct($isAvailableCallback); + } + + #[\Override] + public function render(mixed $row): string + { + \assert($row instanceof DatabaseObject); + + if (\is_string($this->languageItem)) { + $label = WCF::getLanguage()->get($this->languageItem); + } else { + $label = ($this->languageItem)($row); + } + + if (\is_string($this->confirmationMessage)) { + $confirmationMessage = WCF::getLanguage()->get($this->confirmationMessage); + } else { + $confirmationMessage = ($this->confirmationMessage)($row); + } + + $endpoint = StringUtil::encodeHTML( + LinkHandler::getInstance()->getControllerLink(ApiAction::class, ['id' => 'rpc']) . + \sprintf($this->endpoint, $row->getObjectID()) + ); + + if ($row instanceof ITitledObject) { + $objectName = StringUtil::encodeHTML($row->getTitle()); + } else { + $objectName = ''; + } + + return << + {$label} + + HTML; + } + + #[\Override] + public function renderInitialization(AbstractGridView $gridView): ?string + { + $id = StringUtil::encodeJS($gridView->getID()); + + return << + require(['WoltLabSuite/Core/Component/GridView/Action/Rpc'], ({ setup }) => { + setup(document.getElementById('{$id}_table')); + }); + + HTML; + } +}