mirror of
https://github.com/SillyTavern/SillyTavern.git
synced 2025-06-05 21:59:27 +02:00
Delete method almost complete
This commit is contained in:
@@ -5553,6 +5553,9 @@ function callPopup(text, type, inputValue = '', { okButton, rows } = {}) {
|
||||
$("#dialogue_popup_ok").text(okButton ?? "Ok");
|
||||
$("#dialogue_popup_cancel").css("display", "none");
|
||||
break;
|
||||
case "delete_extension":
|
||||
$("#dialogue_popup_ok").text(okButton ?? "Ok");
|
||||
break;
|
||||
case "new_chat":
|
||||
case "confirm":
|
||||
$("#dialogue_popup_ok").text(okButton ?? "Yes");
|
||||
|
@@ -412,16 +412,20 @@ async function generateExtensionHtml(name, manifest, isActive, isDisabled, isExt
|
||||
`<input type="checkbox" title="Click to toggle" data-name="${name}" class="${isActive ? 'toggle_disable' : 'toggle_enable'} ${checkboxClass}" ${isActive ? 'checked' : ''}>` :
|
||||
`<input type="checkbox" title="Cannot enable extension" data-name="${name}" class="extension_missing ${checkboxClass}" disabled>`;
|
||||
|
||||
let deleteButton = isExternal ? `<span class="delete-button"><button class="btn_delete menu_button" data-name="${name.replace('third-party', '')}" title="Delete"><i class="fa-solid fa-trash-can"></i></button></span>` : '';
|
||||
|
||||
// if external, wrap the name in a link to the repo
|
||||
|
||||
let extensionHtml = `<hr>
|
||||
<h4>
|
||||
${updateButton}
|
||||
${deleteButton}
|
||||
${originHtml}
|
||||
<span class="${isActive ? "extension_enabled" : isDisabled ? "extension_disabled" : "extension_missing"}">
|
||||
${DOMPurify.sanitize(displayName)}${displayVersion}
|
||||
</span>
|
||||
${isExternal ? '</a>' : ''}
|
||||
|
||||
<span style="float:right;">${toggleElement}</span>
|
||||
</h4>`;
|
||||
|
||||
@@ -530,6 +534,32 @@ async function onUpdateClick() {
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Handles the click event for the delete button of an extension.
|
||||
* This function makes a POST request to '/delete_extension' with the extension's name.
|
||||
* If the extension is deleted, it displays a success message.
|
||||
* Creates a popup for the user to confirm before delete.
|
||||
*/
|
||||
async function onDeleteClick() {
|
||||
const extensionName = $(this).data('name');
|
||||
// use callPopup to create a popup for the user to confirm before delete
|
||||
const confirmation = await callPopup(`Are you sure you want to delete ${extensionName}?`, 'delete_extension');
|
||||
if (confirmation) {
|
||||
try {
|
||||
const response = await fetch('/delete_extension', {
|
||||
method: 'POST',
|
||||
headers: getRequestHeaders(),
|
||||
body: JSON.stringify({ extensionName })
|
||||
});
|
||||
} catch (error) {
|
||||
console.error('Error:', error);
|
||||
}
|
||||
toastr.success(`Extension ${extensionName} deleted`);
|
||||
showExtensionsDetails();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Fetches the version details of a specific extension.
|
||||
@@ -600,4 +630,5 @@ $(document).ready(async function () {
|
||||
$(document).on('click', '.toggle_disable', onDisableExtensionClick);
|
||||
$(document).on('click', '.toggle_enable', onEnableExtensionClick);
|
||||
$(document).on('click', '.btn_update', onUpdateClick);
|
||||
$(document).on('click', '.btn_delete', onDeleteClick);
|
||||
});
|
||||
|
@@ -3807,6 +3807,13 @@ input.extension_missing[type="checkbox"] {
|
||||
display: inline-flex;
|
||||
}
|
||||
|
||||
/* Align the content of this span to the right */
|
||||
.delete-button {
|
||||
margin-right: 10px;
|
||||
display: inline-flex;
|
||||
|
||||
}
|
||||
|
||||
/* possible place for WI Entry header styling */
|
||||
/* .world_entry_form .inline-drawer-header {
|
||||
background-color: var(--SmartThemeShadowColor);
|
||||
|
31
server.js
31
server.js
@@ -4532,5 +4532,36 @@ app.post('/get_extension_version', jsonParser, async (request, response) => {
|
||||
}
|
||||
);
|
||||
|
||||
/**
|
||||
* HTTP POST handler function to delete a git repository based on the extension name provided in the request body.
|
||||
*
|
||||
* @param {Object} request - HTTP Request object, expects a JSON body with a 'url' property.
|
||||
* @param {Object} response - HTTP Response object used to respond to the HTTP request.
|
||||
*
|
||||
* @returns {void}
|
||||
*/
|
||||
app.post('/delete_extension', jsonParser, async (request, response) => {
|
||||
if (!request.body.extensionName) {
|
||||
return response.status(400).send('Bad Request: extensionName is required in the request body.');
|
||||
}
|
||||
|
||||
// Sanatize the extension name to prevent directory traversal
|
||||
const extensionName = sanitize(request.body.extensionName);
|
||||
|
||||
try {
|
||||
const extensionPath = path.join(directories.extensions, 'third-party', extensionName);
|
||||
|
||||
if (!fs.existsSync(extensionPath)) {
|
||||
return response.status(404).send(`Directory does not exist at ${extensionPath}`);
|
||||
}
|
||||
|
||||
await fs.promises.rmdir(extensionPath, { recursive: true });
|
||||
console.log(`Extension has been deleted at ${extensionPath}`);
|
||||
|
||||
return response.send(`Extension has been deleted at ${extensionPath}`);
|
||||
|
||||
} catch (error) {
|
||||
console.log('Deleting custom content failed', error);
|
||||
return response.status(500).send(`Server Error: ${error.message}`);
|
||||
}
|
||||
});
|
||||
|
Reference in New Issue
Block a user