added quality-of-life improvements, persistent output buffer and better error messages
This commit is contained in:
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"manifest_version": 3,
|
||||
"name": "WWCompanion",
|
||||
"version": "0.1.2",
|
||||
"version": "0.1.3",
|
||||
"description": "Manual reasoning companion for WaterlooWorks job postings.",
|
||||
"permissions": ["storage", "activeTab"],
|
||||
"host_permissions": ["https://waterlooworks.uwaterloo.ca/*"],
|
||||
|
||||
@@ -46,6 +46,7 @@
|
||||
<div class="footer-left">
|
||||
<button id="copyRenderedBtn" class="ghost" type="button">Copy</button>
|
||||
<button id="copyRawBtn" class="ghost" type="button">Copy Markdown</button>
|
||||
<button id="clearOutputBtn" class="ghost" type="button">Clear</button>
|
||||
</div>
|
||||
<button id="settingsBtn" class="link">Open Settings</button>
|
||||
</footer>
|
||||
|
||||
46
popup.js
46
popup.js
@@ -12,6 +12,10 @@ const promptCountEl = document.getElementById("promptCount");
|
||||
const settingsBtn = document.getElementById("settingsBtn");
|
||||
const copyRenderedBtn = document.getElementById("copyRenderedBtn");
|
||||
const copyRawBtn = document.getElementById("copyRawBtn");
|
||||
const clearOutputBtn = document.getElementById("clearOutputBtn");
|
||||
|
||||
const OUTPUT_STORAGE_KEY = "lastOutput";
|
||||
let persistTimer = null;
|
||||
|
||||
const state = {
|
||||
postingText: "",
|
||||
@@ -217,6 +221,21 @@ function renderOutput() {
|
||||
outputEl.scrollTop = outputEl.scrollHeight;
|
||||
}
|
||||
|
||||
function persistOutputNow() {
|
||||
if (persistTimer) {
|
||||
clearTimeout(persistTimer);
|
||||
persistTimer = null;
|
||||
}
|
||||
return chrome.storage.local.set({ [OUTPUT_STORAGE_KEY]: state.outputRaw });
|
||||
}
|
||||
|
||||
function schedulePersistOutput() {
|
||||
if (persistTimer) clearTimeout(persistTimer);
|
||||
persistTimer = setTimeout(() => {
|
||||
void persistOutputNow();
|
||||
}, 250);
|
||||
}
|
||||
|
||||
function setStatus(message) {
|
||||
statusEl.textContent = message;
|
||||
}
|
||||
@@ -280,7 +299,11 @@ function sendToActiveTab(message) {
|
||||
chrome.tabs.sendMessage(tab.id, message, (response) => {
|
||||
const error = chrome.runtime.lastError;
|
||||
if (error) {
|
||||
reject(new Error(error.message));
|
||||
const msg =
|
||||
error.message && error.message.includes("Receiving end does not exist")
|
||||
? "Couldn't reach the page. Try refreshing WaterlooWorks and retry."
|
||||
: error.message;
|
||||
reject(new Error(msg));
|
||||
return;
|
||||
}
|
||||
resolve(response);
|
||||
@@ -297,24 +320,28 @@ function ensurePort() {
|
||||
if (message?.type === "DELTA") {
|
||||
state.outputRaw += message.text;
|
||||
renderOutput();
|
||||
schedulePersistOutput();
|
||||
return;
|
||||
}
|
||||
|
||||
if (message?.type === "DONE") {
|
||||
setAnalyzing(false);
|
||||
setStatus("Done");
|
||||
void persistOutputNow();
|
||||
return;
|
||||
}
|
||||
|
||||
if (message?.type === "ABORTED") {
|
||||
setAnalyzing(false);
|
||||
setStatus("Aborted.");
|
||||
void persistOutputNow();
|
||||
return;
|
||||
}
|
||||
|
||||
if (message?.type === "ERROR") {
|
||||
setAnalyzing(false);
|
||||
setStatus(message.message || "Error during analysis.");
|
||||
void persistOutputNow();
|
||||
}
|
||||
});
|
||||
|
||||
@@ -401,6 +428,7 @@ async function handleAnalyze() {
|
||||
|
||||
state.outputRaw = "";
|
||||
renderOutput();
|
||||
void persistOutputNow();
|
||||
setAnalyzing(true);
|
||||
setStatus("Analyzing...");
|
||||
|
||||
@@ -434,6 +462,13 @@ function handleAbort() {
|
||||
setStatus("Aborted.");
|
||||
}
|
||||
|
||||
async function handleClearOutput() {
|
||||
state.outputRaw = "";
|
||||
renderOutput();
|
||||
await persistOutputNow();
|
||||
setStatus("Output cleared.");
|
||||
}
|
||||
|
||||
async function copyTextToClipboard(text, label) {
|
||||
try {
|
||||
await navigator.clipboard.writeText(text);
|
||||
@@ -468,6 +503,7 @@ abortBtn.addEventListener("click", handleAbort);
|
||||
settingsBtn.addEventListener("click", () => chrome.runtime.openOptionsPage());
|
||||
copyRenderedBtn.addEventListener("click", handleCopyRendered);
|
||||
copyRawBtn.addEventListener("click", handleCopyRaw);
|
||||
clearOutputBtn.addEventListener("click", () => void handleClearOutput());
|
||||
|
||||
updatePostingCount();
|
||||
updatePromptCount(0);
|
||||
@@ -476,6 +512,14 @@ setAnalyzing(false);
|
||||
loadTasks();
|
||||
loadTheme();
|
||||
|
||||
async function loadSavedOutput() {
|
||||
const stored = await getStorage([OUTPUT_STORAGE_KEY]);
|
||||
state.outputRaw = stored[OUTPUT_STORAGE_KEY] || "";
|
||||
renderOutput();
|
||||
}
|
||||
|
||||
loadSavedOutput();
|
||||
|
||||
chrome.storage.onChanged.addListener((changes) => {
|
||||
if (changes.theme) {
|
||||
applyTheme(changes.theme.newValue || "system");
|
||||
|
||||
Reference in New Issue
Block a user