diff --git a/public/js/api.js b/public/js/api.js index cb20e01..cde919a 100644 --- a/public/js/api.js +++ b/public/js/api.js @@ -36,6 +36,8 @@ export const api = { createCategory: (name, savePath) => jpost('/api/categories', { name, savePath }), deleteCategory: (name) => jpost('/api/categories/delete', { name }), + editCategory: (name, newName, savePath) => + jpost('/api/categories/edit', { name, newName, savePath }), createTag: (name) => jpost('/api/tags', { name }), deleteTag: (name) => jpost('/api/tags/delete', { name }), diff --git a/public/js/app.js b/public/js/app.js index 3c0c815..6c20aa6 100644 --- a/public/js/app.js +++ b/public/js/app.js @@ -264,6 +264,9 @@ function onSidebarContext(e, type, value, removable) { const items = [ { label: type === 'category' ? 'New category…' : 'New tag…', act: () => (type === 'category' ? openCreateCategory() : openCreateTag()) }, ]; + if (type === 'category') { + items.push({ label: 'Edit category…', act: () => openEditCategory(value) }); + } if (removable) { items.push({ sep: true }); items.push({ label: `Delete ${type}`, danger: true, act: () => confirmDeleteMeta(type, value) }); @@ -495,7 +498,7 @@ async function confirmDelete(hashes) { /* ---------- add torrent modal ---------- */ function openAddModal() { const cats = '' + - state.meta.categories.map((c) => ``).join(''); + state.meta.categories.filter((c) => c.name).map((c) => ``).join(''); const tagOpts = state.meta.tags.map((t) => ``).join(''); openModal('Add torrent', ` @@ -765,7 +768,7 @@ function promptCategory() { const cur = state.snapshot?.torrents?.find((t) => t.hash === [...state.selected][0])?.category || ''; const sel = (v) => (v === cur ? ' selected' : ''); const opts = `` + - state.meta.categories.map((c) => ``).join(''); + state.meta.categories.filter((c) => c.name).map((c) => ``).join(''); openModal('Set category', `

Need a new one? Use + next to “Categories” in the sidebar.

`, @@ -795,6 +798,33 @@ function openCreateCategory() { setTimeout(() => document.getElementById('catName')?.focus(), 0); } +function openEditCategory(value) { + const isUncat = value === ''; + const cur = state.meta.categories.find((c) => c.name === value); + const curPath = cur ? (cur.savePath || '') : ''; + const nameField = isUncat + ? `
` + : `
`; + openModal('Edit category', ` + ${nameField} +
+
`, + [{ label: 'Cancel', act: closeModal }, { + label: 'Save', primary: true, act: async () => { + const newName = isUncat ? '' : document.getElementById('catName').value.trim(); + if (!isUncat && !newName) return closeModal(); + const savePath = document.getElementById('catPath').value.trim(); + await api.editCategory(value, newName, savePath); + await refreshMeta(); + if (!isUncat && newName !== value && state.filter.type === 'category' && state.filter.value === value) + state.filter = { type: 'category', value: newName }; + renderView(); + closeModal(); + }, + }]); + setTimeout(() => document.getElementById('catName')?.focus(), 0); +} + function openCreateTag() { openModal('New tag', `
`, [{ label: 'Cancel', act: closeModal }, {