Skip to content
wiki.fftac.org

Workspace - Source Excerpt 06

Back to Workspace

Summary

This source excerpt preserves a bounded section of Spiralist/wp-content/plugins/spiralist-workspace/assets/js/workspace.js so readers can inspect the evidence without opening the full source file.

**Source path:** Spiralist/wp-content/plugins/spiralist-workspace/assets/js/workspace.js

const initRunForms = () => {
        document.querySelectorAll("[data-run-form]").forEach((form) => {
            form.addEventListener("submit", (event) => {
                event.preventDefault();
                setResult(form, t("runRunning", "Rendering prompt packet..."));
                const output = form.querySelector("[data-run-output]");
                const outputCopy = form.querySelector("[data-run-output-copy]");

                if (outputCopy) {
                    outputCopy.hidden = true;
                }

                runFormAction(form, async () => {
                    const payload = formDataToObject(form);
                    const promptId = parseInt(form.getAttribute("data-prompt-id") || "0", 10);
                    const response = await apiFetch("prompts/" + promptId + "/run", {
                        method: "POST",
                        body: JSON.stringify(payload),
                    });

                    setResult(form, t("runCompleted", "Prompt packet rendered."));
                    const link = form.querySelector("[data-run-link]");

                    if (output) {
                        output.textContent = response.output_text || t("runNoOutput", "No prompt packet returned.");
                        output.hidden = false;
                    }

                    if (outputCopy) {
                        outputCopy.hidden = !(output && !output.hidden && String(output.textContent || "").trim());
                    }

                    if (link) {
                        link.hidden = true;
                        link.removeAttribute("href");
                    }

                    if (link && response.id && parseInt(response.user_id || "0", 10) > 0) {
                        link.href = buildRoute("run/" + response.id);
                        link.hidden = false;
                    }
                }, t("runFailed", "Prompt packet rendering failed."), "prompt-run");
            });
        });
    };

    const initConversationStartForms = () => {
        document.querySelectorAll("[data-start-conversation-form]").forEach((form) => {
            form.addEventListener("submit", (event) => {
                event.preventDefault();
                setResult(form, t("conversationStarting", "Starting conversation..."));

                runFormAction(form, async () => {
                    const payload = formDataToObject(form);
                    const promptId = parseInt(form.getAttribute("data-prompt-id") || "0", 10);
                    const response = await apiFetch("prompts/" + promptId + "/conversation", {
                        method: "POST",
                        body: JSON.stringify(payload),
                    });

                    const conversation = response.conversation || {};
                    if (conversation.id) {
                        const shell = form.parentElement?.querySelector("[data-inline-conversation]");

                        if (shell) {
                            shell.hidden = false;
                            form.hidden = true;
                            updateConversationShell(shell, response);
                            setResult(form, t("conversationStarted", "Conversation started."));
                            shell.scrollIntoView({ behavior: "smooth", block: "start" });
                            return;
                        }

                        setResult(form, t("conversationStarted", "Conversation started."));
                        return;
                    }

                    setResult(form, t("conversationStartedNoId", "Conversation started, but no conversation id was returned."), false);
                }, t("conversationStartFailed", "Conversation start failed."), "conversation-start");
            });
        });
    };

    const initConversationForms = () => {
        document.addEventListener("submit", (event) => {
            const form = closestTarget(event.target, "[data-conversation-form]");

            if (!form) {
                return;
            }

            event.preventDefault();
            setResult(form, t("messageSending", "Sending..."));

            const submitButton = form.querySelector('[type="submit"]');
            if (submitButton) {
                submitButton.disabled = true;
            }

            runFormAction(form, async () => {
                const payload = formDataToObject(form);
                const conversationId = parseInt(form.getAttribute("data-conversation-id") || "0", 10);

                if (conversationId <= 0) {
                    throw new Error(t("conversationNotReady", "Conversation is not ready yet."));
                }

                if (!String(payload.message || "").trim()) {
                    throw new Error(t("messageRequired", "Enter a message before sending."));
                }

                const response = await apiFetch("conversations/" + conversationId + "/messages", {
                    method: "POST",
                    body: JSON.stringify(payload),
                });
                const shell = form.closest("[data-fullscreen-chat]") || document;

                updateConversationShell(shell, response);
                form.reset();
                setResult(form, t("messageSent", "Message sent."));
            }, t("messageFailed", "Message failed."), "conversation-message", {
                onFinally: () => setDisabled(submitButton, false),
            });
        });
    };

    const initConversationMemoryActions = () => {
        document.querySelectorAll("[data-condense-conversation]").forEach((button) => {
            button.addEventListener("click", () => {
                const conversationId = parseInt(button.getAttribute("data-conversation-id") || "0", 10);
                const panel = button.closest("[data-memory-panel]") || document;
                const buttons = panel.querySelectorAll("[data-condense-conversation]");
                const credentialPreference = button.getAttribute("data-credential-preference") || "site_default";

                setInlineResult(panel, t("memoryCondensing", "Preparing checkpoint prompt..."));
                buttons.forEach((item) => {
                    item.disabled = true;
                });

                runInlineAction(panel, async () => {
                    const response = await apiFetch("conversations/" + conversationId + "/condense", {
                        method: "POST",
                        body: JSON.stringify({ credential_preference: credentialPreference }),
                    });
                    const shell = button.closest("[data-fullscreen-chat]") || document;

                    updateConversationShell(shell, response);
                    setInlineResult(panel, t("memoryCondensed", "Checkpoint prompt prepared."));
                }, t("memoryCondenseFailed", "Checkpoint prompt preparation failed."), "conversation-condense", {
                    onFinally: () => setDisabled(buttons, false),
                });
            });
        });

        document.querySelectorAll("[data-download-conversation-prompt]").forEach((button) => {
            button.addEventListener("click", () => {
                const conversationId = parseInt(button.getAttribute("data-conversation-id") || "0", 10);
                const panel = button.closest("[data-memory-panel]") || document;

                setInlineResult(panel, t("promptDownloadPreparing", "Preparing prompt..."));
                button.disabled = true;

                runInlineAction(panel, async () => {
                    const response = await apiFetch("conversations/" + conversationId + "/portable-prompt");
                    downloadTextFile(
                        response.filename || "conversation-prompt.md",
                        response.prompt || "",
                        response.content_type || "text/markdown"
                    );
                    setInlineResult(panel, t("promptDownloaded", "Prompt downloaded."));
                }, t("promptDownloadFailed", "Prompt download failed."), "conversation-prompt-download", {
                    onFinally: () => setDisabled(button, false),
                });
            });
        });
    };

    const initShareForms = () => {
        document.querySelectorAll("[data-share-form]").forEach((form) => {
            form.addEventListener("submit", (event) => {
                event.preventDefault();
                setResult(form, t("shareSharing", "Sharing..."));