diff options
author | Eric P <eric@kastelo.net> | 2023-02-09 09:14:36 +0100 |
---|---|---|
committer | GitHub <noreply@github.com> | 2023-02-09 09:14:36 +0100 |
commit | 0530f0edbf57db8f8765be523bd1ad8f2f3deac8 (patch) | |
tree | a0ffb6e9d5ef29010e5fd7e3c01f221acc1e276b | |
parent | 784129e1cf89220dfceb2c3c2cbdc04c150a33b3 (diff) |
gui: Add xattr filter editor (fixes #8660) (#8734)
-rw-r--r-- | gui/default/assets/css/overrides.css | 4 | ||||
-rwxr-xr-x | gui/default/syncthing/core/syncthingController.js | 79 | ||||
-rw-r--r-- | gui/default/syncthing/folder/editFolderModalView.html | 56 |
3 files changed, 139 insertions, 0 deletions
diff --git a/gui/default/assets/css/overrides.css b/gui/default/assets/css/overrides.css index 47147f3d2c..06f705629a 100644 --- a/gui/default/assets/css/overrides.css +++ b/gui/default/assets/css/overrides.css @@ -144,6 +144,10 @@ table.table-auto td { max-width: 0px; } +td input[type="checkbox"] { + margin-top: 13px; +} + /* Remote Devices connection-quality indicator */ .reception-0 { background: url('../../vendor/bootstrap/fonts/reception-0.svg') no-repeat; diff --git a/gui/default/syncthing/core/syncthingController.js b/gui/default/syncthing/core/syncthingController.js index f61f0b0cf7..495e4e1b07 100755 --- a/gui/default/syncthing/core/syncthingController.js +++ b/gui/default/syncthing/core/syncthingController.js @@ -2301,6 +2301,7 @@ angular.module('syncthing.core') return; } + $scope.validateXattrFilter(); var folderCfg = angular.copy($scope.currentFolder); $scope.currentSharing.selected[$scope.myID] = true; var newDevices = []; @@ -3330,6 +3331,84 @@ angular.module('syncthing.core') $scope.showTemporaryTooltip(event, message); }; + + $scope.newXattrEntry = function () { + var entries = $scope.currentFolder.xattrFilter.entries; + var newEntry = {match: '', permit: false}; + + if (entries.some(function (n) { + return n.match == ''; + })) { + return; + } + + if (entries.length > 0 && entries[entries.length -1].match === '*') { + if (newEntry.match !== '*') { + entries.splice(entries.length - 1, 0, newEntry); + } + + return; + } + + entries.push(newEntry); + }; + + $scope.removeXattrEntry = function (entry) { + $scope.currentFolder.xattrFilter.entries = $scope.currentFolder.xattrFilter.entries.filter(function (n) { + return n !== entry; + }); + }; + + $scope.getXattrHint = function () { + var xattrFilter = $scope.currentFolder.xattrFilter; + if (xattrFilter == null || xattrFilter == {}) { + return ''; + } + var filterEntries = xattrFilter.entries; + if (filterEntries.length === 0) { + return ''; + } + + // When the user explicitely added a wild-card, we don't show hints. + if (filterEntries.length === 1 && filterEntries[0].match === '*') { + return ''; + } + // If all the filter entries are 'deny', we suggest adding a permit-any + // rule in the end since the default is already deny in that case. + if (filterEntries.every(function (entry) { + return entry.permit === false; + })) { + return $translate.instant('Hint: only deny-rules detected while the default is deny. Consider adding "permit any" as last rule.'); + } + + return ''; + }; + + $scope.getXattrDefault = function () { + var xattrFilter = $scope.currentFolder.xattrFilter; + if (xattrFilter == null || xattrFilter == {}) { + return ''; + } + + var filterEntries = xattrFilter.entries; + // No entries present, default is thus 'allow' + if (filterEntries.length === 0) { + return $translate.instant('permit'); + } + // If any rule is present and the last entry isn't a wild-card, the default is deny. + if (filterEntries[filterEntries.length -1].match !== '*') { + return $translate.instant('deny'); + } + + return ''; + }; + + $scope.validateXattrFilter = function () { + // Fitlering out empty rules when saving the config + $scope.currentFolder.xattrFilter.entries = $scope.currentFolder.xattrFilter.entries.filter(function (n) { + return n.match !== ""; + }); + }; }) .directive('shareTemplate', function () { return { diff --git a/gui/default/syncthing/folder/editFolderModalView.html b/gui/default/syncthing/folder/editFolderModalView.html index a21c45472c..6564479d0f 100644 --- a/gui/default/syncthing/folder/editFolderModalView.html +++ b/gui/default/syncthing/folder/editFolderModalView.html @@ -323,7 +323,63 @@ </p> </div> </div> + + <div class="row" ng-if="currentFolder.syncXattrs"> + <div class="col-md-12"> + <p> + <label translate>Extended Attributes Filter</label> + <a href="{{docsURL('advanced/folder-xattr-filter')}}" target="_blank"><span class="fas fa-question-circle"></span> <span translate>Help</span></a> + </p> + </div> + <div class="col-md-6"> + <p translate class="help-block"> + To permit a rule, have the checkbox checked. To deny a rule, leave it unchecked. + </p> + <label translate>Active filter rules</label> + <table class="table table-condensed"> + <colgroup> + <col class="col-xs-1 center"/> + <col class="col-xs-9"/> + <col class="col-xs-2"/> + </colgroup> + <tr ng-repeat="entry in currentFolder.xattrFilter.entries"> + <td> + <input type="checkbox" ng-model="entry.permit"> + </td> + <td><input class="form-control text-left" aria-required="true" ng-model="entry.match"/></td> + <td> + <button type="button" class="btn btn-default form-control" ng-click="removeXattrEntry(entry)"> + <span class="fas fa-trash-alt"></span> + </button> + </td> + </tr> + </table> + <div class="form-group"> + <button type="button" class="btn btn-default" ng-click="newXattrEntry()"> + <span class="fas fa-plus"></span> <span translate>Add filter entry</span> + </button> + </div> + <p ng-if="currentFolder.xattrFilter.entries.length === 0"> + <i translate>No rules set</i> + </p> + <p ng-if="getXattrDefault() !== ''"> + <i><span translate>Default</span>: {{getXattrDefault()}}</i> + </p> + <p ng-if="getXattrHint() !== ''"> + <i>{{getXattrHint()}}</i> + </p> + </div> + <div class="col-md-6 form-group"> + <label for="xattrMaxSingleEntrySize" translate>Maximum single entry size</label> + <input name="xattrMaxSingleEntrySize" id="xattrMaxSingleEntrySize" class="form-control" type="number" ng-model="currentFolder.xattrFilter.maxSingleEntrySize" required="" aria-required="true" min="0" /> + </div> + <div class="col-md-6 form-group"> + <label for="xattrMaxTotalSize" translate>Maximum total size</label> + <input name="xattrMaxTotalSize" id="xattrMaxTotalSize" class="form-control" type="number" ng-model="currentFolder.xattrFilter.maxTotalSize" required="" aria-required="true" min="0" /> + </div> + </div> </div> + </div> </form> </div> |