reworked UI, moved environment selection to tasks
This commit is contained in:
@@ -242,6 +242,30 @@ chrome.runtime.onInstalled.addListener(async () => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const resolvedEnvConfigs = updates.envConfigs || stored.envConfigs || [];
|
||||||
|
const defaultEnvId =
|
||||||
|
resolvedEnvConfigs[0]?.id ||
|
||||||
|
updates.activeEnvConfigId ||
|
||||||
|
stored.activeEnvConfigId ||
|
||||||
|
"";
|
||||||
|
const taskSource = Array.isArray(updates.tasks)
|
||||||
|
? updates.tasks
|
||||||
|
: Array.isArray(stored.tasks)
|
||||||
|
? stored.tasks
|
||||||
|
: [];
|
||||||
|
if (taskSource.length) {
|
||||||
|
const normalizedTasks = taskSource.map((task) => ({
|
||||||
|
...task,
|
||||||
|
defaultEnvId: task.defaultEnvId || defaultEnvId
|
||||||
|
}));
|
||||||
|
const needsTaskUpdate = normalizedTasks.some(
|
||||||
|
(task, index) => task.defaultEnvId !== taskSource[index]?.defaultEnvId
|
||||||
|
);
|
||||||
|
if (needsTaskUpdate) {
|
||||||
|
updates.tasks = normalizedTasks;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (Object.keys(updates).length) {
|
if (Object.keys(updates).length) {
|
||||||
await chrome.storage.local.set(updates);
|
await chrome.storage.local.set(updates);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -127,28 +127,33 @@ select {
|
|||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.button-row {
|
.env-row {
|
||||||
display: grid;
|
display: flex;
|
||||||
grid-template-columns: minmax(64px, 0.8fr) minmax(0, 1.4fr) minmax(64px, 0.8fr);
|
align-items: flex-end;
|
||||||
|
}
|
||||||
|
|
||||||
|
.env-row .env-field {
|
||||||
|
flex: 1;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.task-row {
|
||||||
|
display: flex;
|
||||||
|
align-items: flex-end;
|
||||||
gap: 8px;
|
gap: 8px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.button-row button {
|
.task-row button {
|
||||||
white-space: nowrap;
|
padding: 6px 15px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.button-row .primary {
|
.task-row .task-field {
|
||||||
padding: 6px 8px;
|
flex: 1;
|
||||||
|
margin: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.stop-row {
|
.task-row select {
|
||||||
display: flex;
|
min-width: 0;
|
||||||
justify-content: stretch;
|
|
||||||
margin-top: 4px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.stop-row button {
|
|
||||||
width: 100%;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.hidden {
|
.hidden {
|
||||||
@@ -192,7 +197,7 @@ button:active {
|
|||||||
border: 1px solid var(--border);
|
border: 1px solid var(--border);
|
||||||
}
|
}
|
||||||
|
|
||||||
.stop-row .ghost {
|
.stop-btn {
|
||||||
background: #c0392b;
|
background: #c0392b;
|
||||||
border-color: #c0392b;
|
border-color: #c0392b;
|
||||||
color: #fff6f2;
|
color: #fff6f2;
|
||||||
|
|||||||
@@ -17,17 +17,19 @@
|
|||||||
<section class="panel">
|
<section class="panel">
|
||||||
<div class="controls-block">
|
<div class="controls-block">
|
||||||
<div class="config-block">
|
<div class="config-block">
|
||||||
<div class="field inline-field">
|
<div class="env-row">
|
||||||
<label for="taskSelect">Task</label>
|
<div class="field inline-field env-field">
|
||||||
<select id="taskSelect"></select>
|
<label for="envSelect">Environment</label>
|
||||||
|
<select id="envSelect"></select>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="button-row">
|
<div class="task-row">
|
||||||
<button id="extractBtn" class="primary">Extract</button>
|
<div class="field inline-field task-field">
|
||||||
<button id="extractRunBtn" class="accent">Extract & Run</button>
|
<label for="taskSelect">Task</label>
|
||||||
<button id="analyzeBtn" class="ghost">Run Task</button>
|
<select id="taskSelect"></select>
|
||||||
</div>
|
</div>
|
||||||
<div id="stopRow" class="stop-row hidden">
|
<button id="runBtn" class="accent">Run</button>
|
||||||
<button id="abortBtn" class="ghost" disabled>Stop</button>
|
<button id="abortBtn" class="ghost stop-btn hidden" disabled>Stop</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -1,10 +1,7 @@
|
|||||||
const extractBtn = document.getElementById("extractBtn");
|
const runBtn = document.getElementById("runBtn");
|
||||||
const analyzeBtn = document.getElementById("analyzeBtn");
|
|
||||||
const abortBtn = document.getElementById("abortBtn");
|
const abortBtn = document.getElementById("abortBtn");
|
||||||
const extractRunBtn = document.getElementById("extractRunBtn");
|
|
||||||
const stopRow = document.getElementById("stopRow");
|
|
||||||
const buttonRow = document.querySelector(".button-row");
|
|
||||||
const taskSelect = document.getElementById("taskSelect");
|
const taskSelect = document.getElementById("taskSelect");
|
||||||
|
const envSelect = document.getElementById("envSelect");
|
||||||
const outputEl = document.getElementById("output");
|
const outputEl = document.getElementById("output");
|
||||||
const statusEl = document.getElementById("status");
|
const statusEl = document.getElementById("status");
|
||||||
const postingCountEl = document.getElementById("postingCount");
|
const postingCountEl = document.getElementById("postingCount");
|
||||||
@@ -16,14 +13,19 @@ const clearOutputBtn = document.getElementById("clearOutputBtn");
|
|||||||
|
|
||||||
const OUTPUT_STORAGE_KEY = "lastOutput";
|
const OUTPUT_STORAGE_KEY = "lastOutput";
|
||||||
const AUTO_RUN_KEY = "autoRunDefaultTask";
|
const AUTO_RUN_KEY = "autoRunDefaultTask";
|
||||||
|
const LAST_TASK_KEY = "lastSelectedTaskId";
|
||||||
|
const LAST_ENV_KEY = "lastSelectedEnvId";
|
||||||
|
|
||||||
const state = {
|
const state = {
|
||||||
postingText: "",
|
postingText: "",
|
||||||
tasks: [],
|
tasks: [],
|
||||||
|
envs: [],
|
||||||
port: null,
|
port: null,
|
||||||
isAnalyzing: false,
|
isAnalyzing: false,
|
||||||
outputRaw: "",
|
outputRaw: "",
|
||||||
autoRunPending: false
|
autoRunPending: false,
|
||||||
|
selectedTaskId: "",
|
||||||
|
selectedEnvId: ""
|
||||||
};
|
};
|
||||||
|
|
||||||
function getStorage(keys) {
|
function getStorage(keys) {
|
||||||
@@ -245,15 +247,12 @@ function applyTheme(theme) {
|
|||||||
|
|
||||||
function setAnalyzing(isAnalyzing) {
|
function setAnalyzing(isAnalyzing) {
|
||||||
state.isAnalyzing = isAnalyzing;
|
state.isAnalyzing = isAnalyzing;
|
||||||
analyzeBtn.disabled = isAnalyzing;
|
runBtn.disabled = isAnalyzing;
|
||||||
abortBtn.disabled = !isAnalyzing;
|
abortBtn.disabled = !isAnalyzing;
|
||||||
extractBtn.disabled = isAnalyzing;
|
runBtn.classList.toggle("hidden", isAnalyzing);
|
||||||
extractRunBtn.disabled = isAnalyzing;
|
abortBtn.classList.toggle("hidden", !isAnalyzing);
|
||||||
if (buttonRow && stopRow) {
|
|
||||||
buttonRow.classList.toggle("hidden", isAnalyzing);
|
|
||||||
stopRow.classList.toggle("hidden", !isAnalyzing);
|
|
||||||
}
|
|
||||||
updateTaskSelectState();
|
updateTaskSelectState();
|
||||||
|
updateEnvSelectState();
|
||||||
}
|
}
|
||||||
|
|
||||||
function updatePostingCount() {
|
function updatePostingCount() {
|
||||||
@@ -286,11 +285,70 @@ function renderTasks(tasks) {
|
|||||||
updateTaskSelectState();
|
updateTaskSelectState();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function renderEnvironments(envs) {
|
||||||
|
state.envs = envs;
|
||||||
|
envSelect.innerHTML = "";
|
||||||
|
|
||||||
|
if (!envs.length) {
|
||||||
|
const option = document.createElement("option");
|
||||||
|
option.textContent = "No environments configured";
|
||||||
|
option.value = "";
|
||||||
|
envSelect.appendChild(option);
|
||||||
|
updateEnvSelectState();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const env of envs) {
|
||||||
|
const option = document.createElement("option");
|
||||||
|
option.value = env.id;
|
||||||
|
option.textContent = env.name || "Default";
|
||||||
|
envSelect.appendChild(option);
|
||||||
|
}
|
||||||
|
updateEnvSelectState();
|
||||||
|
}
|
||||||
|
|
||||||
function updateTaskSelectState() {
|
function updateTaskSelectState() {
|
||||||
const hasTasks = state.tasks.length > 0;
|
const hasTasks = state.tasks.length > 0;
|
||||||
taskSelect.disabled = state.isAnalyzing || !hasTasks;
|
taskSelect.disabled = state.isAnalyzing || !hasTasks;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function updateEnvSelectState() {
|
||||||
|
const hasEnvs = state.envs.length > 0;
|
||||||
|
envSelect.disabled = state.isAnalyzing || !hasEnvs;
|
||||||
|
}
|
||||||
|
|
||||||
|
function getTaskDefaultEnvId(task) {
|
||||||
|
return task?.defaultEnvId || state.envs[0]?.id || "";
|
||||||
|
}
|
||||||
|
|
||||||
|
function setEnvironmentSelection(envId) {
|
||||||
|
const target =
|
||||||
|
envId && state.envs.some((env) => env.id === envId)
|
||||||
|
? envId
|
||||||
|
: state.envs[0]?.id || "";
|
||||||
|
if (target) {
|
||||||
|
envSelect.value = target;
|
||||||
|
}
|
||||||
|
state.selectedEnvId = target;
|
||||||
|
}
|
||||||
|
|
||||||
|
function selectTask(taskId, { resetEnv } = { resetEnv: false }) {
|
||||||
|
if (!taskId) return;
|
||||||
|
taskSelect.value = taskId;
|
||||||
|
state.selectedTaskId = taskId;
|
||||||
|
const task = state.tasks.find((item) => item.id === taskId);
|
||||||
|
if (resetEnv) {
|
||||||
|
setEnvironmentSelection(getTaskDefaultEnvId(task));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function persistSelections() {
|
||||||
|
await chrome.storage.local.set({
|
||||||
|
[LAST_TASK_KEY]: state.selectedTaskId,
|
||||||
|
[LAST_ENV_KEY]: state.selectedEnvId
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
function isWaterlooWorksUrl(url) {
|
function isWaterlooWorksUrl(url) {
|
||||||
try {
|
try {
|
||||||
return new URL(url).hostname === "waterlooworks.uwaterloo.ca";
|
return new URL(url).hostname === "waterlooworks.uwaterloo.ca";
|
||||||
@@ -377,9 +435,45 @@ function ensurePort() {
|
|||||||
return port;
|
return port;
|
||||||
}
|
}
|
||||||
|
|
||||||
async function loadTasks() {
|
async function loadConfig() {
|
||||||
const { tasks = [] } = await getStorage(["tasks"]);
|
const stored = await getStorage([
|
||||||
|
"tasks",
|
||||||
|
"envConfigs",
|
||||||
|
LAST_TASK_KEY,
|
||||||
|
LAST_ENV_KEY
|
||||||
|
]);
|
||||||
|
const tasks = Array.isArray(stored.tasks) ? stored.tasks : [];
|
||||||
|
const envs = Array.isArray(stored.envConfigs) ? stored.envConfigs : [];
|
||||||
renderTasks(tasks);
|
renderTasks(tasks);
|
||||||
|
renderEnvironments(envs);
|
||||||
|
|
||||||
|
if (!tasks.length) {
|
||||||
|
state.selectedTaskId = "";
|
||||||
|
state.selectedEnvId = envs[0]?.id || "";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const storedTaskId = stored[LAST_TASK_KEY];
|
||||||
|
const storedEnvId = stored[LAST_ENV_KEY];
|
||||||
|
const initialTaskId = tasks.some((task) => task.id === storedTaskId)
|
||||||
|
? storedTaskId
|
||||||
|
: tasks[0].id;
|
||||||
|
selectTask(initialTaskId, { resetEnv: false });
|
||||||
|
|
||||||
|
const task = tasks.find((item) => item.id === initialTaskId);
|
||||||
|
if (storedEnvId && envs.some((env) => env.id === storedEnvId)) {
|
||||||
|
setEnvironmentSelection(storedEnvId);
|
||||||
|
} else {
|
||||||
|
setEnvironmentSelection(getTaskDefaultEnvId(task));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (
|
||||||
|
storedTaskId !== state.selectedTaskId ||
|
||||||
|
storedEnvId !== state.selectedEnvId
|
||||||
|
) {
|
||||||
|
await persistSelections();
|
||||||
|
}
|
||||||
|
|
||||||
maybeRunDefaultTask();
|
maybeRunDefaultTask();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -434,7 +528,6 @@ async function handleAnalyze() {
|
|||||||
apiConfigs = [],
|
apiConfigs = [],
|
||||||
activeApiConfigId = "",
|
activeApiConfigId = "",
|
||||||
envConfigs = [],
|
envConfigs = [],
|
||||||
activeEnvConfigId = "",
|
|
||||||
apiBaseUrl,
|
apiBaseUrl,
|
||||||
apiKeyHeader,
|
apiKeyHeader,
|
||||||
apiKeyPrefix,
|
apiKeyPrefix,
|
||||||
@@ -447,7 +540,6 @@ async function handleAnalyze() {
|
|||||||
"apiConfigs",
|
"apiConfigs",
|
||||||
"activeApiConfigId",
|
"activeApiConfigId",
|
||||||
"envConfigs",
|
"envConfigs",
|
||||||
"activeEnvConfigId",
|
|
||||||
"apiBaseUrl",
|
"apiBaseUrl",
|
||||||
"apiKeyHeader",
|
"apiKeyHeader",
|
||||||
"apiKeyPrefix",
|
"apiKeyPrefix",
|
||||||
@@ -458,13 +550,18 @@ async function handleAnalyze() {
|
|||||||
|
|
||||||
const resolvedConfigs = Array.isArray(apiConfigs) ? apiConfigs : [];
|
const resolvedConfigs = Array.isArray(apiConfigs) ? apiConfigs : [];
|
||||||
const resolvedEnvs = Array.isArray(envConfigs) ? envConfigs : [];
|
const resolvedEnvs = Array.isArray(envConfigs) ? envConfigs : [];
|
||||||
|
const selectedEnvId = envSelect.value;
|
||||||
const activeEnv =
|
const activeEnv =
|
||||||
resolvedEnvs.find((entry) => entry.id === activeEnvConfigId) ||
|
resolvedEnvs.find((entry) => entry.id === selectedEnvId) ||
|
||||||
resolvedEnvs[0];
|
resolvedEnvs[0];
|
||||||
|
if (!activeEnv) {
|
||||||
|
setStatus("Add an environment in Settings.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
const resolvedSystemPrompt =
|
const resolvedSystemPrompt =
|
||||||
activeEnv?.systemPrompt ?? systemPrompt ?? "";
|
activeEnv.systemPrompt ?? systemPrompt ?? "";
|
||||||
const resolvedApiConfigId =
|
const resolvedApiConfigId =
|
||||||
activeEnv?.apiConfigId || activeApiConfigId || resolvedConfigs[0]?.id || "";
|
activeEnv.apiConfigId || activeApiConfigId || resolvedConfigs[0]?.id || "";
|
||||||
const activeConfig =
|
const activeConfig =
|
||||||
resolvedConfigs.find((entry) => entry.id === resolvedApiConfigId) ||
|
resolvedConfigs.find((entry) => entry.id === resolvedApiConfigId) ||
|
||||||
resolvedConfigs[0];
|
resolvedConfigs[0];
|
||||||
@@ -593,20 +690,26 @@ function handleCopyRaw() {
|
|||||||
void copyTextToClipboard(text, "Markdown");
|
void copyTextToClipboard(text, "Markdown");
|
||||||
}
|
}
|
||||||
|
|
||||||
extractBtn.addEventListener("click", handleExtract);
|
runBtn.addEventListener("click", handleExtractAndAnalyze);
|
||||||
analyzeBtn.addEventListener("click", handleAnalyze);
|
|
||||||
extractRunBtn.addEventListener("click", handleExtractAndAnalyze);
|
|
||||||
abortBtn.addEventListener("click", handleAbort);
|
abortBtn.addEventListener("click", handleAbort);
|
||||||
settingsBtn.addEventListener("click", () => chrome.runtime.openOptionsPage());
|
settingsBtn.addEventListener("click", () => chrome.runtime.openOptionsPage());
|
||||||
copyRenderedBtn.addEventListener("click", handleCopyRendered);
|
copyRenderedBtn.addEventListener("click", handleCopyRendered);
|
||||||
copyRawBtn.addEventListener("click", handleCopyRaw);
|
copyRawBtn.addEventListener("click", handleCopyRaw);
|
||||||
clearOutputBtn.addEventListener("click", () => void handleClearOutput());
|
clearOutputBtn.addEventListener("click", () => void handleClearOutput());
|
||||||
|
taskSelect.addEventListener("change", () => {
|
||||||
|
selectTask(taskSelect.value, { resetEnv: true });
|
||||||
|
void persistSelections();
|
||||||
|
});
|
||||||
|
envSelect.addEventListener("change", () => {
|
||||||
|
setEnvironmentSelection(envSelect.value);
|
||||||
|
void persistSelections();
|
||||||
|
});
|
||||||
|
|
||||||
updatePostingCount();
|
updatePostingCount();
|
||||||
updatePromptCount(0);
|
updatePromptCount(0);
|
||||||
renderOutput();
|
renderOutput();
|
||||||
setAnalyzing(false);
|
setAnalyzing(false);
|
||||||
loadTasks();
|
loadConfig();
|
||||||
loadTheme();
|
loadTheme();
|
||||||
|
|
||||||
async function loadSavedOutput() {
|
async function loadSavedOutput() {
|
||||||
@@ -628,7 +731,8 @@ function maybeRunDefaultTask() {
|
|||||||
if (!state.autoRunPending) return;
|
if (!state.autoRunPending) return;
|
||||||
if (state.isAnalyzing) return;
|
if (state.isAnalyzing) return;
|
||||||
if (!state.tasks.length) return;
|
if (!state.tasks.length) return;
|
||||||
taskSelect.value = state.tasks[0].id;
|
selectTask(state.tasks[0].id, { resetEnv: true });
|
||||||
|
void persistSelections();
|
||||||
state.autoRunPending = false;
|
state.autoRunPending = false;
|
||||||
void handleExtractAndAnalyze();
|
void handleExtractAndAnalyze();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -78,17 +78,16 @@
|
|||||||
<span class="caret-closed">▸</span>
|
<span class="caret-closed">▸</span>
|
||||||
<span class="caret-open">▾</span>
|
<span class="caret-open">▾</span>
|
||||||
</span>
|
</span>
|
||||||
<h2>Environment</h2>
|
<div class="row-title">
|
||||||
|
<h2>Environment</h2>
|
||||||
|
<span class="hint hint-accent">API configuration and system prompt go here</span>
|
||||||
|
</div>
|
||||||
</summary>
|
</summary>
|
||||||
<div class="panel-body">
|
<div class="panel-body">
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div></div>
|
<div></div>
|
||||||
<button id="addEnvConfigBtn" class="ghost" type="button">Add Config</button>
|
<button id="addEnvConfigBtn" class="ghost" type="button">Add Config</button>
|
||||||
</div>
|
</div>
|
||||||
<div class="field">
|
|
||||||
<label for="activeEnvConfigSelect">Active environment</label>
|
|
||||||
<select id="activeEnvConfigSelect"></select>
|
|
||||||
</div>
|
|
||||||
<div id="envConfigs" class="env-configs"></div>
|
<div id="envConfigs" class="env-configs"></div>
|
||||||
</div>
|
</div>
|
||||||
</details>
|
</details>
|
||||||
@@ -99,7 +98,10 @@
|
|||||||
<span class="caret-closed">▸</span>
|
<span class="caret-closed">▸</span>
|
||||||
<span class="caret-open">▾</span>
|
<span class="caret-open">▾</span>
|
||||||
</span>
|
</span>
|
||||||
<h2>Resume</h2>
|
<div class="row-title">
|
||||||
|
<h2>Resume</h2>
|
||||||
|
<span class="hint hint-accent">Text to your profile goes here</span>
|
||||||
|
</div>
|
||||||
</summary>
|
</summary>
|
||||||
<div class="panel-body">
|
<div class="panel-body">
|
||||||
<textarea id="resume" rows="10" placeholder="Paste your resume text..."></textarea>
|
<textarea id="resume" rows="10" placeholder="Paste your resume text..."></textarea>
|
||||||
|
|||||||
@@ -6,7 +6,6 @@ const addApiKeyBtn = document.getElementById("addApiKeyBtn");
|
|||||||
const apiKeysContainer = document.getElementById("apiKeys");
|
const apiKeysContainer = document.getElementById("apiKeys");
|
||||||
const addEnvConfigBtn = document.getElementById("addEnvConfigBtn");
|
const addEnvConfigBtn = document.getElementById("addEnvConfigBtn");
|
||||||
const envConfigsContainer = document.getElementById("envConfigs");
|
const envConfigsContainer = document.getElementById("envConfigs");
|
||||||
const activeEnvConfigSelect = document.getElementById("activeEnvConfigSelect");
|
|
||||||
const addTaskBtn = document.getElementById("addTaskBtn");
|
const addTaskBtn = document.getElementById("addTaskBtn");
|
||||||
const tasksContainer = document.getElementById("tasks");
|
const tasksContainer = document.getElementById("tasks");
|
||||||
const statusEl = document.getElementById("status");
|
const statusEl = document.getElementById("status");
|
||||||
@@ -91,6 +90,10 @@ function ensureUniqueName(desired, existingNames) {
|
|||||||
return buildUniqueDefaultName(existingNames);
|
return buildUniqueDefaultName(existingNames);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function getTopEnvId() {
|
||||||
|
return collectEnvConfigs()[0]?.id || "";
|
||||||
|
}
|
||||||
|
|
||||||
function setApiConfigAdvanced(card, isAdvanced) {
|
function setApiConfigAdvanced(card, isAdvanced) {
|
||||||
card.classList.toggle("is-advanced", isAdvanced);
|
card.classList.toggle("is-advanced", isAdvanced);
|
||||||
card.dataset.mode = isAdvanced ? "advanced" : "basic";
|
card.dataset.mode = isAdvanced ? "advanced" : "basic";
|
||||||
@@ -250,6 +253,46 @@ function buildApiConfigCard(config) {
|
|||||||
|
|
||||||
const actions = document.createElement("div");
|
const actions = document.createElement("div");
|
||||||
actions.className = "api-config-actions";
|
actions.className = "api-config-actions";
|
||||||
|
const moveTopBtn = document.createElement("button");
|
||||||
|
moveTopBtn.type = "button";
|
||||||
|
moveTopBtn.className = "ghost move-top";
|
||||||
|
moveTopBtn.textContent = "Top";
|
||||||
|
const moveUpBtn = document.createElement("button");
|
||||||
|
moveUpBtn.type = "button";
|
||||||
|
moveUpBtn.className = "ghost move-up";
|
||||||
|
moveUpBtn.textContent = "Up";
|
||||||
|
const moveDownBtn = document.createElement("button");
|
||||||
|
moveDownBtn.type = "button";
|
||||||
|
moveDownBtn.className = "ghost move-down";
|
||||||
|
moveDownBtn.textContent = "Down";
|
||||||
|
|
||||||
|
moveTopBtn.addEventListener("click", () => {
|
||||||
|
const first = apiConfigsContainer.firstElementChild;
|
||||||
|
if (!first || first === card) return;
|
||||||
|
apiConfigsContainer.insertBefore(card, first);
|
||||||
|
updateApiConfigControls();
|
||||||
|
updateEnvApiOptions();
|
||||||
|
});
|
||||||
|
|
||||||
|
moveUpBtn.addEventListener("click", () => {
|
||||||
|
const previous = card.previousElementSibling;
|
||||||
|
if (!previous) return;
|
||||||
|
apiConfigsContainer.insertBefore(card, previous);
|
||||||
|
updateApiConfigControls();
|
||||||
|
updateEnvApiOptions();
|
||||||
|
});
|
||||||
|
|
||||||
|
moveDownBtn.addEventListener("click", () => {
|
||||||
|
const next = card.nextElementSibling;
|
||||||
|
if (!next) return;
|
||||||
|
apiConfigsContainer.insertBefore(card, next.nextElementSibling);
|
||||||
|
updateApiConfigControls();
|
||||||
|
updateEnvApiOptions();
|
||||||
|
});
|
||||||
|
|
||||||
|
actions.appendChild(moveTopBtn);
|
||||||
|
actions.appendChild(moveUpBtn);
|
||||||
|
actions.appendChild(moveDownBtn);
|
||||||
const advancedBtn = document.createElement("button");
|
const advancedBtn = document.createElement("button");
|
||||||
advancedBtn.type = "button";
|
advancedBtn.type = "button";
|
||||||
advancedBtn.className = "ghost advanced-toggle";
|
advancedBtn.className = "ghost advanced-toggle";
|
||||||
@@ -312,6 +355,7 @@ function buildApiConfigCard(config) {
|
|||||||
deleteBtn.addEventListener("click", () => {
|
deleteBtn.addEventListener("click", () => {
|
||||||
card.remove();
|
card.remove();
|
||||||
updateEnvApiOptions();
|
updateEnvApiOptions();
|
||||||
|
updateApiConfigControls();
|
||||||
});
|
});
|
||||||
actions.appendChild(deleteBtn);
|
actions.appendChild(deleteBtn);
|
||||||
|
|
||||||
@@ -344,6 +388,18 @@ function collectApiConfigs() {
|
|||||||
return cards.map((card) => readApiConfigFromCard(card));
|
return cards.map((card) => readApiConfigFromCard(card));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function updateApiConfigControls() {
|
||||||
|
const cards = [...apiConfigsContainer.querySelectorAll(".api-config-card")];
|
||||||
|
cards.forEach((card, index) => {
|
||||||
|
const moveTopBtn = card.querySelector(".move-top");
|
||||||
|
const moveUpBtn = card.querySelector(".move-up");
|
||||||
|
const moveDownBtn = card.querySelector(".move-down");
|
||||||
|
if (moveTopBtn) moveTopBtn.disabled = index === 0;
|
||||||
|
if (moveUpBtn) moveUpBtn.disabled = index === 0;
|
||||||
|
if (moveDownBtn) moveDownBtn.disabled = index === cards.length - 1;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
function buildApiKeyCard(entry) {
|
function buildApiKeyCard(entry) {
|
||||||
const card = document.createElement("div");
|
const card = document.createElement("div");
|
||||||
card.className = "api-key-card";
|
card.className = "api-key-card";
|
||||||
@@ -388,6 +444,46 @@ function buildApiKeyCard(entry) {
|
|||||||
|
|
||||||
const actions = document.createElement("div");
|
const actions = document.createElement("div");
|
||||||
actions.className = "api-key-actions";
|
actions.className = "api-key-actions";
|
||||||
|
const moveTopBtn = document.createElement("button");
|
||||||
|
moveTopBtn.type = "button";
|
||||||
|
moveTopBtn.className = "ghost move-top";
|
||||||
|
moveTopBtn.textContent = "Top";
|
||||||
|
const moveUpBtn = document.createElement("button");
|
||||||
|
moveUpBtn.type = "button";
|
||||||
|
moveUpBtn.className = "ghost move-up";
|
||||||
|
moveUpBtn.textContent = "Up";
|
||||||
|
const moveDownBtn = document.createElement("button");
|
||||||
|
moveDownBtn.type = "button";
|
||||||
|
moveDownBtn.className = "ghost move-down";
|
||||||
|
moveDownBtn.textContent = "Down";
|
||||||
|
|
||||||
|
moveTopBtn.addEventListener("click", () => {
|
||||||
|
const first = apiKeysContainer.firstElementChild;
|
||||||
|
if (!first || first === card) return;
|
||||||
|
apiKeysContainer.insertBefore(card, first);
|
||||||
|
updateApiKeyControls();
|
||||||
|
updateApiConfigKeyOptions();
|
||||||
|
});
|
||||||
|
|
||||||
|
moveUpBtn.addEventListener("click", () => {
|
||||||
|
const previous = card.previousElementSibling;
|
||||||
|
if (!previous) return;
|
||||||
|
apiKeysContainer.insertBefore(card, previous);
|
||||||
|
updateApiKeyControls();
|
||||||
|
updateApiConfigKeyOptions();
|
||||||
|
});
|
||||||
|
|
||||||
|
moveDownBtn.addEventListener("click", () => {
|
||||||
|
const next = card.nextElementSibling;
|
||||||
|
if (!next) return;
|
||||||
|
apiKeysContainer.insertBefore(card, next.nextElementSibling);
|
||||||
|
updateApiKeyControls();
|
||||||
|
updateApiConfigKeyOptions();
|
||||||
|
});
|
||||||
|
|
||||||
|
actions.appendChild(moveTopBtn);
|
||||||
|
actions.appendChild(moveUpBtn);
|
||||||
|
actions.appendChild(moveDownBtn);
|
||||||
const deleteBtn = document.createElement("button");
|
const deleteBtn = document.createElement("button");
|
||||||
deleteBtn.type = "button";
|
deleteBtn.type = "button";
|
||||||
deleteBtn.className = "ghost delete";
|
deleteBtn.className = "ghost delete";
|
||||||
@@ -395,6 +491,7 @@ function buildApiKeyCard(entry) {
|
|||||||
deleteBtn.addEventListener("click", () => {
|
deleteBtn.addEventListener("click", () => {
|
||||||
card.remove();
|
card.remove();
|
||||||
updateApiConfigKeyOptions();
|
updateApiConfigKeyOptions();
|
||||||
|
updateApiKeyControls();
|
||||||
});
|
});
|
||||||
actions.appendChild(deleteBtn);
|
actions.appendChild(deleteBtn);
|
||||||
|
|
||||||
@@ -422,6 +519,18 @@ function collectApiKeys() {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function updateApiKeyControls() {
|
||||||
|
const cards = [...apiKeysContainer.querySelectorAll(".api-key-card")];
|
||||||
|
cards.forEach((card, index) => {
|
||||||
|
const moveTopBtn = card.querySelector(".move-top");
|
||||||
|
const moveUpBtn = card.querySelector(".move-up");
|
||||||
|
const moveDownBtn = card.querySelector(".move-down");
|
||||||
|
if (moveTopBtn) moveTopBtn.disabled = index === 0;
|
||||||
|
if (moveUpBtn) moveUpBtn.disabled = index === 0;
|
||||||
|
if (moveDownBtn) moveDownBtn.disabled = index === cards.length - 1;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
function updateApiConfigKeyOptions() {
|
function updateApiConfigKeyOptions() {
|
||||||
const keys = collectApiKeys();
|
const keys = collectApiKeys();
|
||||||
const selects = apiConfigsContainer.querySelectorAll(".api-config-key-select");
|
const selects = apiConfigsContainer.querySelectorAll(".api-config-key-select");
|
||||||
@@ -494,6 +603,46 @@ function buildEnvConfigCard(config) {
|
|||||||
|
|
||||||
const actions = document.createElement("div");
|
const actions = document.createElement("div");
|
||||||
actions.className = "env-config-actions";
|
actions.className = "env-config-actions";
|
||||||
|
const moveTopBtn = document.createElement("button");
|
||||||
|
moveTopBtn.type = "button";
|
||||||
|
moveTopBtn.className = "ghost move-top";
|
||||||
|
moveTopBtn.textContent = "Top";
|
||||||
|
const moveUpBtn = document.createElement("button");
|
||||||
|
moveUpBtn.type = "button";
|
||||||
|
moveUpBtn.className = "ghost move-up";
|
||||||
|
moveUpBtn.textContent = "Up";
|
||||||
|
const moveDownBtn = document.createElement("button");
|
||||||
|
moveDownBtn.type = "button";
|
||||||
|
moveDownBtn.className = "ghost move-down";
|
||||||
|
moveDownBtn.textContent = "Down";
|
||||||
|
|
||||||
|
moveTopBtn.addEventListener("click", () => {
|
||||||
|
const first = envConfigsContainer.firstElementChild;
|
||||||
|
if (!first || first === card) return;
|
||||||
|
envConfigsContainer.insertBefore(card, first);
|
||||||
|
updateEnvControls();
|
||||||
|
updateTaskEnvOptions();
|
||||||
|
});
|
||||||
|
|
||||||
|
moveUpBtn.addEventListener("click", () => {
|
||||||
|
const previous = card.previousElementSibling;
|
||||||
|
if (!previous) return;
|
||||||
|
envConfigsContainer.insertBefore(card, previous);
|
||||||
|
updateEnvControls();
|
||||||
|
updateTaskEnvOptions();
|
||||||
|
});
|
||||||
|
|
||||||
|
moveDownBtn.addEventListener("click", () => {
|
||||||
|
const next = card.nextElementSibling;
|
||||||
|
if (!next) return;
|
||||||
|
envConfigsContainer.insertBefore(card, next.nextElementSibling);
|
||||||
|
updateEnvControls();
|
||||||
|
updateTaskEnvOptions();
|
||||||
|
});
|
||||||
|
|
||||||
|
actions.appendChild(moveTopBtn);
|
||||||
|
actions.appendChild(moveUpBtn);
|
||||||
|
actions.appendChild(moveDownBtn);
|
||||||
|
|
||||||
const duplicateBtn = document.createElement("button");
|
const duplicateBtn = document.createElement("button");
|
||||||
duplicateBtn.type = "button";
|
duplicateBtn.type = "button";
|
||||||
@@ -515,7 +664,8 @@ function buildEnvConfigCard(config) {
|
|||||||
});
|
});
|
||||||
card.insertAdjacentElement("afterend", newCard);
|
card.insertAdjacentElement("afterend", newCard);
|
||||||
updateEnvApiOptions();
|
updateEnvApiOptions();
|
||||||
updateEnvConfigSelect(newCard.dataset.id);
|
updateEnvControls();
|
||||||
|
updateTaskEnvOptions();
|
||||||
});
|
});
|
||||||
|
|
||||||
const deleteBtn = document.createElement("button");
|
const deleteBtn = document.createElement("button");
|
||||||
@@ -524,15 +674,13 @@ function buildEnvConfigCard(config) {
|
|||||||
deleteBtn.textContent = "Delete";
|
deleteBtn.textContent = "Delete";
|
||||||
deleteBtn.addEventListener("click", () => {
|
deleteBtn.addEventListener("click", () => {
|
||||||
card.remove();
|
card.remove();
|
||||||
updateEnvConfigSelect(activeEnvConfigSelect.value);
|
updateEnvControls();
|
||||||
|
updateTaskEnvOptions();
|
||||||
});
|
});
|
||||||
|
|
||||||
actions.appendChild(duplicateBtn);
|
actions.appendChild(duplicateBtn);
|
||||||
actions.appendChild(deleteBtn);
|
actions.appendChild(deleteBtn);
|
||||||
|
nameInput.addEventListener("input", () => updateEnvApiOptions());
|
||||||
nameInput.addEventListener("input", () =>
|
|
||||||
updateEnvConfigSelect(activeEnvConfigSelect.value)
|
|
||||||
);
|
|
||||||
|
|
||||||
card.appendChild(nameField);
|
card.appendChild(nameField);
|
||||||
card.appendChild(apiField);
|
card.appendChild(apiField);
|
||||||
@@ -542,6 +690,51 @@ function buildEnvConfigCard(config) {
|
|||||||
return card;
|
return card;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function updateEnvControls() {
|
||||||
|
const cards = [...envConfigsContainer.querySelectorAll(".env-config-card")];
|
||||||
|
cards.forEach((card, index) => {
|
||||||
|
const moveTopBtn = card.querySelector(".move-top");
|
||||||
|
const moveUpBtn = card.querySelector(".move-up");
|
||||||
|
const moveDownBtn = card.querySelector(".move-down");
|
||||||
|
if (moveTopBtn) moveTopBtn.disabled = index === 0;
|
||||||
|
if (moveUpBtn) moveUpBtn.disabled = index === 0;
|
||||||
|
if (moveDownBtn) moveDownBtn.disabled = index === cards.length - 1;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function updateTaskEnvOptions() {
|
||||||
|
const envs = collectEnvConfigs();
|
||||||
|
const selects = tasksContainer.querySelectorAll(".task-env-select");
|
||||||
|
selects.forEach((select) => {
|
||||||
|
const preferred = select.dataset.preferred || select.value;
|
||||||
|
select.innerHTML = "";
|
||||||
|
if (!envs.length) {
|
||||||
|
const option = document.createElement("option");
|
||||||
|
option.value = "";
|
||||||
|
option.textContent = "No environments configured";
|
||||||
|
select.appendChild(option);
|
||||||
|
select.disabled = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
select.disabled = false;
|
||||||
|
for (const env of envs) {
|
||||||
|
const option = document.createElement("option");
|
||||||
|
option.value = env.id;
|
||||||
|
option.textContent = env.name || "Default";
|
||||||
|
select.appendChild(option);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (preferred && envs.some((env) => env.id === preferred)) {
|
||||||
|
select.value = preferred;
|
||||||
|
} else {
|
||||||
|
select.value = envs[0].id;
|
||||||
|
}
|
||||||
|
|
||||||
|
select.dataset.preferred = select.value;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
function collectEnvConfigs() {
|
function collectEnvConfigs() {
|
||||||
const cards = [...envConfigsContainer.querySelectorAll(".env-config-card")];
|
const cards = [...envConfigsContainer.querySelectorAll(".env-config-card")];
|
||||||
return cards.map((card) => {
|
return cards.map((card) => {
|
||||||
@@ -557,35 +750,6 @@ function collectEnvConfigs() {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function updateEnvConfigSelect(preferredId) {
|
|
||||||
const configs = collectEnvConfigs();
|
|
||||||
activeEnvConfigSelect.innerHTML = "";
|
|
||||||
|
|
||||||
if (!configs.length) {
|
|
||||||
const option = document.createElement("option");
|
|
||||||
option.value = "";
|
|
||||||
option.textContent = "No environments configured";
|
|
||||||
activeEnvConfigSelect.appendChild(option);
|
|
||||||
activeEnvConfigSelect.disabled = true;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
activeEnvConfigSelect.disabled = false;
|
|
||||||
const selectedId =
|
|
||||||
preferredId && configs.some((config) => config.id === preferredId)
|
|
||||||
? preferredId
|
|
||||||
: configs[0].id;
|
|
||||||
|
|
||||||
for (const config of configs) {
|
|
||||||
const option = document.createElement("option");
|
|
||||||
option.value = config.id;
|
|
||||||
option.textContent = config.name || "Default";
|
|
||||||
activeEnvConfigSelect.appendChild(option);
|
|
||||||
}
|
|
||||||
|
|
||||||
activeEnvConfigSelect.value = selectedId;
|
|
||||||
}
|
|
||||||
|
|
||||||
function updateEnvApiOptions() {
|
function updateEnvApiOptions() {
|
||||||
const apiConfigs = collectApiConfigs();
|
const apiConfigs = collectApiConfigs();
|
||||||
const selects = envConfigsContainer.querySelectorAll(".env-config-api-select");
|
const selects = envConfigsContainer.querySelectorAll(".env-config-api-select");
|
||||||
@@ -617,6 +781,7 @@ function updateEnvApiOptions() {
|
|||||||
|
|
||||||
select.dataset.preferred = select.value;
|
select.dataset.preferred = select.value;
|
||||||
});
|
});
|
||||||
|
updateTaskEnvOptions();
|
||||||
}
|
}
|
||||||
|
|
||||||
function buildTaskCard(task) {
|
function buildTaskCard(task) {
|
||||||
@@ -635,6 +800,16 @@ function buildTaskCard(task) {
|
|||||||
nameField.appendChild(nameLabel);
|
nameField.appendChild(nameLabel);
|
||||||
nameField.appendChild(nameInput);
|
nameField.appendChild(nameInput);
|
||||||
|
|
||||||
|
const envField = document.createElement("div");
|
||||||
|
envField.className = "field";
|
||||||
|
const envLabel = document.createElement("label");
|
||||||
|
envLabel.textContent = "Default environment";
|
||||||
|
const envSelect = document.createElement("select");
|
||||||
|
envSelect.className = "task-env-select";
|
||||||
|
envSelect.dataset.preferred = task.defaultEnvId || "";
|
||||||
|
envField.appendChild(envLabel);
|
||||||
|
envField.appendChild(envSelect);
|
||||||
|
|
||||||
const textField = document.createElement("div");
|
const textField = document.createElement("div");
|
||||||
textField.className = "field";
|
textField.className = "field";
|
||||||
const textLabel = document.createElement("label");
|
const textLabel = document.createElement("label");
|
||||||
@@ -710,9 +885,15 @@ function buildTaskCard(task) {
|
|||||||
const name = buildUniqueDefaultName(
|
const name = buildUniqueDefaultName(
|
||||||
collectNames(tasksContainer, ".task-name")
|
collectNames(tasksContainer, ".task-name")
|
||||||
);
|
);
|
||||||
const newCard = buildTaskCard({ id: newTaskId(), name, text: "" });
|
const newCard = buildTaskCard({
|
||||||
|
id: newTaskId(),
|
||||||
|
name,
|
||||||
|
text: "",
|
||||||
|
defaultEnvId: getTopEnvId()
|
||||||
|
});
|
||||||
card.insertAdjacentElement("afterend", newCard);
|
card.insertAdjacentElement("afterend", newCard);
|
||||||
updateTaskControls();
|
updateTaskControls();
|
||||||
|
updateTaskEnvOptions();
|
||||||
});
|
});
|
||||||
|
|
||||||
duplicateBtn.addEventListener("click", () => {
|
duplicateBtn.addEventListener("click", () => {
|
||||||
@@ -722,11 +903,13 @@ function buildTaskCard(task) {
|
|||||||
`${nameInput.value || "Untitled"} Copy`,
|
`${nameInput.value || "Untitled"} Copy`,
|
||||||
collectNames(tasksContainer, ".task-name")
|
collectNames(tasksContainer, ".task-name")
|
||||||
),
|
),
|
||||||
text: textArea.value
|
text: textArea.value,
|
||||||
|
defaultEnvId: envSelect.value || ""
|
||||||
};
|
};
|
||||||
const newCard = buildTaskCard(copy);
|
const newCard = buildTaskCard(copy);
|
||||||
card.insertAdjacentElement("afterend", newCard);
|
card.insertAdjacentElement("afterend", newCard);
|
||||||
updateTaskControls();
|
updateTaskControls();
|
||||||
|
updateTaskEnvOptions();
|
||||||
});
|
});
|
||||||
|
|
||||||
deleteBtn.addEventListener("click", () => {
|
deleteBtn.addEventListener("click", () => {
|
||||||
@@ -742,6 +925,7 @@ function buildTaskCard(task) {
|
|||||||
actions.appendChild(deleteBtn);
|
actions.appendChild(deleteBtn);
|
||||||
|
|
||||||
card.appendChild(nameField);
|
card.appendChild(nameField);
|
||||||
|
card.appendChild(envField);
|
||||||
card.appendChild(textField);
|
card.appendChild(textField);
|
||||||
card.appendChild(actions);
|
card.appendChild(actions);
|
||||||
|
|
||||||
@@ -765,10 +949,12 @@ function collectTasks() {
|
|||||||
return cards.map((card) => {
|
return cards.map((card) => {
|
||||||
const nameInput = card.querySelector(".task-name");
|
const nameInput = card.querySelector(".task-name");
|
||||||
const textArea = card.querySelector(".task-text");
|
const textArea = card.querySelector(".task-text");
|
||||||
|
const envSelect = card.querySelector(".task-env-select");
|
||||||
return {
|
return {
|
||||||
id: card.dataset.id || newTaskId(),
|
id: card.dataset.id || newTaskId(),
|
||||||
name: (nameInput?.value || "Untitled Task").trim(),
|
name: (nameInput?.value || "Untitled Task").trim(),
|
||||||
text: (textArea?.value || "").trim()
|
text: (textArea?.value || "").trim(),
|
||||||
|
defaultEnvId: envSelect?.value || ""
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -841,6 +1027,7 @@ async function loadSettings() {
|
|||||||
apiKeysContainer.appendChild(buildApiKeyCard(entry));
|
apiKeysContainer.appendChild(buildApiKeyCard(entry));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
updateApiKeyControls();
|
||||||
|
|
||||||
let resolvedConfigs = Array.isArray(apiConfigs) ? apiConfigs : [];
|
let resolvedConfigs = Array.isArray(apiConfigs) ? apiConfigs : [];
|
||||||
let resolvedActiveConfigId = activeApiConfigId;
|
let resolvedActiveConfigId = activeApiConfigId;
|
||||||
@@ -891,9 +1078,9 @@ async function loadSettings() {
|
|||||||
apiConfigsContainer.appendChild(buildApiConfigCard(config));
|
apiConfigsContainer.appendChild(buildApiConfigCard(config));
|
||||||
}
|
}
|
||||||
updateApiConfigKeyOptions();
|
updateApiConfigKeyOptions();
|
||||||
|
updateApiConfigControls();
|
||||||
|
|
||||||
let resolvedEnvConfigs = Array.isArray(envConfigs) ? envConfigs : [];
|
let resolvedEnvConfigs = Array.isArray(envConfigs) ? envConfigs : [];
|
||||||
let resolvedActiveEnvId = activeEnvConfigId;
|
|
||||||
const fallbackApiConfigId =
|
const fallbackApiConfigId =
|
||||||
resolvedActiveConfigId || resolvedConfigs[0]?.id || "";
|
resolvedActiveConfigId || resolvedConfigs[0]?.id || "";
|
||||||
|
|
||||||
@@ -905,10 +1092,9 @@ async function loadSettings() {
|
|||||||
systemPrompt: systemPrompt || DEFAULT_SYSTEM_PROMPT
|
systemPrompt: systemPrompt || DEFAULT_SYSTEM_PROMPT
|
||||||
};
|
};
|
||||||
resolvedEnvConfigs = [migrated];
|
resolvedEnvConfigs = [migrated];
|
||||||
resolvedActiveEnvId = migrated.id;
|
|
||||||
await chrome.storage.local.set({
|
await chrome.storage.local.set({
|
||||||
envConfigs: resolvedEnvConfigs,
|
envConfigs: resolvedEnvConfigs,
|
||||||
activeEnvConfigId: resolvedActiveEnvId
|
activeEnvConfigId: migrated.id
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
const withDefaults = resolvedEnvConfigs.map((config) => ({
|
const withDefaults = resolvedEnvConfigs.map((config) => ({
|
||||||
@@ -928,11 +1114,12 @@ async function loadSettings() {
|
|||||||
await chrome.storage.local.set({ envConfigs: resolvedEnvConfigs });
|
await chrome.storage.local.set({ envConfigs: resolvedEnvConfigs });
|
||||||
}
|
}
|
||||||
const hasActive = resolvedEnvConfigs.some(
|
const hasActive = resolvedEnvConfigs.some(
|
||||||
(config) => config.id === resolvedActiveEnvId
|
(config) => config.id === activeEnvConfigId
|
||||||
);
|
);
|
||||||
if (!hasActive) {
|
if (!hasActive && resolvedEnvConfigs.length) {
|
||||||
resolvedActiveEnvId = resolvedEnvConfigs[0].id;
|
await chrome.storage.local.set({
|
||||||
await chrome.storage.local.set({ activeEnvConfigId: resolvedActiveEnvId });
|
activeEnvConfigId: resolvedEnvConfigs[0].id
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -941,21 +1128,44 @@ async function loadSettings() {
|
|||||||
envConfigsContainer.appendChild(buildEnvConfigCard(config));
|
envConfigsContainer.appendChild(buildEnvConfigCard(config));
|
||||||
}
|
}
|
||||||
updateEnvApiOptions();
|
updateEnvApiOptions();
|
||||||
updateEnvConfigSelect(resolvedActiveEnvId);
|
updateEnvControls();
|
||||||
|
|
||||||
tasksContainer.innerHTML = "";
|
tasksContainer.innerHTML = "";
|
||||||
if (!tasks.length) {
|
const defaultEnvId = resolvedEnvConfigs[0]?.id || "";
|
||||||
|
const normalizedTasks = Array.isArray(tasks)
|
||||||
|
? tasks.map((task) => ({
|
||||||
|
...task,
|
||||||
|
defaultEnvId: task.defaultEnvId || defaultEnvId
|
||||||
|
}))
|
||||||
|
: [];
|
||||||
|
if (
|
||||||
|
normalizedTasks.length &&
|
||||||
|
normalizedTasks.some(
|
||||||
|
(task, index) => task.defaultEnvId !== tasks[index]?.defaultEnvId
|
||||||
|
)
|
||||||
|
) {
|
||||||
|
await chrome.storage.local.set({ tasks: normalizedTasks });
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!normalizedTasks.length) {
|
||||||
tasksContainer.appendChild(
|
tasksContainer.appendChild(
|
||||||
buildTaskCard({ id: newTaskId(), name: "", text: "" })
|
buildTaskCard({
|
||||||
|
id: newTaskId(),
|
||||||
|
name: "",
|
||||||
|
text: "",
|
||||||
|
defaultEnvId
|
||||||
|
})
|
||||||
);
|
);
|
||||||
updateTaskControls();
|
updateTaskControls();
|
||||||
|
updateTaskEnvOptions();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (const task of tasks) {
|
for (const task of normalizedTasks) {
|
||||||
tasksContainer.appendChild(buildTaskCard(task));
|
tasksContainer.appendChild(buildTaskCard(task));
|
||||||
}
|
}
|
||||||
updateTaskControls();
|
updateTaskControls();
|
||||||
|
updateTaskEnvOptions();
|
||||||
}
|
}
|
||||||
|
|
||||||
async function saveSettings() {
|
async function saveSettings() {
|
||||||
@@ -963,11 +1173,8 @@ async function saveSettings() {
|
|||||||
const apiKeys = collectApiKeys();
|
const apiKeys = collectApiKeys();
|
||||||
const apiConfigs = collectApiConfigs();
|
const apiConfigs = collectApiConfigs();
|
||||||
const envConfigs = collectEnvConfigs();
|
const envConfigs = collectEnvConfigs();
|
||||||
const activeEnvConfigId =
|
const activeEnvConfigId = envConfigs[0]?.id || "";
|
||||||
envConfigs.find((entry) => entry.id === activeEnvConfigSelect.value)?.id ||
|
const activeEnv = envConfigs[0];
|
||||||
envConfigs[0]?.id ||
|
|
||||||
"";
|
|
||||||
const activeEnv = envConfigs.find((entry) => entry.id === activeEnvConfigId);
|
|
||||||
const activeApiConfigId =
|
const activeApiConfigId =
|
||||||
activeEnv?.apiConfigId || apiConfigs[0]?.id || "";
|
activeEnv?.apiConfigId || apiConfigs[0]?.id || "";
|
||||||
const activeConfig = apiConfigs.find((entry) => entry.id === activeApiConfigId);
|
const activeConfig = apiConfigs.find((entry) => entry.id === activeApiConfigId);
|
||||||
@@ -995,7 +1202,12 @@ addTaskBtn.addEventListener("click", () => {
|
|||||||
const name = buildUniqueDefaultName(
|
const name = buildUniqueDefaultName(
|
||||||
collectNames(tasksContainer, ".task-name")
|
collectNames(tasksContainer, ".task-name")
|
||||||
);
|
);
|
||||||
const newCard = buildTaskCard({ id: newTaskId(), name, text: "" });
|
const newCard = buildTaskCard({
|
||||||
|
id: newTaskId(),
|
||||||
|
name,
|
||||||
|
text: "",
|
||||||
|
defaultEnvId: getTopEnvId()
|
||||||
|
});
|
||||||
const first = tasksContainer.firstElementChild;
|
const first = tasksContainer.firstElementChild;
|
||||||
if (first) {
|
if (first) {
|
||||||
tasksContainer.insertBefore(newCard, first);
|
tasksContainer.insertBefore(newCard, first);
|
||||||
@@ -1003,6 +1215,7 @@ addTaskBtn.addEventListener("click", () => {
|
|||||||
tasksContainer.appendChild(newCard);
|
tasksContainer.appendChild(newCard);
|
||||||
}
|
}
|
||||||
updateTaskControls();
|
updateTaskControls();
|
||||||
|
updateTaskEnvOptions();
|
||||||
});
|
});
|
||||||
|
|
||||||
addApiKeyBtn.addEventListener("click", () => {
|
addApiKeyBtn.addEventListener("click", () => {
|
||||||
@@ -1017,6 +1230,7 @@ addApiKeyBtn.addEventListener("click", () => {
|
|||||||
apiKeysContainer.appendChild(newCard);
|
apiKeysContainer.appendChild(newCard);
|
||||||
}
|
}
|
||||||
updateApiConfigKeyOptions();
|
updateApiConfigKeyOptions();
|
||||||
|
updateApiKeyControls();
|
||||||
});
|
});
|
||||||
|
|
||||||
addApiConfigBtn.addEventListener("click", () => {
|
addApiConfigBtn.addEventListener("click", () => {
|
||||||
@@ -1042,6 +1256,7 @@ addApiConfigBtn.addEventListener("click", () => {
|
|||||||
}
|
}
|
||||||
updateApiConfigKeyOptions();
|
updateApiConfigKeyOptions();
|
||||||
updateEnvApiOptions();
|
updateEnvApiOptions();
|
||||||
|
updateApiConfigControls();
|
||||||
});
|
});
|
||||||
|
|
||||||
addEnvConfigBtn.addEventListener("click", () => {
|
addEnvConfigBtn.addEventListener("click", () => {
|
||||||
@@ -1062,11 +1277,8 @@ addEnvConfigBtn.addEventListener("click", () => {
|
|||||||
envConfigsContainer.appendChild(newCard);
|
envConfigsContainer.appendChild(newCard);
|
||||||
}
|
}
|
||||||
updateEnvApiOptions();
|
updateEnvApiOptions();
|
||||||
updateEnvConfigSelect(newCard.dataset.id);
|
updateEnvControls();
|
||||||
});
|
updateTaskEnvOptions();
|
||||||
|
|
||||||
activeEnvConfigSelect.addEventListener("change", () => {
|
|
||||||
updateEnvConfigSelect(activeEnvConfigSelect.value);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
themeSelect.addEventListener("change", () => applyTheme(themeSelect.value));
|
themeSelect.addEventListener("change", () => applyTheme(themeSelect.value));
|
||||||
|
|||||||
Reference in New Issue
Block a user