-
-
Notifications
You must be signed in to change notification settings - Fork 4k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add save path and category editing to WebUI #9228
Conversation
@@ -1210,13 +1210,13 @@ void TorrentHandle::setName(const QString &name) | |||
} | |||
} | |||
|
|||
bool TorrentHandle::setCategory(const QString &category) | |||
bool TorrentHandle::setCategory(const QString &category, const QString &savePath) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please revert this change. It produces incorrect interface.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The bigger issue is that this function already supports creating a new category. I'll refactor the existing code.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If you want to change Core logic, please do it in separate PR. It isn't required here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The bigger issue is that this function already supports creating a new category.
In a good way, we should allow only assign an existing category to the torrent.
This PR contains several, closely related changes:
|
if (!m_session->addCategory(category)) | ||
return false; | ||
} | ||
if (!category.isEmpty()) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This if
requires braces since it has multiline body.
src/webui/api/torrentscontroller.cpp
Outdated
@@ -801,8 +801,14 @@ void TorrentsController::setCategoryAction() | |||
|
|||
const QStringList hashes {params()["hashes"].split('|')}; | |||
const QString category {params()["category"].trimmed()}; | |||
applyToTorrents(hashes, [category](BitTorrent::TorrentHandle *torrent) | |||
const QString savePath {params()["savePath"].trimmed()}; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
setCategory is (should) used to assign torrent to existing category. Why this inconsistent parameter?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This setCategory
API receives requests for both new and existing categories. The savePath
is used when the category is new.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The savePath is used when the category is new.
It's incorrect interface.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It’s the existing interface. We can address it in a separate PR.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Really? Either you don't know what the "interface" is, or you're just kidding... There are no incorrect parameters before your changes. torrent.setCategory(category)
is correct interface but torrent.setCategory(category, savePath)
isn't since "savePath" has nothing to do with "assign torrent(s) to category".
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You should squash last commit since it just a fixup of one of the previous.
@@ -320,7 +320,7 @@ namespace | |||
// - "full_update": full data update flag | |||
// - "torrents": dictionary contains information about torrents. | |||
// - "torrents_removed": a list of hashes of removed torrents | |||
// - "categories": list of categories | |||
// - "categories": map of categories info |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please replace "map" with "dictionary" since such term is used in other place.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Both are used throughout the documentation
src/webui/api/synccontroller.cpp
Outdated
|
||
data["categories"] = categories; | ||
data["categories"] = categoriesList; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
TODO: This change causes minor API version change.
src/webui/api/torrentscontroller.cpp
Outdated
applyToTorrents(hashes, [category](BitTorrent::TorrentHandle *torrent) | ||
{ | ||
auto *session = BitTorrent::Session::instance(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this variable can be inlined.
src/webui/api/synccontroller.cpp
Outdated
for (auto key : categories.keys()) { | ||
categoriesList << QVariantMap { | ||
{"name", key}, | ||
{"savePath", categories.value(key)}, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
should the comma at the end be removed?
@@ -120,3 +120,9 @@ function escapeHtml(str) { | |||
div.appendChild(document.createTextNode(str)); | |||
return div.innerHTML; | |||
} | |||
|
|||
function safeTrim(value) { | |||
if (value === undefined || value === null) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
please add parentheses to each comparison.
<script> | ||
console.log("newcategory.html"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
slipped in?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good catch
return false; | ||
if (categoryName.match("^([^\\\\\\/]|[^\\\\\\/]([^\\\\\\/]|\\/(?=[^\\/]))*[^\\\\\\/])$") === null) { | ||
alert("QBT_TR(Invalid category name:\nPlease do not use any special characters in the category name.)QBT_TR[CONTEXT=HttpServer]"); | ||
var uriAction = safeTrim(new URI().getData('action')); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe it is possible to write it as: String(new URI().getData('action')).trim();
instead of adding a new function?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
String(null)
returns "null"
and String(undefined)
returns "undefined"
in JavaScript.
return true; | ||
}; | ||
|
||
if (uriAction === "set") { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There are 3 if-cases here, consider using switch()
?
e8b62eb
to
a25452a
Compare
All fixed up and squashed |
@@ -120,3 +120,9 @@ function escapeHtml(str) { | |||
div.appendChild(document.createTextNode(str)); | |||
return div.innerHTML; | |||
} | |||
|
|||
function safeTrim(value) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
String(null) returns "null" and String(undefined) returns "undefined" in JavaScript.
OK, however I think a true "safe trim" should look like this:
function safeTrim(str) {
try {
return str.trim();
}
catch (e) {
if (e instanceof TypeError)
return "";
throw e;
}
}
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sure, will update the implementation.
Do you intend to squash the commits again? At least the last 2 commits can be merged into previous one. |
11a8331
to
f649996
Compare
Squashed both into the previous commit. |
if (!m_session->categories().contains(category)) | ||
if (!m_session->addCategory(category)) | ||
return false; | ||
if (!Session::isValidCategoryName(category) || !m_session->categories().contains(category)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Checking for valid name is redundant now.
src/webui/api/torrentscontroller.cpp
Outdated
applyToTorrents(hashes, [category](BitTorrent::TorrentHandle *torrent) | ||
{ | ||
const QStringList categories = BitTorrent::Session::instance()->categories().keys(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Where is it used?
src/webui/api/torrentscontroller.cpp
Outdated
const QString category {params()["category"].trimmed()}; | ||
const QString savePath {params()["savePath"].trimmed()}; | ||
|
||
if (category.isEmpty() || savePath.isEmpty()) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Empty save path is valid.
src/webui/api/synccontroller.cpp
Outdated
QVariantList categories; | ||
for (auto i = session->categories().cbegin(); i != session->categories().cend(); ++i) | ||
categories << i.key(); | ||
QVariantList categoriesList; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You have chosen the wrong type for this task. You need to sync it as QVariantHash (with category names as keys and category info encoded as QVariantMap as values) to properly handle category changed/modified events. See "torrents" for example.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In my testing the QVariantList
seems to work great. Removing a category shows it in the categories_removed
section of sync/maindata. Editing a category's save path results in the category being shown in both categories
and categories_removed
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Editing a category's save path results in the category being shown in both
categories
andcategories_removed
.
It's wrong behavior. It's not so critical while category has only one property (save path). Besides "category edited" events are not so frequent. Although it contradicts the "sync" feature design. "Edited" event should send only changed data, not to be transformed into pair of "removed" + "added" events.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've switched it to a QVariantHash
and now I'm seeing the intended behavior. Will push the changes.
17c3964
to
1d9cfed
Compare
I don't believe this was ever a feature of the GUI or WebUI. You can create a new category and set it in one action, but not modify an existing category while also setting it.
I like this pattern a lot. I believe we can support it with |
Sorry, I'm not sure I understood you correctly...
It seems like you allow "modify an existing category while also setting it" and this behavior is incorrect. Or am I wrong and you don't allow it? Then please point me to a code preventing it. |
@Chocobo1, can you answer? |
I don't recall we ever defined it, how about we do it now. And put it in some file e.g.
|
Please refer to the changes in
There's no ability to modify an existing category and then set it on a torrent. You would need to initiate two discreet actions. |
I like this proposal. We can also add the webui minimum browser requirements to the site. I do see this as a separate PR where I can also refactor this code (and possibly other forms) to use the new features unsupported on old versions of IE. For now the pattern I follow here is how we've architected all of our web forms. |
How can I set existing category to torrent? |
From the WebUI, right click on a torrent and select the category from the context menu. |
Oh, that's right. There's also a
OK. |
@Piccirello you can add "closes #9223, closes #5716" or "fixes #xxxx" in the body of first post. Note that closes/fixes must exist before every issue mention for github to close it, same goes for when doing it in commits. Edit: I did it here in case this gets merged before you see this. |
Thanks thalieht, I didn’t know that was an official feature. |
src/webui/api/torrentscontroller.cpp
Outdated
@@ -821,10 +822,30 @@ void TorrentsController::createCategoryAction() | |||
checkParams({"category"}); | |||
|
|||
const QString category {params()["category"].trimmed()}; | |||
if (!BitTorrent::Session::isValidCategoryName(category) && !category.isEmpty()) | |||
const QString savePath {params()["savePath"].trimmed()}; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Path string may end with whitespace.
src/webui/api/synccontroller.cpp
Outdated
QVariantList categories; | ||
for (auto i = session->categories().cbegin(); i != session->categories().cend(); ++i) | ||
categories << i.key(); | ||
QVariantHash categoriesHash; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I can imagine why did you rename the variable while making the changes. But I don't think it has to get a new name in the final patch. Also, "hash" is a ambiguous suffix, which is used elsewhere in the project to refer to the hash value but not a hash table.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is pretty pedantic, but I'll make the change.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I appreciate that!
b404017
to
63c5376
Compare
If no more comments, please approve |
Thank you! |
Before:
After:
GUI for comparison:
Closes #9223, closes #5716.