Get Conversation session action buttons out from under the three dot menu

This commit is contained in:
Debanjum Singh Solanky
2024-05-31 07:36:44 +05:30
parent 7fa42daf89
commit 92bab9fa61
2 changed files with 150 additions and 111 deletions

View File

@@ -461,8 +461,8 @@ export class KhojChatView extends KhojPaneView {
this.renderMessage(chatBodyEl, "Hey 👋🏾, what's up?", "khoj");
}
async toggleChatSessions(chatBodyEl: HTMLElement): Promise<boolean> {
if (this.contentEl.getElementsByClassName("side-panel")?.length > 0) {
async toggleChatSessions(chatBodyEl: HTMLElement, forceShow: boolean = false): Promise<boolean> {
if (!forceShow && this.contentEl.getElementsByClassName("side-panel")?.length > 0) {
chatBodyEl.innerHTML = "";
return this.getChatHistory(chatBodyEl);
}
@@ -497,121 +497,32 @@ export class KhojChatView extends KhojPaneView {
let conversation = responseJson[key];
let conversationSessionEl = this.contentEl.createEl('div');
let incomingConversationId = conversation["conversation_id"];
const conversationTitle = conversation["slug"] || `New conversation 🌱`;
conversationSessionEl.textContent = conversationTitle;
conversationSessionEl.classList.add("conversation-session");
if (incomingConversationId == conversationId) {
conversationSessionEl.classList.add("selected-conversation");
}
conversationSessionEl.addEventListener('click', () => {
const conversationTitle = conversation["slug"] || `New conversation 🌱`;
const conversationSessionTitleEl = conversationSessionEl.createDiv("conversation-session-title");
conversationSessionTitleEl.textContent = conversationTitle;
conversationSessionTitleEl.addEventListener('click', () => {
chatBodyEl.innerHTML = "";
chatBodyEl.dataset.conversationId = incomingConversationId;
chatBodyEl.dataset.conversationTitle = conversationTitle;
this.getChatHistory(chatBodyEl);
});
let threeDotMenuEl = this.contentEl.createEl('div');
threeDotMenuEl.classList.add("three-dot-menu");
let threeDotMenuButton = this.contentEl.createEl('button');
threeDotMenuButton.innerHTML = "⋮";
threeDotMenuButton.classList.add("three-dot-menu-button");
threeDotMenuButton.addEventListener('click', (event) => {
event.stopPropagation();
let existingChildren = threeDotMenuEl.children;
if (existingChildren.length > 1) {
// Skip deleting the first, since that's the menu button.
for (let i = 1; i < existingChildren.length; i++) {
existingChildren[i].remove();
}
return;
}
let conversationMenuEl = this.contentEl.createEl('div');
conversationMenuEl = this.addConversationMenu(
conversationMenuEl,
conversationSessionEl,
conversationTitle,
conversationSessionTitleEl,
chatBodyEl,
incomingConversationId,
incomingConversationId == conversationId,
);
let conversationMenuEl = this.contentEl.createEl('div');
conversationMenuEl.classList.add("conversation-menu");
let editConversationTitleButtonEl = this.contentEl.createEl('button');
editConversationTitleButtonEl.innerHTML = "Rename";
editConversationTitleButtonEl.classList.add("edit-title-button");
editConversationTitleButtonEl.classList.add("three-dot-menu-button-item");
editConversationTitleButtonEl.addEventListener('click', (event) => {
event.stopPropagation();
let conversationMenuChildren = conversationMenuEl.children;
let totalItems = conversationMenuChildren.length;
for (let i = totalItems - 1; i >= 0; i--) {
conversationMenuChildren[i].remove();
}
// Create a dialog box to get new title for conversation
let editConversationTitleInputBoxEl = this.contentEl.createEl('div');
editConversationTitleInputBoxEl.classList.add("conversation-title-input-box");
let editConversationTitleInputEl = this.contentEl.createEl('input');
editConversationTitleInputEl.classList.add("conversation-title-input");
editConversationTitleInputEl.value = conversationTitle;
editConversationTitleInputEl.addEventListener('click', function(event) {
event.stopPropagation();
});
editConversationTitleInputEl.addEventListener('keydown', function(event) {
if (event.key === "Enter") {
event.preventDefault();
editConversationTitleSaveButtonEl.click();
}
});
let editConversationTitleSaveButtonEl = this.contentEl.createEl('button');
editConversationTitleInputBoxEl.appendChild(editConversationTitleInputEl);
editConversationTitleSaveButtonEl.innerHTML = "Save";
editConversationTitleSaveButtonEl.classList.add("three-dot-menu-button-item");
editConversationTitleSaveButtonEl.addEventListener('click', (event) => {
event.stopPropagation();
let newTitle = editConversationTitleInputEl.value;
if (newTitle != null) {
let editURL = `/api/chat/title?client=web&conversation_id=${incomingConversationId}&title=${newTitle}`;
fetch(`${this.setting.khojUrl}${editURL}`, { method: "PATCH", headers })
.then(response => response.ok ? response.json() : Promise.reject(response))
.then(data => {
conversationSessionEl.textContent = newTitle;
})
.catch(err => {
return;
});
editConversationTitleInputBoxEl.remove();
}
});
editConversationTitleInputBoxEl.appendChild(editConversationTitleSaveButtonEl);
conversationMenuEl.appendChild(editConversationTitleInputBoxEl);
});
conversationMenuEl.appendChild(editConversationTitleButtonEl);
threeDotMenuEl.appendChild(conversationMenuEl);
let deleteConversationButtonEl = this.contentEl.createEl('button');
deleteConversationButtonEl.innerHTML = "Delete";
deleteConversationButtonEl.classList.add("delete-conversation-button");
deleteConversationButtonEl.classList.add("three-dot-menu-button-item");
deleteConversationButtonEl.addEventListener('click', () => {
// Ask for confirmation before deleting chat session
let confirmation = confirm('Are you sure you want to delete this chat session?');
if (!confirmation) return;
let deleteURL = `/api/chat/history?client=obsidian&conversation_id=${incomingConversationId}`;
fetch(`${this.setting.khojUrl}${deleteURL}`, { method: "DELETE", headers })
.then(response => response.ok ? response.json() : Promise.reject(response))
.then(data => {
chatBodyEl.innerHTML = "";
chatBodyEl.dataset.conversationId = "";
chatBodyEl.dataset.conversationTitle = "";
this.getChatHistory(chatBodyEl);
})
.catch(err => {
return;
});
});
conversationMenuEl.appendChild(deleteConversationButtonEl);
threeDotMenuEl.appendChild(conversationMenuEl);
});
threeDotMenuEl.appendChild(threeDotMenuButton);
conversationSessionEl.appendChild(threeDotMenuEl);
conversationSessionEl.appendChild(conversationMenuEl);
conversationListBodyEl.appendChild(conversationSessionEl);
chatBodyEl.appendChild(sidePanelEl);
}
@@ -622,6 +533,123 @@ export class KhojChatView extends KhojPaneView {
return true;
}
addConversationMenu(
conversationMenuEl: HTMLDivElement,
conversationSessionEl: HTMLElement,
conversationTitle: string,
conversationSessionTitleEl: HTMLElement,
chatBodyEl: HTMLElement,
incomingConversationId: string,
selectedConversation: boolean,
) {
conversationMenuEl.classList.add("conversation-menu");
const headers = { 'Authorization': `Bearer ${this.setting.khojApiKey}` };
let editConversationTitleButtonEl = this.contentEl.createEl('button');
setIcon(editConversationTitleButtonEl, "edit");
editConversationTitleButtonEl.title = "Rename";
editConversationTitleButtonEl.classList.add("edit-title-button");
editConversationTitleButtonEl.classList.add("three-dot-menu-button-item");
if (selectedConversation) editConversationTitleButtonEl.classList.add("selected-conversation");
editConversationTitleButtonEl.addEventListener('click', (event) => {
event.stopPropagation();
let conversationMenuChildren = conversationMenuEl.children;
let totalItems = conversationMenuChildren.length;
for (let i = totalItems - 1; i >= 0; i--) {
conversationMenuChildren[i].remove();
}
// Create a dialog box to get new title for conversation
let editConversationTitleInputEl = this.contentEl.createEl('input');
editConversationTitleInputEl.classList.add("conversation-title-input");
editConversationTitleInputEl.value = conversationTitle;
editConversationTitleInputEl.addEventListener('click', function(event) {
event.stopPropagation();
});
editConversationTitleInputEl.addEventListener('keydown', function(event) {
if (event.key === "Enter") {
event.preventDefault();
editConversationTitleSaveButtonEl.click();
}
});
let editConversationTitleSaveButtonEl = this.contentEl.createEl('button');
conversationSessionTitleEl.replaceWith(editConversationTitleInputEl);
editConversationTitleSaveButtonEl.innerHTML = "Save";
editConversationTitleSaveButtonEl.classList.add("three-dot-menu-button-item");
if (selectedConversation) editConversationTitleSaveButtonEl.classList.add("selected-conversation");
editConversationTitleSaveButtonEl.addEventListener('click', (event) => {
event.stopPropagation();
let newTitle = editConversationTitleInputEl.value;
if (newTitle != null) {
let editURL = `/api/chat/title?client=web&conversation_id=${incomingConversationId}&title=${newTitle}`;
fetch(`${this.setting.khojUrl}${editURL}`, { method: "PATCH", headers })
.then(response => response.ok ? response.json() : Promise.reject(response))
.then(data => {
conversationSessionTitleEl.textContent = newTitle;
})
.catch(err => {
return;
});
const conversationSessionTitleEl = conversationSessionEl.createDiv("conversation-session-title");
conversationSessionTitleEl.textContent = newTitle;
conversationSessionTitleEl.addEventListener('click', () => {
chatBodyEl.innerHTML = "";
chatBodyEl.dataset.conversationId = incomingConversationId;
chatBodyEl.dataset.conversationTitle = conversationTitle;
this.getChatHistory(chatBodyEl);
});
let newConversationMenuEl = this.contentEl.createEl('div');
newConversationMenuEl = this.addConversationMenu(
newConversationMenuEl,
conversationSessionEl,
newTitle,
conversationSessionTitleEl,
chatBodyEl,
incomingConversationId,
selectedConversation,
);
conversationMenuEl.replaceWith(newConversationMenuEl);
editConversationTitleInputEl.replaceWith(conversationSessionTitleEl);
}
});
conversationMenuEl.appendChild(editConversationTitleSaveButtonEl);
});
conversationMenuEl.appendChild(editConversationTitleButtonEl);
let deleteConversationButtonEl = this.contentEl.createEl('button');
setIcon(deleteConversationButtonEl, "trash");
deleteConversationButtonEl.title = "Delete";
deleteConversationButtonEl.classList.add("delete-conversation-button");
deleteConversationButtonEl.classList.add("three-dot-menu-button-item");
if (selectedConversation) deleteConversationButtonEl.classList.add("selected-conversation");
deleteConversationButtonEl.addEventListener('click', () => {
// Ask for confirmation before deleting chat session
let confirmation = confirm('Are you sure you want to delete this chat session?');
if (!confirmation) return;
let deleteURL = `/api/chat/history?client=obsidian&conversation_id=${incomingConversationId}`;
fetch(`${this.setting.khojUrl}${deleteURL}`, { method: "DELETE", headers })
.then(response => response.ok ? response.json() : Promise.reject(response))
.then(data => {
chatBodyEl.innerHTML = "";
chatBodyEl.dataset.conversationId = "";
chatBodyEl.dataset.conversationTitle = "";
this.toggleChatSessions(chatBodyEl, true);
})
.catch(err => {
return;
});
});
conversationMenuEl.appendChild(deleteConversationButtonEl);
return conversationMenuEl;
}
async getChatHistory(chatBodyEl: HTMLElement): Promise<boolean> {
// Get chat history from Khoj backend
let chatUrl = `${this.setting.khojUrl}/api/chat/history?client=obsidian`;

View File

@@ -240,10 +240,22 @@ img {
max-width: 60%;
}
div.new-conversation {
display: grid;
grid-auto-flow: column;
grid-template-columns: 1fr auto;
margin-bottom: 16px;
}
div.conversation-header-title {
text-align: left;
font-size: larger;
line-height: 1.5em;
}
div.conversation-session {
color: var(--color-base-90);
border: 1px solid var(--khoj-storm-grey);
border-radius: 5px;
margin-top: 8px;
padding: 5px;
font-size: 14px;
font-weight: 300;
@@ -264,9 +276,11 @@ div.conversation-session {
/* position: relative; */
}
button.three-dot-menu-button-item {
button.selected-conversation {
background: var(--khoj-winter-sun);
color: var(--khoj-storm-grey);
}
button.three-dot-menu-button-item {
color: var(--color-base-90);
border: none;
box-shadow: none;
font-size: 14px;
@@ -307,11 +321,8 @@ div.conversation-menu {
top: 100%;
right: 0;
text-align: right;
background-color: var(--khoj-winter-sun);
border: 1px solid var(--khoj-storm-grey);
border-radius: 5px;
padding: 5px;
box-shadow: 0 0 11px #aaa;
}
div.conversation-session:hover {
transform: scale(1.03);