mirror of
https://github.com/khoaliber/khoj.git
synced 2026-03-08 21:29:12 +00:00
Generate automation cards via DOM scripting
This commit is contained in:
@@ -388,86 +388,132 @@
|
|||||||
function generateAutomationRow(automation, isSuggested=false) {
|
function generateAutomationRow(automation, isSuggested=false) {
|
||||||
let automationId = automation.id;
|
let automationId = automation.id;
|
||||||
let automationNextRun = `Next run at ${automation.next}\nCron: ${automation.crontime}`;
|
let automationNextRun = `Next run at ${automation.next}\nCron: ${automation.crontime}`;
|
||||||
|
|
||||||
|
// Create card top elements
|
||||||
let automationEl = document.createElement("div");
|
let automationEl = document.createElement("div");
|
||||||
automationEl.innerHTML = `
|
let automationCardEl = document.createElement("div");
|
||||||
<div class="card automation" id="automation-card-${automationId}">
|
automationCardEl.id = `automation-card-${automationId}`;
|
||||||
<div class="card-header" onclick="onClickEditAutomationCard('${automationId}')">
|
automationCardEl.classList.add("card", "automation");
|
||||||
<div class="subject-wrapper">
|
|
||||||
<input type="text"
|
|
||||||
id="automation-subject-${automationId}"
|
|
||||||
class="${automationId} fake-input"
|
|
||||||
name="subject"
|
|
||||||
data-original="${automation.subject}"
|
|
||||||
value="${automation.subject}">
|
|
||||||
<img class=automation-share-icon id="share-link-${automationId}" src="/static/assets/icons/share.svg" alt="Share" onclick="copyShareLink(event, '${automationId}', '${automation.subject}', '${automation.crontime}', '${automation.query_to_run}')">
|
|
||||||
<img class="automation-edit-icon ${automationId}" src="/static/assets/icons/pencil-edit.svg" onclick="onClickEditAutomationCard('${automationId}')" alt="Automations">
|
|
||||||
</div>
|
|
||||||
<input type="text"
|
|
||||||
id="automation-schedule-${automationId}"
|
|
||||||
name="schedule"
|
|
||||||
class="schedule ${automationId} fake-input"
|
|
||||||
data-cron="${automation.crontime}"
|
|
||||||
data-original="${automation.schedule}"
|
|
||||||
title="${automationNextRun}"
|
|
||||||
value="${automation.schedule}">
|
|
||||||
<textarea id="automation-queryToRun-${automationId}"
|
|
||||||
class="automation-instructions ${automationId} fake-input"
|
|
||||||
data-original="${automation.query_to_run}"
|
|
||||||
name="query-to-run">${automation.query_to_run}</textarea>
|
|
||||||
${isSuggested ?
|
|
||||||
`<img class=promo-image src="${automation.promoImage}" alt="Promo Image">`:
|
|
||||||
""
|
|
||||||
}
|
|
||||||
</div>
|
|
||||||
<div id="automation-buttons-wrapper">
|
|
||||||
<div class="automation-buttons">
|
|
||||||
${isSuggested ?
|
|
||||||
`<div id="empty-div"></div>
|
|
||||||
<div id="empty-div"></div>`:
|
|
||||||
`
|
|
||||||
<button type="button"
|
|
||||||
class="delete-automation-button negative-button"
|
|
||||||
id="delete-automation-button-${automationId}">Delete</button>
|
|
||||||
<button type="button"
|
|
||||||
class="send-preview-automation-button positive-button"
|
|
||||||
title="Immediately get a preview of this automation"
|
|
||||||
onclick="sendAPreviewAutomation('${automationId}')">Preview</button>
|
|
||||||
`
|
|
||||||
}
|
|
||||||
<button type="button"
|
|
||||||
class="save-automation-button positive-button"
|
|
||||||
id="save-automation-button-${automationId}">
|
|
||||||
${isSuggested ? "Add" : "Save"}
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div id="automation-success-${automationId}" style="display: none;"></div>
|
|
||||||
</div>
|
|
||||||
`;
|
|
||||||
|
|
||||||
let automationButtonsSection = automationEl.querySelector(".automation-buttons");
|
// Create card header elements
|
||||||
|
let automationCardFormEl = document.createElement("div");
|
||||||
|
automationCardFormEl.className = "card-header";
|
||||||
|
|
||||||
|
let automationButtonsWrapperEl = document.createElement("div");
|
||||||
|
automationButtonsWrapperEl.id = "automation-buttons-wrapper";
|
||||||
|
|
||||||
|
let automationSuccessEl = document.createElement("div");
|
||||||
|
automationSuccessEl.id = `automation-success-${automationId}`;
|
||||||
|
automationSuccessEl.style.display = "none";
|
||||||
|
|
||||||
|
// Create automation card form section
|
||||||
|
automationCardFormEl.onclick = function() { onClickEditAutomationCard(automationId); };
|
||||||
|
|
||||||
|
// automation subject input
|
||||||
|
let subjectWrapperEl = document.createElement("div");
|
||||||
|
subjectWrapperEl.className = "subject-wrapper";
|
||||||
|
let subjectEl = document.createElement("input");
|
||||||
|
subjectEl.type = "text";
|
||||||
|
subjectEl.id = `automation-subject-${automationId}`;
|
||||||
|
subjectEl.classList.add(automationId, "fake-input");
|
||||||
|
subjectEl.name = "subject";
|
||||||
|
subjectEl.setAttribute("data-original", automation.subject);
|
||||||
|
subjectEl.value = automation.subject;
|
||||||
|
|
||||||
|
// automation share link
|
||||||
|
let shareLinkEl = document.createElement("img");
|
||||||
|
shareLinkEl.id = `share-link-${automationId}`,
|
||||||
|
shareLinkEl.className = "automation-share-icon";
|
||||||
|
shareLinkEl.src = "/static/assets/icons/share.svg";
|
||||||
|
shareLinkEl.alt = "Share";
|
||||||
|
shareLinkEl.onclick = function(event) { copyShareLink(event, automationId, automation.subject, automation.crontime, automation.query_to_run); };
|
||||||
|
|
||||||
|
// automation edit action
|
||||||
|
let editIconEl = document.createElement("img");
|
||||||
|
editIconEl.classList.add("automation-edit-icon", automationId);
|
||||||
|
editIconEl.src = "/static/assets/icons/pencil-edit.svg";
|
||||||
|
editIconEl.alt = "Automations";
|
||||||
|
editIconEl.onclick = function() { onClickEditAutomationCard(automationId); };
|
||||||
|
|
||||||
|
// automation schedule input
|
||||||
|
let scheduleEl = document.createElement("input");
|
||||||
|
scheduleEl.type = "text";
|
||||||
|
scheduleEl.id = `automation-schedule-${automationId}`;
|
||||||
|
scheduleEl.name = "schedule";
|
||||||
|
scheduleEl.classList.add("schedule", automationId, "fake-input");
|
||||||
|
scheduleEl.setAttribute("data-cron", automation.crontime);
|
||||||
|
scheduleEl.setAttribute("data-original", automation.schedule);
|
||||||
|
scheduleEl.title = automationNextRun;
|
||||||
|
scheduleEl.value = automation.schedule;
|
||||||
|
|
||||||
|
// automation query to run input
|
||||||
|
let queryToRunEl = document.createElement("textarea");
|
||||||
|
queryToRunEl.id = `automation-queryToRun-${automationId}`;
|
||||||
|
queryToRunEl.classList.add("automation-instructions", automationId, "fake-input");
|
||||||
|
queryToRunEl.setAttribute("data-original", automation.query_to_run);
|
||||||
|
queryToRunEl.name = "query-to-run";
|
||||||
|
queryToRunEl.textContent = automation.query_to_run;
|
||||||
|
|
||||||
|
// Create automation actions section
|
||||||
|
let automationButtonsEl = document.createElement("div");
|
||||||
|
automationButtonsEl.className = "automation-buttons";
|
||||||
if (!isSuggested) {
|
if (!isSuggested) {
|
||||||
automationButtonsSection.classList.add("hide-details");
|
automationButtonsEl.classList.add("hide-details", automationId);
|
||||||
automationButtonsSection.classList.add(automationId);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let saveAutomationButtonEl = automationEl.querySelector(`#save-automation-button-${automation.id}`);
|
// save automation button
|
||||||
saveAutomationButtonEl.addEventListener("click", async () => { await saveAutomation(automation.id, isSuggested); });
|
let saveAutomationButtonEl = document.createElement("button");
|
||||||
let deleteAutomationButtonEl = automationEl.querySelector(`#delete-automation-button-${automation.id}`);
|
saveAutomationButtonEl.type = "button";
|
||||||
if (deleteAutomationButtonEl) {
|
saveAutomationButtonEl.className = "save-automation-button positive-button";
|
||||||
deleteAutomationButtonEl.addEventListener("click", () => {
|
saveAutomationButtonEl.id = `save-automation-button-${automationId}`;
|
||||||
deleteAutomation(automation.id);
|
saveAutomationButtonEl.textContent = isSuggested ? "Add" : "Save";
|
||||||
document.getElementById('overlay').style.display = 'none';
|
saveAutomationButtonEl.onclick = async () => { await saveAutomation(automation.id, isSuggested); };
|
||||||
});
|
|
||||||
|
// promo image for suggested automations
|
||||||
|
let promoImageEl = isSuggested ? document.createElement("img") : null;
|
||||||
|
if (isSuggested) {
|
||||||
|
promoImageEl.className = "promo-image";
|
||||||
|
promoImageEl.src = automation.promoImage;
|
||||||
|
promoImageEl.alt = "Promo Image";
|
||||||
}
|
}
|
||||||
let cancelEditAutomationButtonEl = automationEl.querySelector(`#cancel-edit-automation-button-${automation.id}`);
|
|
||||||
if (cancelEditAutomationButtonEl) {
|
// delete automation button
|
||||||
cancelEditAutomationButtonEl.addEventListener("click", (event) => {
|
let emptyDivEl = document.createElement("div");
|
||||||
clickCancelEdit(event, automation.id);
|
emptyDivEl.className = "empty-div";
|
||||||
document.getElementById('overlay').style.display = 'none';
|
let deleteAutomationButtonEl = !isSuggested ? document.createElement("button") : emptyDivEl;
|
||||||
});
|
if (!isSuggested) {
|
||||||
|
deleteAutomationButtonEl.type = "button";
|
||||||
|
deleteAutomationButtonEl.className = "delete-automation-button negative-button";
|
||||||
|
deleteAutomationButtonEl.id = `delete-automation-button-${automationId}`;
|
||||||
|
deleteAutomationButtonEl.textContent = "Delete";
|
||||||
|
deleteAutomationButtonEl.onclick = function() { deleteAutomation(automationId); document.getElementById('overlay').style.display = 'none'; };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// send preview automation button
|
||||||
|
emptyDivEl = document.createElement("div");
|
||||||
|
emptyDivEl.className = "empty-div";
|
||||||
|
let sendPreviewAutomationButtonEl = !isSuggested ? document.createElement("button") : emptyDivEl;
|
||||||
|
if (!isSuggested) {
|
||||||
|
sendPreviewAutomationButtonEl.type = "button";
|
||||||
|
sendPreviewAutomationButtonEl.className = "send-preview-automation-button positive-button";
|
||||||
|
sendPreviewAutomationButtonEl.title = "Immediately get a preview of this automation";
|
||||||
|
sendPreviewAutomationButtonEl.textContent = "Preview";
|
||||||
|
sendPreviewAutomationButtonEl.onclick = function() { sendAPreviewAutomation(automationId); };
|
||||||
|
}
|
||||||
|
|
||||||
|
// Construct automation card from elements
|
||||||
|
subjectWrapperEl.append(subjectEl, shareLinkEl, editIconEl);
|
||||||
|
automationButtonsEl.append(deleteAutomationButtonEl, sendPreviewAutomationButtonEl, saveAutomationButtonEl);
|
||||||
|
|
||||||
|
automationCardFormEl.append(subjectWrapperEl, scheduleEl, queryToRunEl);
|
||||||
|
if (isSuggested) {
|
||||||
|
automationCardFormEl.append(promoImageEl);
|
||||||
|
}
|
||||||
|
automationButtonsWrapperEl.append(automationButtonsEl);
|
||||||
|
|
||||||
|
automationCardEl.append(automationCardFormEl, automationButtonsWrapperEl, automationSuccessEl);
|
||||||
|
automationEl.append(automationCardEl);
|
||||||
|
|
||||||
return automationEl.firstElementChild;
|
return automationEl.firstElementChild;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -560,9 +606,6 @@
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
function listSuggestedAutomations() {
|
function listSuggestedAutomations() {
|
||||||
const SuggestedAutomationsList = document.getElementById("suggested-automations-list");
|
const SuggestedAutomationsList = document.getElementById("suggested-automations-list");
|
||||||
SuggestedAutomationsList.innerHTML = ''; // Clear existing content
|
SuggestedAutomationsList.innerHTML = ''; // Clear existing content
|
||||||
@@ -830,7 +873,6 @@
|
|||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get client location information from IP
|
// Get client location information from IP
|
||||||
@@ -887,6 +929,8 @@
|
|||||||
})
|
})
|
||||||
.then(response => response.ok ? response.json() : Promise.reject(data))
|
.then(response => response.ok ? response.json() : Promise.reject(data))
|
||||||
.then(automation => {
|
.then(automation => {
|
||||||
|
// Remove modal overlay
|
||||||
|
document.getElementById('overlay').style.display = 'none';
|
||||||
if (create) {
|
if (create) {
|
||||||
const automationEl = document.getElementById(`automation-card-${automationId}`);
|
const automationEl = document.getElementById(`automation-card-${automationId}`);
|
||||||
// Create a more interesting confirmation animation.
|
// Create a more interesting confirmation animation.
|
||||||
@@ -936,66 +980,113 @@
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
const create_automation_button = document.getElementById("create-automation-button");
|
function createAutomationEl(placeholderId = null) {
|
||||||
create_automation_button.addEventListener("click", function(event) {
|
let automationEl = document.createElement("div");
|
||||||
event.preventDefault();
|
automationEl.classList.add("card", "automation", "new-automation");
|
||||||
var automationEl = document.createElement("div");
|
placeholderId = placeholderId ?? `automation_${Date.now()}`;
|
||||||
automationEl.classList.add("card");
|
|
||||||
automationEl.classList.add("automation");
|
|
||||||
automationEl.classList.add("new-automation")
|
|
||||||
const placeholderId = Date.now();
|
|
||||||
automationEl.id = "automation-card-" + placeholderId;
|
automationEl.id = "automation-card-" + placeholderId;
|
||||||
var scheduleSelector = createScheduleSelector(placeholderId);
|
|
||||||
automationEl.innerHTML = `
|
// Create label for schedule
|
||||||
<label for="schedule">New Automation</label>
|
let scheduleLabel = document.createElement("label");
|
||||||
${scheduleSelector.outerHTML}
|
scheduleLabel.setAttribute("for", "schedule");
|
||||||
<label for="query-to-run">What would you like to receive in your automation?</label>
|
scheduleLabel.textContent = "New Automation";
|
||||||
<textarea id="automation-queryToRun-${placeholderId}" placeholder="Provide me with a mindful moment, reminding me to be centered."></textarea>
|
|
||||||
<div class="automation-buttons">
|
// Create schedule selector
|
||||||
<button type="button"
|
let scheduleSelector = createScheduleSelector(placeholderId);
|
||||||
class="delete-automation-button negative-button"
|
|
||||||
onclick="deleteAutomation(${placeholderId}, true)"
|
// Create label for query-to-run
|
||||||
id="delete-automation-button-${placeholderId}">Cancel</button>
|
let queryLabel = document.createElement("label");
|
||||||
<button type="button"
|
queryLabel.setAttribute("for", "query-to-run");
|
||||||
class="save-automation-button"
|
queryLabel.textContent = "What would you like to receive in your automation?";
|
||||||
onclick="saveAutomation(${placeholderId}, true)"
|
|
||||||
id="save-automation-button-${placeholderId}">Create</button>
|
// Create textarea for query-to-run
|
||||||
</div>
|
let queryTextarea = document.createElement("textarea");
|
||||||
<div id="automation-success-${placeholderId}" style="display: none;"></div>
|
queryTextarea.id = `automation-queryToRun-${placeholderId}`;
|
||||||
`;
|
queryTextarea.classList.add(`automation-queryToRun-${placeholderId}`);
|
||||||
|
queryTextarea.placeholder = "Provide me with a mindful moment, reminding me to be centered.";
|
||||||
|
|
||||||
|
// Create buttons container
|
||||||
|
let buttonsContainer = document.createElement("div");
|
||||||
|
buttonsContainer.classList.add("automation-buttons");
|
||||||
|
|
||||||
|
// Create cancel button
|
||||||
|
let deleteButton = document.createElement("button");
|
||||||
|
deleteButton.type = "button";
|
||||||
|
deleteButton.classList.add("delete-automation-button", "negative-button");
|
||||||
|
deleteButton.textContent = "Cancel";
|
||||||
|
deleteButton.id = `delete-automation-button-${placeholderId}`;
|
||||||
|
deleteButton.onclick = () => deleteAutomation(placeholderId, true);
|
||||||
|
|
||||||
|
// Create save button
|
||||||
|
let saveButton = document.createElement("button");
|
||||||
|
saveButton.type = "button";
|
||||||
|
saveButton.classList.add("save-automation-button");
|
||||||
|
saveButton.textContent = "Create";
|
||||||
|
saveButton.id = `save-automation-button-${placeholderId}`;
|
||||||
|
saveButton.onclick = () => saveAutomation(placeholderId, true);
|
||||||
|
|
||||||
|
// Create success message container
|
||||||
|
let successMessage = document.createElement("div");
|
||||||
|
successMessage.id = `automation-success-${placeholderId}`;
|
||||||
|
successMessage.style.display = "none";
|
||||||
|
|
||||||
|
// Append schedule label and selector
|
||||||
|
automationEl.appendChild(scheduleLabel);
|
||||||
|
automationEl.appendChild(scheduleSelector);
|
||||||
|
|
||||||
|
// Append query label and textarea
|
||||||
|
automationEl.appendChild(queryLabel);
|
||||||
|
automationEl.appendChild(queryTextarea);
|
||||||
|
|
||||||
|
// Append buttons to their container
|
||||||
|
buttonsContainer.appendChild(deleteButton);
|
||||||
|
buttonsContainer.appendChild(saveButton);
|
||||||
|
|
||||||
|
// Append buttons container to automationEl
|
||||||
|
automationEl.appendChild(buttonsContainer);
|
||||||
|
|
||||||
|
// Append success message to automationEl
|
||||||
|
automationEl.appendChild(successMessage);
|
||||||
|
|
||||||
|
return automationEl;
|
||||||
|
}
|
||||||
|
|
||||||
|
const createAutomationButtonEl = document.getElementById("create-automation-button");
|
||||||
|
createAutomationButtonEl.addEventListener("click", function(event) {
|
||||||
|
event.preventDefault();
|
||||||
|
|
||||||
|
// Insert automationEl into the DOM
|
||||||
|
let placeholderId = `automation_${Date.now()}`;
|
||||||
|
let automationEl = createAutomationEl(placeholderId);
|
||||||
document.getElementById("automations").insertBefore(automationEl, document.getElementById("automations").firstChild);
|
document.getElementById("automations").insertBefore(automationEl, document.getElementById("automations").firstChild);
|
||||||
|
|
||||||
setupScheduleViewListener("* * * * *", placeholderId);
|
setupScheduleViewListener("* * * * *", placeholderId);
|
||||||
})
|
})
|
||||||
|
|
||||||
function createPreFilledAutomation(subject, crontime, query) {
|
function createPreFilledAutomation(subject, crontime, query) {
|
||||||
document.getElementById('overlay').style.display = 'block';
|
document.getElementById('overlay').style.display = 'block';
|
||||||
var automationEl = document.createElement("div");
|
|
||||||
automationEl.classList.add("card");
|
let placeholderId = `automation_${Date.now()}`;
|
||||||
automationEl.classList.add("automation");
|
let automationEl = createAutomationEl(placeholderId);
|
||||||
automationEl.classList.add("new-automation")
|
|
||||||
const placeholderId = Date.now();
|
// Configure automationEl with pre-filled values
|
||||||
automationEl.classList.add(`${placeholderId}`);
|
automationEl.classList.add(`${placeholderId}`);
|
||||||
automationEl.id = "automation-card-" + placeholderId;
|
automationEl.getElementsByClassName(`automation-queryToRun-${placeholderId}`)[0].value = query;
|
||||||
var scheduleSelector = createScheduleSelector(placeholderId);
|
|
||||||
automationEl.innerHTML = `
|
// Create input for subject
|
||||||
<label for="subject">New Automation</label>
|
let subjectEl = document.createElement("input");
|
||||||
<input type="text" id="automation-subject-${placeholderId}" value="${subject}">
|
subjectEl.type = "text";
|
||||||
${scheduleSelector.outerHTML}
|
subjectEl.id = `automation-subject-${placeholderId}`;
|
||||||
<label for="query-to-run">What would you like to receive in your automation?</label>
|
subjectEl.value = subject;
|
||||||
<textarea id="automation-queryToRun-${placeholderId}">${query}</textarea>
|
|
||||||
<div class="automation-buttons">
|
// Insert subjectEl after label for subject
|
||||||
<button type="button"
|
let subjectLabel = automationEl.querySelector(`label[for="automation-subject-${placeholderId}"]`);
|
||||||
class="delete-automation-button negative-button"
|
automationEl.firstChild.insertAdjacentElement('afterend', subjectEl);
|
||||||
onclick="deleteAutomation(${placeholderId}, true)"
|
automationEl.firstChild.label = "subject";
|
||||||
id="delete-automation-button-${placeholderId}">Cancel</button>
|
|
||||||
<button type="button"
|
// Insert automationEl into the DOM
|
||||||
class="save-automation-button"
|
|
||||||
onclick="saveAutomation(${placeholderId}, true)"
|
|
||||||
id="save-automation-button-${placeholderId}">Create</button>
|
|
||||||
</div>
|
|
||||||
<div id="automation-success-${placeholderId}" style="display: none;"></div>
|
|
||||||
`;
|
|
||||||
document.getElementById("automations").insertBefore(automationEl, document.getElementById("automations").firstChild);
|
document.getElementById("automations").insertBefore(automationEl, document.getElementById("automations").firstChild);
|
||||||
|
|
||||||
setupScheduleViewListener(crontime, placeholderId);
|
setupScheduleViewListener(crontime, placeholderId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user