private void setPreviousDeployments(JsArray<RSConnectDeploymentRecord> recs) {
    // clear existing deployment menu, if any
    publishMenu_.clearItems();
    defaultRec_ = null;

    // if there are existing deployments, make the UI reflect that this is a
    // republish
    if (recs != null && recs.length() > 0) {
      applyCaption("Republish");

      // find the default (last deployed record)--this needs to be done as
      // a first pass so we can identify the associated menu item in one
      // pass
      for (int i = 0; i < recs.length(); i++) {
        final RSConnectDeploymentRecord rec = recs.get(i);
        if (rec == null) continue;
        if (defaultRec_ == null || defaultRec_.getWhen() < rec.getWhen()) {
          defaultRec_ = rec;
        }
      }

      // build the deployment menu
      for (int i = 0; i < recs.length(); i++) {
        final RSConnectDeploymentRecord rec = recs.get(i);
        final DeploymentMenuItem menuItem =
            new DeploymentMenuItem(
                rec,
                rec == defaultRec_,
                new Command() {
                  @Override
                  public void execute() {
                    onPublishRecordClick(rec);
                  }
                });
        publishMenu_.addItem(menuItem);
      }

      publishMenu_.addSeparator();
      publishMenu_.addItem(
          new MenuItem(
              AppCommand.formatMenuLabel(
                  commands_.rsconnectDeploy().getImageResource(), "Other Destination...", null),
              true,
              new Scheduler.ScheduledCommand() {
                @Override
                public void execute() {
                  onPublishRecordClick(null);
                }
              }));
    } else {
      // show first-time publish button caption
      applyCaption("Publish");

      // no existing deployments to redeploy to, so just offer to make a new
      // one
      publishMenu_.addItem(
          new MenuItem(
              AppCommand.formatMenuLabel(
                  commands_.rsconnectDeploy().getImageResource(),
                  "Publish " + RSConnect.contentTypeDesc(contentType_) + "...",
                  null),
              true,
              new Scheduler.ScheduledCommand() {
                @Override
                public void execute() {
                  onPublishRecordClick(defaultRec_);
                }
              }));
    }

    // if it's a plot, show an MRU of recently deployed plot "names"
    if (contentType_ == RSConnect.CONTENT_TYPE_PLOT) {
      plotMru_.addPlotMruEntries(
          publishMenu_,
          new OperationWithInput<PlotPublishMRUList.Entry>() {
            @Override
            public void execute(Entry plot) {
              republishPlot(plot);
            }
          });
    }
    publishMenu_.addSeparator();
    publishMenu_.addItem(commands_.rsconnectManageAccounts().createMenuItem(false));
  }
  @Inject
  public PublishingPreferencesPane(
      GlobalDisplay globalDisplay,
      RSConnectServerOperations server,
      RSAccountConnector connector,
      UIPrefs prefs,
      DependencyManager deps) {
    reloadRequired_ = false;
    display_ = globalDisplay;
    uiPrefs_ = prefs;
    server_ = server;
    connector_ = connector;
    deps_ = deps;

    VerticalPanel accountPanel = new VerticalPanel();
    Label accountLabel = headerLabel("Publishing Accounts");
    HorizontalPanel hpanel = new HorizontalPanel();

    accountPanel.add(accountLabel);

    accountList_ = new RSConnectAccountList(server, globalDisplay, true, true);
    accountList_.setHeight("200px");
    accountList_.setWidth("300px");
    accountList_.getElement().getStyle().setMarginBottom(15, Unit.PX);
    accountList_.getElement().getStyle().setMarginLeft(3, Unit.PX);
    hpanel.add(accountList_);

    accountList_.setOnRefreshCompleted(
        new Operation() {
          @Override
          public void execute() {
            setButtonEnabledState();
          }
        });
    accountList_.addChangeHandler(
        new ChangeHandler() {
          @Override
          public void onChange(ChangeEvent arg0) {
            setButtonEnabledState();
          }
        });

    VerticalPanel vpanel = new VerticalPanel();
    hpanel.add(vpanel);

    connectButton_ = new ThemedButton("Connect...");
    connectButton_.getElement().getStyle().setMarginBottom(5, Unit.PX);
    connectButton_.setWidth("100%");
    connectButton_.setWrapperWidth("100%");
    connectButton_.addClickHandler(
        new ClickHandler() {
          @Override
          public void onClick(ClickEvent event) {
            onConnect();
          }
        });
    vpanel.add(connectButton_);

    reconnectButton_ = new ThemedButton("Reconnect...");
    reconnectButton_.getElement().getStyle().setMarginBottom(5, Unit.PX);
    reconnectButton_.setWidth("100%");
    reconnectButton_.setWrapperWidth("100%");
    reconnectButton_.addClickHandler(
        new ClickHandler() {
          @Override
          public void onClick(ClickEvent event) {
            onReconnect();
          }
        });
    vpanel.add(reconnectButton_);

    disconnectButton_ = new ThemedButton("Disconnect");
    disconnectButton_.setWidth("100%");
    disconnectButton_.setWrapperWidth("100%");
    disconnectButton_.addClickHandler(
        new ClickHandler() {
          @Override
          public void onClick(ClickEvent event) {
            onDisconnect();
          }
        });
    vpanel.add(disconnectButton_);

    setButtonEnabledState();

    accountPanel.add(hpanel);
    add(accountPanel);

    // special UI to show when we detect that there are account records but
    // the RSConnect package isn't installed
    final VerticalPanel missingPkgPanel = new VerticalPanel();
    missingPkgPanel.setVisible(false);
    missingPkgPanel.add(
        new Label(
            "Account records appear to exist, but cannot be viewed because a "
                + "required package is not installed."));
    ThemedButton installPkgs = new ThemedButton("Install Missing Packages");
    installPkgs.addClickHandler(
        new ClickHandler() {
          @Override
          public void onClick(ClickEvent arg0) {
            deps_.withRSConnect(
                "Viewing publish accounts",
                false,
                null,
                new CommandWithArg<Boolean>() {
                  @Override
                  public void execute(Boolean succeeded) {
                    if (succeeded) {
                      // refresh the account list to show the accounts
                      accountList_.refreshAccountList();

                      // remove the "missing package" UI
                      missingPkgPanel.setVisible(false);
                    }
                  }
                });
          }
        });
    installPkgs.getElement().getStyle().setMarginLeft(0, Unit.PX);
    installPkgs.getElement().getStyle().setMarginTop(10, Unit.PX);
    missingPkgPanel.add(installPkgs);
    missingPkgPanel.getElement().getStyle().setMarginBottom(20, Unit.PX);
    add(missingPkgPanel);

    final CheckBox chkEnableRSConnect =
        checkboxPref("Enable publishing to RStudio Connect", uiPrefs_.enableRStudioConnect());
    final HorizontalPanel rsconnectPanel = checkBoxWithHelp(chkEnableRSConnect, "rstudio_connect");
    lessSpaced(rsconnectPanel);

    add(headerLabel("Settings"));
    CheckBox chkEnablePublishing =
        checkboxPref("Enable publishing documents and apps", uiPrefs_.showPublishUi());
    chkEnablePublishing.addValueChangeHandler(
        new ValueChangeHandler<Boolean>() {
          @Override
          public void onValueChange(ValueChangeEvent<Boolean> event) {
            reloadRequired_ = true;
            rsconnectPanel.setVisible(RSConnect.showRSConnectUI() && event.getValue());
          }
        });
    add(chkEnablePublishing);

    if (RSConnect.showRSConnectUI()) add(rsconnectPanel);

    add(
        checkboxPref(
            "Show diagnostic information when publishing", uiPrefs_.showPublishDiagnostics()));

    server_.hasOrphanedAccounts(
        new ServerRequestCallback<Int>() {
          @Override
          public void onResponseReceived(Int numOrphans) {
            missingPkgPanel.setVisible(numOrphans.getValue() > 0);
          }

          @Override
          public void onError(ServerError error) {
            // if we can't determine whether orphans exist, presume that they
            // don't (this state is recoverable as we'll attempt to install
            // rsconnect if necessary and refresh the account list when the user
            // tries to interact with it)
          }
        });
  }
 private void onPublishRecordClick(final RSConnectDeploymentRecord previous) {
   switch (contentType_) {
     case RSConnect.CONTENT_TYPE_HTML:
     case RSConnect.CONTENT_TYPE_PRES:
       if (publishHtmlSource_ == null) {
         display_.showErrorMessage(
             "Content Publish Failed", "No HTML could be generated for the content.");
         return;
       }
       publishHtmlSource_.generatePublishHtml(
           new CommandWithArg<String>() {
             @Override
             public void execute(String arg) {
               events_.fireEvent(
                   RSConnectActionEvent.DeployHtmlEvent(
                       contentType_, contentPath_, arg, publishHtmlSource_.getTitle(), previous));
             }
           });
       break;
     case RSConnect.CONTENT_TYPE_PLOT:
       // for plots, we need to generate the hosting HTML prior to publishing
       if (publishHtmlSource_ != null) {
         publishHtmlSource_.generatePublishHtml(
             new CommandWithArg<String>() {
               @Override
               public void execute(String htmlFile) {
                 events_.fireEvent(RSConnectActionEvent.DeployPlotEvent(htmlFile, previous));
               }
             });
       }
       break;
     case RSConnect.CONTENT_TYPE_APP:
     case RSConnect.CONTENT_TYPE_APP_SINGLE:
       // Shiny application
       events_.fireEvent(
           RSConnectActionEvent.DeployAppEvent(contentPath_, contentType_, previous));
       break;
     case RSConnect.CONTENT_TYPE_DOCUMENT:
       if (docPreview_ == null
           || (docPreview_.isStatic()
               && StringUtil.isNullOrEmpty(docPreview_.getOutputFile())
               && docPreview_.getSourceFile() != null)) {
         // if the doc has been saved but not been rendered, go render it and
         // come back when we're finished
         renderThenPublish(contentPath_, previous);
       } else {
         // All R Markdown variants (single/multiple and static/Shiny)
         if (docPreview_.getSourceFile() == null) {
           display_.showErrorMessage(
               "Unsaved Document",
               "Unsaved documents cannot be published. Save the document "
                   + "before publishing it.");
           break;
         }
         events_.fireEvent(
             RSConnectActionEvent.DeployDocEvent(
                 docPreview_, RSConnect.CONTENT_TYPE_DOCUMENT, previous));
       }
       break;
     case RSConnect.CONTENT_TYPE_WEBSITE:
       events_.fireEvent(
           RSConnectActionEvent.DeployDocEvent(
               docPreview_, RSConnect.CONTENT_TYPE_WEBSITE, previous));
       break;
     default:
       // should never happen
       display_.showErrorMessage(
           "Can't Publish " + RSConnect.contentTypeDesc(contentType_),
           "The content type '"
               + RSConnect.contentTypeDesc(contentType_)
               + "' is not currently supported for publishing.");
   }
 }