-
-
Notifications
You must be signed in to change notification settings - Fork 1.5k
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
Database merge confirmation dialog #10173
base: develop
Are you sure you want to change the base?
Database merge confirmation dialog #10173
Conversation
This PR doesn't yet follow the contribution guidelines and contains temporary code, so don't take it too seriously. I did a first draft to simply be able to call with a I was struggeling a bit with the lifetime of the objects and if there are any guarantees defined somewhere and if e.g. the entry pointers are actually guaranteed to be not null and will remain valid. The last major open task is to fix the merge of the deletions since the current implementation relies on the other entries being merged first - however, this change requires to not modify anything before confirmed by the user. |
Awesome MVP!! |
ad194d3
to
9223d95
Compare
Sorry that the PR became kind of huge - I encountered some unexpected issues with the merge logic for deletions since it relied on the groups/entries already being merged before. Thanks a lot to whoever wrote the extensive test suite for the merge logic, that helped a lot to debug issues and also understand the reasoning behind the merge behavior. If you want to, I can also split this into two PRs, I already kept it apart in two commits (one for the merge logic refactoring and one for the UI). I also left a couple of |
9223d95
to
4b1aac0
Compare
4b1aac0
to
580fee7
Compare
If this happens, the program will get stuck in an infinite signal loop. Adding an assertion will help developers recognize such errors earlier and not waste time debugging.
Allow the calculation of the change list without modifying the target database. After that, it becomes possible to merge with exactly these generated changes. Additionally, add additional test cases to cover this new behavior.
580fee7
to
00f98b3
Compare
@taminob Thanks for investing time into implementing this. I have suggested some related CLI features and I've been told to suggest them here as this PR is the perfect place for this. It would be amazing if we can have the table you implemented in GUI into CLI since the info is there and it would be just a matter for formatting (for instance in markdown table format): ❯ keepassxc-cli merge --dry-run --same-credentials db-local.kdbx db-remote.kdbx
Enter password to unlock db-local.kdbx
| Action | what | UUID |
|--------------------------------------|-----------|--------------------|
| Overwriting | blah blah | [814h814h814h814h] |
| '_ Synchronizing from newer source | blah blah | [814h814h814h814h] |
| '_ Creating missing | blah blah | [814h814h814h814h] |
| '_ Creating missing | blah blah | [814h814h814h814h] |
Database was not modified by merge operation. Additionally, It would be extra useful to specify which file is the "newer source" (newer can be based on file modification time or internal variable in databases). In the screenshot you posted in GUI, you also have "newer source" which is imho ambiguous. Also (slightly off-topic), I wonder if it is feasible to use some sort of color coding. Then As a final remark and comment/feedback on your amazing work, I would like to suggest to move the UUID to the last column of the table as to the user UUID is not so useful compared to other columns. Thanks again for your efforts. I've been waiting for this feature for quite some time :) |
@mmahmoudian thanks for suggesting, I think that would be an improvement, too. I also like your mockup, although I'm not quite sure what's the meaning of the tree-like structure in the However, I think that it might be better to keep further user experience improvements to a separate follow-up PR since this PR is already quite complex. I even thought about moving the entire GUI stuff to a separate PR. Do you have any opinion @droidmonkey, do you think the current refactoring is worth the risk? I'd also be willing to look into the CLI improvements, generating such a table shouldn't be too hard. Otherwise, this PR would also be ready if you have time to review it. The failing CI is unfortunately caused by out-dated translations on |
Basically this hierarchical structure is better render of what the CLI outputs at the moment. To illustrate it further, compare the screenshot and the table in this post:
Sure. Definitely you know better :) |
Generally speaking, I try to avoid refactor unless we are solving a code pain point. Looks like you'd be good to not make all this additions to Merger.h/cpp |
I completely understand that and agree that unnecessary refactorings can cause a lot of pain. I looked again at the alternative which is modifying the database (or a temporary copy of it) and restore the original database if the merge was aborted. keepassxc/src/gui/DatabaseWidget.cpp Line 1838 in a472ef8
|
Undo refactorings to keep it simple.
// deep copy of root group with same uuid | ||
auto tmpRootGroup = m_targetDatabase->rootGroup()->clone(Entry::CloneFlag::CloneIncludeHistory, | ||
Group::CloneFlag::CloneIncludeEntries); | ||
Database tmpDatabase; | ||
tmpDatabase.setRootGroup(tmpRootGroup); | ||
m_changes = Merger(m_sourceDatabase.data(), &tmpDatabase).merge(); |
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.
@droidmonkey while this kind works, is there a better way to clone a database? Wasn't able to find one in the current code base.
Also, this does not include the Database::m_metadata
which doesn't leads to missing changes regarding Recycling Bin and Custom Icons - is there a reason why it doesn't implement a clone()
function or should I implement it to do a full deep copy of a database?
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'd have to check but I don't think so since cloning a database is not really a thing in the program. Not saying it wouldn't be useful, but the current method you are using here is not the correct way. That would be more like transferring root group and children.
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.
But doesn't Group::clone()
create an independent copy of the root group (the ownership of which I then transfer to the temporary database)?
The alternative to cloning the database would be to implement something like discardModifications()
for a database - as far as I can see, that doesn't exist yet. But then we have to be absolutely sure that no one will save the database in the meantime before the merge is confirmed.
Which of these two approaches do you think fit the current design better? Or do you have another idea on how to achieve such a "temporary merge" without major changes to the merge logic?
Another (hopefully small) addition you could make to this merge window is the option to exclude entries from the merge. Let's say we have DB foo and DB bar both with some new and outdated entries. You might want to exclude the outdated entries when merging to avoid having to roll them back later. |
When implementing my first draft, I had this feature already in mind (although for a separate PR). However, this could require a complete rewrite of the merge logic which was rejected before (see #10173 (comment)) for valid reasons - refactoring such a complex part of the code is not without risks. Otherwise, I'm currently waiting on feedback on #10173 (comment) @droidmonkey - some hints on how you think the feature would fit the current architecture best would be appreciated. |
This PR adds a dialog allowing a user to review the changes of a merge operation.
This dialog displays the changes and allows the user to abort the merge without modifying the database.
Fixes #1152
Screenshots
Testing strategy
Manual testing and the execution of the already existing test suite
testmerge
.I also added a some basic tests verifying that a database will remain unmodified when only calculating the changelist and if for a merge without re-calculation only that changelist will be applied to the database.
Type of change