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

PyRevit Synchronise #1832

Closed
Robbo1234 opened this issue May 31, 2023 · 39 comments
Closed

PyRevit Synchronise #1832

Robbo1234 opened this issue May 31, 2023 · 39 comments
Assignees
Labels
New Feature New feature request [class->Implemented #{number}: {title}] Tools Issues related to pyRevit commands [subsystem]

Comments

@Robbo1234
Copy link

Is your feature request related to a problem? Please describe.

Best practice for synchronising in Revit would be as follows:

  1. Reload Latest before you Synchronise with Central.
  2. To speed up Synchronise with Central close hidden views and only have a generic drafting view open when synchronising.

Describe the solution you'd like
To speed up this process would it be possible to have a PyRevit Sync button that automates the following:

  1. Reload the Latest
  2. Open the default Starting View
  3. Close Inactive (Views)
  4. Save and Sync

image

Additional context
Maybe one could Shift-Click to control what Revit commands you want to run when Synchronising with Central.

@jmcouffin
Copy link
Contributor

something proposed by @alexdaversa is treating some features of your request #1692

@jmcouffin jmcouffin added Tools Issues related to pyRevit commands [subsystem] New Feature New feature request [class->Implemented #{number}: {title}] labels May 31, 2023
@thumDer
Copy link
Contributor

thumDer commented Jun 3, 2023

@jmcouffin this seems like exactly what we just started to implement, but haven't finished. we should blow the dust off.

@jmcouffin
Copy link
Contributor

Care for a working session this week in the morning @thumDer to check it out?

@alexdaversa
Copy link
Contributor

All, this feature seems complimentary to the feature I had developed, but probably separate. The autosave PR only periodically saves the local, but does not sync to central.

I could see this being implemented with two different approaches: one which uses the doc-syncing hook, and one which utilizes a toolbar button. Either approach seems viable, but if using the hooks approach, please provide a toggle to turn off this "enhanced sync" feature. I expect some users might be confused or upset that the tool closes open views. Look at my PR for an example of this.

@jmcouffin
Copy link
Contributor

@alexdaversa yeah,
I did not want to push your excellent PR right away exactly for that reason.
I am still trying to figure out what would be the best approach for both features.

  • Auto-sync must be optionnal and auto save as well.
  • Closing all windows should be optional as well in both features
  • Maybe reopening closed windows could be an option if there are not too many of them as it would be painful on complex models

@thumDer
Copy link
Contributor

thumDer commented Jun 14, 2023

Sorry for getting back late, I'm too busy these days.
My insights:

  • reopening the closed views shouldn't be significantly slower than syncing while keeping them open (Revit regenerates them on reload latest)
  • the manual sync function is like 80% done, making it attached to the built-in sync would require starting it over but at least a significant modification.
  • if we decide on making it automatic we have to consider the following:
    • it shouldn't be timebased as the auto-save tool, because this could have more dangerous consequences, so the only way to solve it is to attach it to the doc-syncing event via a hook as you guys already said
    • we will have to cancel the original sync, store it's options, and initiate ours reusing these options
    • regarding compact sync we will have to store the count of normal syncs and compare it against the config, and store this value in a DataStorage element. this I've already implemented
    • AFAIK we can only have a single hook script for a specific event per extension, so we'll have to deceide wether this tool needs its own extension, or should it be included in the pyRevitTools extension
    • the config should have it's own pushbutton, preferably in the Project panel
    • if no config is set (no view closing, no compact sync) we should let the original sync event to execute

What do you guys think? Should we keep going according the above, or do you have any objections?

@jmcouffin
Copy link
Contributor

jmcouffin commented Jun 20, 2023

  • closing views, most probablynit a big impact, would need some testing. I still feel reopening might impact performance
  • automatic? Yes
    • there are a few examples of this on the building coder blog
    • i would be comfortable to have it in PYREVIT tools base set, but it will require extensive testing before releasing it, this is not something we would like breaking a Revit file
    • the config with it's own button or part of the settings. The activation should be a toggle button, so that user sees it's activated:
      • config in pushbutton or built-in settings
      • toggle button to show activation state
      • hook to bypass sync for custom sync

@thumDer
Copy link
Contributor

thumDer commented Jun 30, 2023

I have bad news. I wasn't able to initiate a new sync from the hook, after cancelling the original. It will throw an Internal Error, which has no explanation in the API docs:

Script Executor Traceback:
Autodesk.Revit.Exceptions.InternalException: An internal error has occurred.
 at Autodesk.Revit.DB.Document.SynchronizeWithCentral(TransactWithCentralOptions transactOptions, SynchronizeWithCentralOptions syncOptions)

Our custom sync function sometimes also throws the same...

Here is the related API forum thread, if anyone is interested.

Here is my first experimental hook, if anybody has some time to play with it:

from pyrevit import script, EXEC_PARAMS

from Autodesk.Revit.DB import TransactWithCentralOptions
from Autodesk.Revit.DB import SynchronizeWithCentralOptions
from Autodesk.Revit.DB import ICentralLockedCallback

logger = script.get_logger()
event_args = EXEC_PARAMS.event_args
doc = event_args.Document

comment_suffix = " pyRevit sync yo!"

class SyncLockCallback(ICentralLockedCallback):
    def ShouldWaitForLockAvailability(self):
        return False

options = event_args.Options
logger.info('Options:')
for attr in dir(options):
    if attr.startswith('__') or callable(getattr(options, attr)):
        continue
    logger.info('{}: {}'.format(attr, getattr(options, attr)))

if comment_suffix in options.Comment:
    script.exit()

logger.info('Cancelling...')
event_args.Cancel()
logger.info('Cancelled!')

twc_opts = TransactWithCentralOptions()
# twc_opts.SetLockCallback(SyncLockCallback())
# swc_opts = SynchronizeWithCentralOptions()
swc_opts = options
swc_opts.Comment += " pyRevit sync yo!"

doc.SynchronizeWithCentral(twc_opts, swc_opts)

@Robbo1234
Copy link
Author

Could we release a simplified version of this tool minus the auto-save that does the following as per my original post?

  1. Reload the Latest
  2. Open the default Starting View
  3. Close Inactive (Views)
  4. Save and Sync

@aniketdikshit
Copy link

I can take a gander at this - if nobody else is already doing it @jmcouffin @thumDer - Let me know :)

@jmcouffin
Copy link
Contributor

@aniketdikshit please do.
I think most of the code needed is in here and #1692
But we must put some thoughts to see where and how to implement it properly so that it does not cause more harm, whatever the use case.
Not everybody wants this, maybe making it a specific extension that is not activated by default is the best path.
making it a smart button to autosave and sync OR making it a regular button as a one off.
As or the location in the ui, what Robbo mentions in its request looks fine to me.
Thoughts anyone?

@aniketdikshit
Copy link

aniketdikshit commented Oct 23, 2023

I was planning on making it a regular button as a one-off to start with :) - we eventually add more complexity - currently following what @Robbo1234 pointed out as a 4 step process should be a good starting point - though closing all inactive views is slightly dangerous - so that's probably going to a checkbox

@nterranova
Copy link

Hey everyone, this might be a separate feature, but I wanted to support this effort however possible, and just kinda let you all know what I am hoping to do soon.

My team has recently requested a "sync queue" feature, especially for large projects. We've talked to other firms who have done this internally, but this just felt like a feature that should be available to everyone to be most effective. I haven't started on my own implementation yet, but if you want me to plug into this effort anywhere just let me know. Otherwise, I can get to a point where I can submit a PR and let you all take a look.

For reference, details of the ask are:

  1. Ability to Join and Leave the queue
  2. Store the queue in a cloud location so that multiple firms in the same model could join the same queue
  3. Sync NOW option to jump the queue

There are of course other implications of these requests that we'll run into as the tool grows.

@aniketdikshit
Copy link

aniketdikshit commented Nov 7, 2023

@jmcouffin @Robbo1234 I didn't know how to submit a PR for this repo and also couldn't create a fun icon - but this is how the code stands

  1. this first gives a pop-up as to whether you want to close all inactive views
  2. then switch the active view to the first drafting view that it finds (if no drafting views then it doesn't switch the current view)
  3. then saves - reloads latest - saves and syncs
  4. 30%ish quicker sync

feel free to put this code in a script.py and use it as is

also - if you place this code in the hooks folder in these Python files then this Sync can replace the command binding and would be the default sync for the users:

command-exec[ID_FILE_SAVE_TO_CENTRAL].py
command-exec[ID_FILE_SAVE_TO_CENTRAL_SHORTCUT].py
from Autodesk.Revit import DB, UI
from pyrevit import script

doc = __revit__.ActiveUIDocument.Document
uidoc = __revit__.ActiveUIDocument

def close_inactiveviews() :
    td = UI.TaskDialog('Better Sync')
    td.TitleAutoPrefix = False
    td.ExtraCheckBoxText = 'Close Inactive Open Views'
    td.MainInstruction = 'Synchronize the Active Document'
    td.MainContent  = 'Central File Path \n{} '.format(doc.PathName)
    td.CommonButtons = UI.TaskDialogCommonButtons.Cancel | UI.TaskDialogCommonButtons.Ok
    td.AllowCancellation = True
    result = td.Show()
    if result == UI.TaskDialogResult.Cancel or result == UI.TaskDialogResult.Close :
        script.exit()
    return td.WasExtraCheckBoxChecked()

'This gets the first drafting view to allow for quick syncing'
def get_first_draftingView() :
    all_views = (DB.FilteredElementCollector(doc).
                 OfClass(DB.View).
                 WhereElementIsNotElementType().
                 ToElements())
    for view in all_views :
        if view.ViewType == DB.ViewType.DraftingView :
            return view
            break


'This closes all views for the current document except the one that is passed through as input'
def close_views(view_list) :
    all_open_views = uidoc.GetOpenUIViews()
    for ui_view in all_open_views :
        doc_view = doc.GetElement(ui_view.ViewId)
        if doc_view.Name not in view_list :
            ui_view.Close()

def sync_document() :
    if doc.IsWorkshared and not doc.IsFamilyDocument and not doc.IsLinked :
        try:
            first_draftingview = get_first_draftingView()
            if uidoc.ActiveView.ViewType != DB.ViewType.DraftingView :
                uidoc.ActiveView = first_draftingview
        except :
            pass
        if close_inactiveviews() :
            close_views(doc.ActiveView.Name)

        transOptions = DB.TransactWithCentralOptions()
        syncOptions = DB.SynchronizeWithCentralOptions()
        relinquish_all = True
        relinquishOptions = DB.RelinquishOptions(relinquish_all)
        reloadLatestOptions = DB.ReloadLatestOptions()

        saveOptions = DB.SaveOptions()

        syncOptions.SetRelinquishOptions(relinquishOptions)
        syncOptions.Compact = True
        doc.Save(saveOptions)
        doc.ReloadLatest(reloadLatestOptions)
        doc.Save(saveOptions)
        doc.SynchronizeWithCentral(transOptions , syncOptions)

    else :
        UI.TaskDialog.Show("Error" , "Current Document is not Workshared")


if __name__ == "__main__" :
    sync_document()

@Robbo1234
Copy link
Author

Robbo1234 commented Nov 7, 2023 via email

@jmcouffin
Copy link
Contributor

Hey everyone, this might be a separate feature, but I wanted to support this effort however possible, and just kinda let you all know what I am hoping to do soon.

My team has recently requested a "sync queue" feature, especially for large projects. We've talked to other firms who have done this internally, but this just felt like a feature that should be available to everyone to be most effective. I haven't started on my own implementation yet, but if you want me to plug into this effort anywhere just let me know. Otherwise, I can get to a point where I can submit a PR and let you all take a look.

For reference, details of the ask are:

  1. Ability to Join and Leave the queue
  2. Store the queue in a cloud location so that multiple firms in the same model could join the same queue
  3. Sync NOW option to jump the queue

There are of course other implications of these requests that we'll run into as the tool grows.

This is interesting, but probably an entirely different feature (and a big one) You coul dcreate a new issue/feature request @nterranova

@jmcouffin
Copy link
Contributor

jmcouffin commented Nov 7, 2023

@jmcouffin @Robbo1234 I didn't know how to submit a PR for this repo and also couldn't create a fun icon - but this is how the code stands

I will try it and make the PR, Thanks a lot @aniketdikshit

@thumDer would you like to do the PR and review?

@Robbo1234 Sir, Yes Sir! Whenever I get the chance

@jmcouffin
Copy link
Contributor

first implementation #2008
should be available in a few minutes here https://github.com/eirannejad/pyRevit/actions/runs/6944599944
@Robbo1234 @aniketdikshit

if you want to review @thumDer ?

Copy link
Contributor

📦 New work-in-progress (wip) builds are available for 4.8.14.23326+1241-wip

Copy link
Contributor

📦 New work-in-progress (wip) builds are available for 4.8.14.23326+2020-wip

Copy link
Contributor

📦 New work-in-progress (wip) builds are available for 4.8.14.23327+1037-wip

Copy link
Contributor

📦 New work-in-progress (wip) builds are available for 4.8.14.23328+0920-wip

@Robbo1234
Copy link
Author

Thanks, Aniket and Jean-Marc for this new PyRevit feature. Rob
image

@jmcouffin
Copy link
Contributor

Thanks, Aniket and Jean-Marc for this new PyRevit feature. Rob

Try it and let us know how it goes

@Robbo1234
Copy link
Author

Robbo1234 commented Nov 29, 2023 via email

Copy link
Contributor

github-actions bot commented Dec 1, 2023

📦 New work-in-progress (wip) builds are available for 4.8.14.23335+1813-wip

@thumDer
Copy link
Contributor

thumDer commented Dec 1, 2023

Dang I've missed this one, sorry. I would be really interested if anyone else experiences random InternalExceptions on calling SynchronizeWithCentral() without any explanation. I'm about to make a pr on this to have an option to reopen the closed views.

Copy link
Contributor

github-actions bot commented Dec 4, 2023

📦 New work-in-progress (wip) builds are available for 4.8.14.23338+0813-wip

Copy link
Contributor

github-actions bot commented Dec 6, 2023

📦 New work-in-progress (wip) builds are available for 4.8.14.23340+1759-wip

Copy link
Contributor

📦 New work-in-progress (wip) builds are available for 4.8.14.23346+0717-wip

Copy link
Contributor

📦 New work-in-progress (wip) builds are available for 4.8.14.23352+1117-wip

Copy link
Contributor

📦 New work-in-progress (wip) builds are available for 4.8.14.23352+1544-wip

Copy link
Contributor

📦 New work-in-progress (wip) builds are available for 4.8.14.23353+1120-wip

Copy link
Contributor

📦 New work-in-progress (wip) builds are available for 4.8.14.23353+1222-wip

Copy link
Contributor

📦 New work-in-progress (wip) builds are available for 4.8.14.23354+0922-wip

Copy link
Contributor

📦 New work-in-progress (wip) builds are available for 4.8.14.23354+1019-wip

Copy link
Contributor

📦 New work-in-progress (wip) builds are available for 4.8.14.23354+1055-wip

Copy link
Contributor

📦 New work-in-progress (wip) builds are available for 4.8.14.24012+1924-wip

Copy link
Contributor

📦 New public release are available for 4.8.14.24016+1909

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
New Feature New feature request [class->Implemented #{number}: {title}] Tools Issues related to pyRevit commands [subsystem]
Projects
None yet
Development

No branches or pull requests

6 participants