cancel
Showing results for 
Search instead for 
Did you mean: 

How to permanently delete items in search trash?

Jean-Michel_Cau
Champ in-the-making
Champ in-the-making

How to permanently delete items in search trash?

In Web UI :

  • No action button as "empty trash" is visible
  • No action button appears in blue menu bar when items are selected

If it is not possible in Web UI, is there any solution using Nuxeo API?

1 ACCEPTED ANSWER

Rodri_
Star Contributor
Star Contributor

Hello,

the solution to this is quite tricky, as I think there is a small bug in "nuxeo-delete-documents-button" element, more specifically in the "_isAvailable" function. Anyway, here is the step-by-step solution:

1) First of all, create your own "nuxeo-delete-documents-button" element. Take special attention to the "_isAvailable" function, as I have changed it. The last condition should be this.hard && this._checkDocsAreTrashed(). In this way, the "hard delete" button will only appears if you are selecting trashed documents.

As you are creating a new element, remember to change its "id" in the first line and in the Polymer script. In my case, for example, I named it "nuxeo-delete-documents-button-v2".

<dom-module id="nuxeo-delete-documents-button-v2" assetpath="nuxeo-document-bulk-actions/">
  <template>
    <style include="nuxeo-action-button-styles"></style>

    <nuxeo-operation id="deleteOp" op="Document.Delete" sync-indexing=""></nuxeo-operation>

    <nuxeo-operation id="trashOp" op="Document.Trash" sync-indexing=""></nuxeo-operation>

    <template is="dom-if" if="[[_isAvailable(documents.splices)]]">
      <div class="action" on-tap="deleteDocuments">
        <paper-icon-button icon="[[_icon]]" id="deleteAllButton"></paper-icon-button>
        <span class="label" hidden$="[[!showLabel]]">[[_label]]</span>
      </div>
      <nuxeo-tooltip for="deleteAllButton" position="[[tooltipPosition]]">[[_label]]</nuxeo-tooltip>
    </template>
  </template>

  <script>
    Polymer({
      is: 'nuxeo-delete-documents-button-v2',
      behaviors: [Nuxeo.I18nBehavior, Nuxeo.FiltersBehavior],
      properties: {
        documents: {
          type: Array,
          notify: true,
          value: []
        },

        /**
         * Permanently delete the documents.
         */
        hard: {
          type: Boolean,
          value: false
        },

        tooltipPosition: {
          type: String,
          value: 'bottom'
        },

        /**
         * `true` if the action should display the label, `false` otherwise.
         */
        showLabel: {
          type: Boolean,
          value: false,
        },

        _icon: {
          type: 'String',
          computed: '_computeIcon(hard)'
        },

        _label: {
          type: 'String',
          computed: '_computeLabel(hard, i18n)'
        }
      },

      deleteDocuments: function() {
        if (this.docsHavePermissions && confirm(this.i18n('deleteDocumentsButton.confirm.deleteDocuments'))) {
          if (this.documents && this.documents.length) {
            var uids = this.documents.map(function(doc) {
              return doc.uid;
            }).join(',');
            var op = this.hard ? this.$.deleteOp : this.$.trashOp;
            op.input = 'docs:' + uids;
            op.execute().then(function() {
              this.fire('nuxeo-documents-deleted', {documents: this.documents});
              this.documents = [];
              this.fire('refresh');
            }.bind(this),
            function(error) {
              this.fire('nuxeo-documents-deleted', {error: error, documents: this.documents});
            }.bind(this));
          }
        }
      },

      /**
       * Action is available if all selected items are not trashed and `hard` is not active OR if all selected items
       * are trashed and `hard` is active.
       */
      _isAvailable: function() {
        return this.documents && this.documents.length > 0 && this._checkDocsPermissions() &&
            (this.hard && this._checkDocsAreTrashed());
      },

      /**
       * Checks if all selected documents are trashed.
       */
      _checkDocsAreTrashed: function() {
        return this.documents.every(function(document) {
          return this.isTrashed(document);
        }.bind(this));
      },

      _checkDocsPermissions: function() {
        this.docsHavePermissions = this.documents && !(this.documents.some(
          function(document) {
            return !this._docHasPermissions(document);
          }.bind(this)));
        return this.docsHavePermissions;
      },

      /*
       * Checks if a single given document has 'Everything' permission to delete or 'Write' to trash
       */
      _docHasPermissions: function(document) {
        return this.hasPermission(document, 'Everything') || (!this.hard && this.hasPermission(document, 'Write'));
      },

      _computeIcon: function(hard) {
        return hard ? 'nuxeo:delete-permanently' : 'nuxeo:delete';
      },

      _computeLabel: function(hard) {
        return this.i18n(hard ? 'deleteDocumentsButton.tooltip.permanently' : 'deleteDocumentsButton.tooltip');
      }
    });
  </script>

</dom-module>

2) The next step is to contribute to the "RESULTS_SELECTION_ACTIONS" slot. You can do this by creating another HTML file with the following content. I named this file "nuxeo-custom-bundle-contribution.html", but you can name it as you want.

<link rel="import" href="nuxeo-delete-documents-button-v2.html">

<nuxeo-slot-content name="hardDeleteSelectionAction" slot="RESULTS_SELECTION_ACTIONS" order="30">
  <template>
    <nuxeo-delete-documents-button-v2 documents="[[selectedItems]]" hard></nuxeo-delete-documents-button-v2>
  </template>
</nuxeo-slot-content>

Take in mind that you need to import the HTML we have created before, and add the new element (that in my case, I named "nuxeo-delete-documents-button-v2"). Also pay attention to the "hard" label I have added in the element.

3) Just like any WebUI contribution, you need to add it to the resources point. To do that, create a new extension like this:

<extension target="org.nuxeo.ecm.platform.WebResources" point="resources">
    <resource name="nuxeo-custom-bundle-contribution.html" type="import" shrinkable="false">
	<uri>/ui/nuxeo-custom-bundle-contribution.html</uri>
    </resource>
</extension>
<extension target="org.nuxeo.ecm.platform.WebResources" point="bundles">
    <bundle name="web-ui">
	<resources append="true">
	        <resource>nuxeo-custom-bundle-contribution.html</resource>
	</resources>
    </bundle>
</extension>

As you can see, I have referenced "nuxeo-custom-bundle-contribution.html" file, which is the file I have created in step 2.

With this, you will have the "hard delete" button when you select trashed documents, keeping the "trash document" button if you select not trashed documents.

Regards!

View answer in original post

3 REPLIES 3

Gregory_Carlin
Elite Collaborator
Elite Collaborator

Hello,

You need to disable solft delete default config (see https://doc.nuxeo.com/nxdoc/trash-service/#soft-delete and optionally remove the corresponding Web UI slot contribution https://doc.nuxeo.com/nxdoc/how-to-disable-trash/

Regards

Jean-Michel_Cau
Champ in-the-making
Champ in-the-making

Thanks, but I don't want to remove soft delete feature. I just want to have a hard delete action to permanently delete document when browsing the trash search. This action is available on a folder document but not in trash search... Regards

Rodri_
Star Contributor
Star Contributor

Hello,

the solution to this is quite tricky, as I think there is a small bug in "nuxeo-delete-documents-button" element, more specifically in the "_isAvailable" function. Anyway, here is the step-by-step solution:

1) First of all, create your own "nuxeo-delete-documents-button" element. Take special attention to the "_isAvailable" function, as I have changed it. The last condition should be this.hard && this._checkDocsAreTrashed(). In this way, the "hard delete" button will only appears if you are selecting trashed documents.

As you are creating a new element, remember to change its "id" in the first line and in the Polymer script. In my case, for example, I named it "nuxeo-delete-documents-button-v2".

<dom-module id="nuxeo-delete-documents-button-v2" assetpath="nuxeo-document-bulk-actions/">
  <template>
    <style include="nuxeo-action-button-styles"></style>

    <nuxeo-operation id="deleteOp" op="Document.Delete" sync-indexing=""></nuxeo-operation>

    <nuxeo-operation id="trashOp" op="Document.Trash" sync-indexing=""></nuxeo-operation>

    <template is="dom-if" if="[[_isAvailable(documents.splices)]]">
      <div class="action" on-tap="deleteDocuments">
        <paper-icon-button icon="[[_icon]]" id="deleteAllButton"></paper-icon-button>
        <span class="label" hidden$="[[!showLabel]]">[[_label]]</span>
      </div>
      <nuxeo-tooltip for="deleteAllButton" position="[[tooltipPosition]]">[[_label]]</nuxeo-tooltip>
    </template>
  </template>

  <script>
    Polymer({
      is: 'nuxeo-delete-documents-button-v2',
      behaviors: [Nuxeo.I18nBehavior, Nuxeo.FiltersBehavior],
      properties: {
        documents: {
          type: Array,
          notify: true,
          value: []
        },

        /**
         * Permanently delete the documents.
         */
        hard: {
          type: Boolean,
          value: false
        },

        tooltipPosition: {
          type: String,
          value: 'bottom'
        },

        /**
         * `true` if the action should display the label, `false` otherwise.
         */
        showLabel: {
          type: Boolean,
          value: false,
        },

        _icon: {
          type: 'String',
          computed: '_computeIcon(hard)'
        },

        _label: {
          type: 'String',
          computed: '_computeLabel(hard, i18n)'
        }
      },

      deleteDocuments: function() {
        if (this.docsHavePermissions && confirm(this.i18n('deleteDocumentsButton.confirm.deleteDocuments'))) {
          if (this.documents && this.documents.length) {
            var uids = this.documents.map(function(doc) {
              return doc.uid;
            }).join(',');
            var op = this.hard ? this.$.deleteOp : this.$.trashOp;
            op.input = 'docs:' + uids;
            op.execute().then(function() {
              this.fire('nuxeo-documents-deleted', {documents: this.documents});
              this.documents = [];
              this.fire('refresh');
            }.bind(this),
            function(error) {
              this.fire('nuxeo-documents-deleted', {error: error, documents: this.documents});
            }.bind(this));
          }
        }
      },

      /**
       * Action is available if all selected items are not trashed and `hard` is not active OR if all selected items
       * are trashed and `hard` is active.
       */
      _isAvailable: function() {
        return this.documents && this.documents.length > 0 && this._checkDocsPermissions() &&
            (this.hard && this._checkDocsAreTrashed());
      },

      /**
       * Checks if all selected documents are trashed.
       */
      _checkDocsAreTrashed: function() {
        return this.documents.every(function(document) {
          return this.isTrashed(document);
        }.bind(this));
      },

      _checkDocsPermissions: function() {
        this.docsHavePermissions = this.documents && !(this.documents.some(
          function(document) {
            return !this._docHasPermissions(document);
          }.bind(this)));
        return this.docsHavePermissions;
      },

      /*
       * Checks if a single given document has 'Everything' permission to delete or 'Write' to trash
       */
      _docHasPermissions: function(document) {
        return this.hasPermission(document, 'Everything') || (!this.hard && this.hasPermission(document, 'Write'));
      },

      _computeIcon: function(hard) {
        return hard ? 'nuxeo:delete-permanently' : 'nuxeo:delete';
      },

      _computeLabel: function(hard) {
        return this.i18n(hard ? 'deleteDocumentsButton.tooltip.permanently' : 'deleteDocumentsButton.tooltip');
      }
    });
  </script>

</dom-module>

2) The next step is to contribute to the "RESULTS_SELECTION_ACTIONS" slot. You can do this by creating another HTML file with the following content. I named this file "nuxeo-custom-bundle-contribution.html", but you can name it as you want.

<link rel="import" href="nuxeo-delete-documents-button-v2.html">

<nuxeo-slot-content name="hardDeleteSelectionAction" slot="RESULTS_SELECTION_ACTIONS" order="30">
  <template>
    <nuxeo-delete-documents-button-v2 documents="[[selectedItems]]" hard></nuxeo-delete-documents-button-v2>
  </template>
</nuxeo-slot-content>

Take in mind that you need to import the HTML we have created before, and add the new element (that in my case, I named "nuxeo-delete-documents-button-v2"). Also pay attention to the "hard" label I have added in the element.

3) Just like any WebUI contribution, you need to add it to the resources point. To do that, create a new extension like this:

<extension target="org.nuxeo.ecm.platform.WebResources" point="resources">
    <resource name="nuxeo-custom-bundle-contribution.html" type="import" shrinkable="false">
	<uri>/ui/nuxeo-custom-bundle-contribution.html</uri>
    </resource>
</extension>
<extension target="org.nuxeo.ecm.platform.WebResources" point="bundles">
    <bundle name="web-ui">
	<resources append="true">
	        <resource>nuxeo-custom-bundle-contribution.html</resource>
	</resources>
    </bundle>
</extension>

As you can see, I have referenced "nuxeo-custom-bundle-contribution.html" file, which is the file I have created in step 2.

With this, you will have the "hard delete" button when you select trashed documents, keeping the "trash document" button if you select not trashed documents.

Regards!