Skip to content
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

Merged
merged 3 commits into from
Sep 13, 2018

Conversation

Piccirello
Copy link
Member

@Piccirello Piccirello commented Jul 23, 2018

Before:
screen shot 2018-07-22 at 8 03 04 pm

After:
screen shot 2018-07-22 at 8 04 50 pm

screen shot 2018-07-23 at 1 53 44 am

GUI for comparison:
screen shot 2018-07-22 at 8 06 00 pm

Closes #9223, closes #5716.

@@ -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)
Copy link
Member

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.

Copy link
Member Author

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.

Copy link
Member

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.

Copy link
Member

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.

@glassez glassez added the WebUI WebUI-related issues/changes label Jul 23, 2018
@Piccirello Piccirello changed the title Add save path to WebUI new category dialog Add save path and category editing to WebUI Jul 23, 2018
@Piccirello
Copy link
Member Author

This PR contains several, closely related changes:

  • Addition of save path to webui categories
  • Ability to edit categories from webui

if (!m_session->addCategory(category))
return false;
}
if (!category.isEmpty())
Copy link
Member

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.

@@ -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()};
Copy link
Member

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?

Copy link
Member Author

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.

Copy link
Member

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.

Copy link
Member Author

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.

Copy link
Member

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".

Copy link
Member

@glassez glassez left a 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
Copy link
Member

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.

Copy link
Member Author

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


data["categories"] = categories;
data["categories"] = categoriesList;
Copy link
Member

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.

applyToTorrents(hashes, [category](BitTorrent::TorrentHandle *torrent)
{
auto *session = BitTorrent::Session::instance();
Copy link
Member

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.

for (auto key : categories.keys()) {
categoriesList << QVariantMap {
{"name", key},
{"savePath", categories.value(key)},
Copy link
Member

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)
Copy link
Member

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");
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

slipped in?

Copy link
Member Author

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'));
Copy link
Member

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?

Copy link
Member Author

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") {
Copy link
Member

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()?

@Piccirello Piccirello force-pushed the addCategory branch 2 times, most recently from e8b62eb to a25452a Compare August 9, 2018 22:56
@Piccirello
Copy link
Member Author

All fixed up and squashed

@@ -120,3 +120,9 @@ function escapeHtml(str) {
div.appendChild(document.createTextNode(str));
return div.innerHTML;
}

function safeTrim(value) {
Copy link
Member

@Chocobo1 Chocobo1 Aug 10, 2018

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;
    }
}

Copy link
Member Author

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.

@Chocobo1
Copy link
Member

Do you intend to squash the commits again? At least the last 2 commits can be merged into previous one.

@Piccirello
Copy link
Member Author

Squashed both into the previous commit.

Chocobo1
Chocobo1 previously approved these changes Aug 10, 2018
if (!m_session->categories().contains(category))
if (!m_session->addCategory(category))
return false;
if (!Session::isValidCategoryName(category) || !m_session->categories().contains(category))
Copy link
Member

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.

applyToTorrents(hashes, [category](BitTorrent::TorrentHandle *torrent)
{
const QStringList categories = BitTorrent::Session::instance()->categories().keys();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Where is it used?

const QString category {params()["category"].trimmed()};
const QString savePath {params()["savePath"].trimmed()};

if (category.isEmpty() || savePath.isEmpty())
Copy link
Member

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.

QVariantList categories;
for (auto i = session->categories().cbegin(); i != session->categories().cend(); ++i)
categories << i.key();
QVariantList categoriesList;
Copy link
Member

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.

Copy link
Member Author

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.

Copy link
Member

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 and categories_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.

Copy link
Member Author

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.

@Piccirello
Copy link
Member Author

  1. Do you still allow to set torrent(s) category simultaneously with changing given category? (I see you use the same dialog for this action but you don't remove/disable "Save path" in it.)

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.

  1. Currently you transfer almost all the logic into corresponding dialog. Why not to use it only for obtaining the data and keep the logic in "caller" JS functions? Or is it impossible? I mean, show dialog (with some initial values when needed), wait for "done" event (when the user presses "Ok"), obtain current values from it and do the appropriate action.

I like this pattern a lot. I believe we can support it with Window.postMessage, though that feature only works in IE10+. I can never remember what minimum browser versions we target, so not sure if this would be an issue.

@glassez
Copy link
Member

glassez commented Aug 20, 2018

I don't believe this was ever a feature of the GUI or WebUI.

Sorry, I'm not sure I understood you correctly...

You can create a new category and set it in one action, but not modify an existing category while also setting it.

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.

@glassez
Copy link
Member

glassez commented Aug 20, 2018

I can never remember what minimum browser versions we target

@Chocobo1, can you answer?

@Chocobo1
Copy link
Member

@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. src/webui/www/Readme.md, @Piccirello do you mind do it?
Here is my naive proposal:

Chrome: (what is the lower bound in the industry?) -> Latest release
Firefox: Oldest active ESR branch -> Latest release
IE: 11 -> Latest release

@Piccirello
Copy link
Member Author

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.

Please refer to the changes in newcategory.html. There are 3 possible actions:

  1. "set": new category is created and then set for torrent(s)
  2. "create": new category is created
  3. "edit": existing category is modified

There's no ability to modify an existing category and then set it on a torrent. You would need to initiate two discreet actions.

@Piccirello
Copy link
Member Author

I don't recall we ever defined it, how about we do it now. And put it in some file e.g. src/webui/www/Readme.md

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.

@glassez
Copy link
Member

glassez commented Aug 24, 2018

"set": new category is created and then set for torrent(s)

How can I set existing category to torrent?

@Piccirello
Copy link
Member Author

From the WebUI, right click on a torrent and select the category from the context menu.

@glassez
Copy link
Member

glassez commented Aug 24, 2018

From the WebUI, right click on a torrent and select the category from the context menu.

Oh, that's right. There's also a torrentSetCategoryFN() function that's not affected by your changes, so I didn't notice it. I have tested this PR and it works as expected.

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.

OK.

glassez
glassez previously approved these changes Aug 24, 2018
Chocobo1
Chocobo1 previously approved these changes Aug 25, 2018
@Piccirello
Copy link
Member Author

Looks like this will close #9223, #5716

@thalieht
Copy link
Contributor

thalieht commented Aug 26, 2018

@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.

@Piccirello
Copy link
Member Author

Thanks thalieht, I didn’t know that was an official feature.

@glassez glassez requested a review from zeule August 31, 2018 08:11
@@ -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()};
Copy link
Contributor

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.

QVariantList categories;
for (auto i = session->categories().cbegin(); i != session->categories().cend(); ++i)
categories << i.key();
QVariantHash categoriesHash;
Copy link
Contributor

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.

Copy link
Member Author

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.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I appreciate that!

@Piccirello
Copy link
Member Author

If no more comments, please approve

@glassez glassez merged commit 28a6ac3 into qbittorrent:master Sep 13, 2018
@glassez
Copy link
Member

glassez commented Sep 13, 2018

Thank you!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
WebAPI WebAPI-related issues/changes WebUI WebUI-related issues/changes
Projects
None yet
Development

Successfully merging this pull request may close these issues.

[Feature] Categories allow definition of save location WebUI missing category settings?
5 participants