@recaptime-dev's working patches + fork for Phorge, a community fork of Phabricator. (Upstream dev and stable branches are at upstream/main and upstream/stable respectively.) hq.recaptime.dev/wiki/Phorge
phorge phabricator
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

Make "hidden" changesets sticky, and show hidden state in the filetree

Summary:
Ref T13455. Make "hidden" a changeset property similar to other changeset properties.

We don't need to render this on the server, so we make a request (to update the setting) and just discard the response.

Test Plan: {F7375468}

Maniphest Tasks: T13455

Differential Revision: https://secure.phabricator.com/D21158

+229 -37
+22 -22
resources/celerity/map.php
··· 12 12 'core.pkg.css' => 'dd5f04a3', 13 13 'core.pkg.js' => '544bc792', 14 14 'differential.pkg.css' => 'cb99cd21', 15 - 'differential.pkg.js' => '6c315e3f', 15 + 'differential.pkg.js' => '54613dd5', 16 16 'diffusion.pkg.css' => '42c75c37', 17 17 'diffusion.pkg.js' => 'a98c0bf7', 18 18 'maniphest.pkg.css' => '35995d6d', ··· 59 59 'rsrc/css/application/countdown/timer.css' => 'bff8012f', 60 60 'rsrc/css/application/daemon/bulk-job.css' => '73af99f5', 61 61 'rsrc/css/application/dashboard/dashboard.css' => '5a205b9d', 62 - 'rsrc/css/application/diff/diff-tree-view.css' => '26fb4a0d', 62 + 'rsrc/css/application/diff/diff-tree-view.css' => 'e2d3e222', 63 63 'rsrc/css/application/diff/inline-comment-summary.css' => '81eb368d', 64 64 'rsrc/css/application/differential/add-comment.css' => '7e5900d9', 65 65 'rsrc/css/application/differential/changeset-view.css' => '489b6995', ··· 378 378 'rsrc/js/application/dashboard/behavior-dashboard-move-panels.js' => 'a2ab19be', 379 379 'rsrc/js/application/dashboard/behavior-dashboard-query-panel-select.js' => '1e413dc9', 380 380 'rsrc/js/application/dashboard/behavior-dashboard-tab-panel.js' => '0116d3e8', 381 - 'rsrc/js/application/diff/DiffChangeset.js' => 'a1a5dc46', 381 + 'rsrc/js/application/diff/DiffChangeset.js' => 'dd1a6f34', 382 382 'rsrc/js/application/diff/DiffChangesetList.js' => '57035863', 383 383 'rsrc/js/application/diff/DiffInline.js' => '16e97ebc', 384 - 'rsrc/js/application/diff/DiffPathView.js' => 'ceb66010', 384 + 'rsrc/js/application/diff/DiffPathView.js' => '8207abf9', 385 385 'rsrc/js/application/diff/DiffTreeView.js' => '5d83623b', 386 386 'rsrc/js/application/diff/behavior-preview-link.js' => 'f51e9c17', 387 387 'rsrc/js/application/differential/behavior-diff-radios.js' => '925fe8cd', ··· 558 558 'conpherence-thread-manager' => 'aec8e38c', 559 559 'conpherence-transaction-css' => '3a3f5e7e', 560 560 'd3' => '9d068042', 561 - 'diff-tree-view-css' => '26fb4a0d', 561 + 'diff-tree-view-css' => 'e2d3e222', 562 562 'differential-changeset-view-css' => '489b6995', 563 563 'differential-core-view-css' => '7300a73e', 564 564 'differential-revision-add-comment-css' => '7e5900d9', ··· 775 775 'phabricator-darklog' => '3b869402', 776 776 'phabricator-darkmessage' => '26cd4b73', 777 777 'phabricator-dashboard-css' => '5a205b9d', 778 - 'phabricator-diff-changeset' => 'a1a5dc46', 778 + 'phabricator-diff-changeset' => 'dd1a6f34', 779 779 'phabricator-diff-changeset-list' => '57035863', 780 780 'phabricator-diff-inline' => '16e97ebc', 781 - 'phabricator-diff-path-view' => 'ceb66010', 781 + 'phabricator-diff-path-view' => '8207abf9', 782 782 'phabricator-diff-tree-view' => '5d83623b', 783 783 'phabricator-drag-and-drop-file-upload' => '4370900d', 784 784 'phabricator-draggable-list' => '0169e425', ··· 1645 1645 'javelin-dom', 1646 1646 'javelin-vector', 1647 1647 ), 1648 + '8207abf9' => array( 1649 + 'javelin-dom', 1650 + ), 1648 1651 83754533 => array( 1649 1652 'javelin-install', 1650 1653 'javelin-util', ··· 1829 1832 'javelin-dom', 1830 1833 'javelin-workflow', 1831 1834 ), 1832 - 'a1a5dc46' => array( 1833 - 'javelin-dom', 1834 - 'javelin-util', 1835 - 'javelin-stratcom', 1836 - 'javelin-install', 1837 - 'javelin-workflow', 1838 - 'javelin-router', 1839 - 'javelin-behavior-device', 1840 - 'javelin-vector', 1841 - 'phabricator-diff-inline', 1842 - 'phabricator-diff-path-view', 1843 - ), 1844 1835 'a241536a' => array( 1845 1836 'javelin-install', 1846 1837 ), ··· 2079 2070 'phuix-icon-view', 2080 2071 'phabricator-busy', 2081 2072 ), 2082 - 'ceb66010' => array( 2083 - 'javelin-dom', 2084 - ), 2085 2073 'cef53b3e' => array( 2086 2074 'javelin-install', 2087 2075 'javelin-dom', ··· 2119 2107 'javelin-behavior', 2120 2108 'javelin-uri', 2121 2109 'phabricator-notification', 2110 + ), 2111 + 'dd1a6f34' => array( 2112 + 'javelin-dom', 2113 + 'javelin-util', 2114 + 'javelin-stratcom', 2115 + 'javelin-install', 2116 + 'javelin-workflow', 2117 + 'javelin-router', 2118 + 'javelin-behavior-device', 2119 + 'javelin-vector', 2120 + 'phabricator-diff-inline', 2121 + 'phabricator-diff-path-view', 2122 2122 ), 2123 2123 'e150bd50' => array( 2124 2124 'javelin-behavior',
+4
src/applications/differential/controller/DifferentialChangesetViewController.php
··· 195 195 196 196 $viewstate = $viewstate_engine->newViewStateFromRequest($request); 197 197 198 + if ($viewstate->getDiscardResponse()) { 199 + return new AphrontAjaxResponse(); 200 + } 201 + 198 202 $parser = id(new DifferentialChangesetParser()) 199 203 ->setViewer($viewer) 200 204 ->setViewState($viewstate)
+1
src/applications/differential/parser/DifferentialChangesetParser.php
··· 1895 1895 'highlight' => $viewstate->getHighlightLanguage(), 1896 1896 'characterEncoding' => $viewstate->getCharacterEncoding(), 1897 1897 'documentEngine' => $viewstate->getDocumentEngineKey(), 1898 + 'isHidden' => $viewstate->getHidden(), 1898 1899 ); 1899 1900 1900 1901 return id(new PhabricatorChangesetResponse())
+16 -6
src/applications/differential/storage/DifferentialViewState.php
··· 60 60 $key, 61 61 $default = null) { 62 62 63 - $path_hash = $this->getChangesetPathHash($changeset); 64 - 65 - $entries = idxv($this->viewState, array('changesets', $path_hash, $key)); 66 - if (!is_array($entries)) { 67 - $entries = array(); 68 - } 63 + $entries = $this->getChangesetPropertyEntries( 64 + $changeset, 65 + $key); 69 66 70 67 $entries = isort($entries, 'epoch'); 71 68 ··· 75 72 } 76 73 77 74 return idx($entry, 'value', $default); 75 + } 76 + 77 + public function getChangesetPropertyEntries( 78 + DifferentialChangeset $changeset, 79 + $key) { 80 + $path_hash = $this->getChangesetPathHash($changeset); 81 + 82 + $entries = idxv($this->viewState, array('changesets', $path_hash, $key)); 83 + if (!is_array($entries)) { 84 + $entries = array(); 85 + } 86 + 87 + return $entries; 78 88 } 79 89 80 90 public function getHasModifications() {
+4
src/applications/diffusion/controller/DiffusionDiffController.php
··· 69 69 70 70 $viewstate = $viewstate_engine->newViewStateFromRequest($request); 71 71 72 + if ($viewstate->getDiscardResponse()) { 73 + return new AphrontAjaxResponse(); 74 + } 75 + 72 76 $parser = id(new DifferentialChangesetParser()) 73 77 ->setViewer($viewer) 74 78 ->setChangeset($changeset)
+30
src/infrastructure/diff/viewstate/PhabricatorChangesetViewState.php
··· 8 8 private $documentEngineKey; 9 9 private $rendererKey; 10 10 private $defaultDeviceRendererKey; 11 + private $hidden; 12 + private $modifiedSinceHide; 13 + private $discardResponse; 11 14 12 15 public function setHighlightLanguage($highlight_language) { 13 16 $this->highlightLanguage = $highlight_language; ··· 52 55 53 56 public function getDefaultDeviceRendererKey() { 54 57 return $this->defaultDeviceRendererKey; 58 + } 59 + 60 + public function setHidden($hidden) { 61 + $this->hidden = $hidden; 62 + return $this; 63 + } 64 + 65 + public function getHidden() { 66 + return $this->hidden; 67 + } 68 + 69 + public function setModifiedSinceHide($modified_since_hide) { 70 + $this->modifiedSinceHide = $modified_since_hide; 71 + return $this; 72 + } 73 + 74 + public function getModifiedSinceHide() { 75 + return $this->modifiedSinceHide; 76 + } 77 + 78 + public function setDiscardResponse($discard_response) { 79 + $this->discardResponse = $discard_response; 80 + return $this; 81 + } 82 + 83 + public function getDiscardResponse() { 84 + return $this->discardResponse; 55 85 } 56 86 57 87 }
+59 -1
src/infrastructure/diff/viewstate/PhabricatorChangesetViewStateEngine.php
··· 60 60 $this->setChangesetProperty('renderer', $renderer); 61 61 } 62 62 63 + $hidden = $request->getStr('hidden'); 64 + if ($hidden !== null) { 65 + $this->setChangesetProperty('hidden', (int)$hidden); 66 + } 67 + 63 68 $this->saveViewStateStorage(); 64 69 65 70 $state = new PhabricatorChangesetViewState(); ··· 75 80 76 81 $renderer = $this->getChangesetProperty('renderer'); 77 82 $state->setRendererKey($renderer); 83 + 84 + $this->updateHiddenState($state); 78 85 79 86 // This is the client-selected default renderer based on viewport 80 87 // dimensions. 81 88 82 89 $device_key = $request->getStr('device'); 83 - if ($device_key !== null && strlen($device_key)) { 90 + if ($device_key !== null) { 84 91 $state->setDefaultDeviceRendererKey($device_key); 92 + } 93 + 94 + $discard_response = $request->getStr('discard'); 95 + if ($discard_response !== null) { 96 + $state->setDiscardResponse(true); 85 97 } 86 98 87 99 return $state; ··· 172 184 } 173 185 174 186 unset($unguarded); 187 + } 188 + 189 + private function updateHiddenState(PhabricatorChangesetViewState $state) { 190 + $is_hidden = false; 191 + $was_modified = false; 192 + 193 + $storage = $this->getStorage(); 194 + $changeset = $this->getChangeset(); 195 + 196 + $entries = $storage->getChangesetPropertyEntries($changeset, 'hidden'); 197 + $entries = isort($entries, 'epoch'); 198 + 199 + if ($entries) { 200 + $other_phid = last_key($entries); 201 + $other_spec = last($entries); 202 + 203 + $this_version = (int)$changeset->getDiffID(); 204 + $other_version = (int)idx($other_spec, 'diffID'); 205 + $other_value = (bool)idx($other_spec, 'value', false); 206 + 207 + if ($other_value === false) { 208 + $is_hidden = false; 209 + } else if ($other_version >= $this_version) { 210 + $is_hidden = $other_value; 211 + } else { 212 + $viewer = $this->getViewer(); 213 + 214 + $other_changeset = id(new DifferentialChangesetQuery()) 215 + ->setViewer($viewer) 216 + ->withPHIDs(array($other_phid)) 217 + ->executeOne(); 218 + 219 + $is_modified = false; 220 + if ($other_changeset) { 221 + if (!$changeset->hasSameEffectAs($other_changeset)) { 222 + $is_modified = true; 223 + } 224 + } 225 + 226 + $is_hidden = false; 227 + $was_modified = true; 228 + } 229 + } 230 + 231 + $state->setHidden($is_hidden); 232 + $state->setModifiedSinceHide($was_modified); 175 233 } 176 234 177 235 }
+13
webroot/rsrc/css/application/diff/diff-tree-view.css
··· 59 59 opacity: 0.5; 60 60 } 61 61 62 + .diff-tree-path-hidden { 63 + opacity: 0.25; 64 + } 65 + 66 + .diff-tree-path-icon-hidden, 67 + .diff-tree-path-hidden .diff-tree-path-icon-kind { 68 + display: none; 69 + } 70 + 71 + .diff-tree-path-hidden .diff-tree-path-icon-hidden { 72 + display: block; 73 + } 74 + 62 75 .diff-tree-path-owned { 63 76 border-left-color: {$orange}; 64 77 box-shadow: inset 2px 0 {$lightorange};
+38 -6
webroot/rsrc/js/application/diff/DiffChangeset.js
··· 39 39 this._pathIconColor = data.pathIconColor; 40 40 this._isLowImportance = data.isLowImportance; 41 41 this._isOwned = data.isOwned; 42 + this._isLoading = true; 42 43 43 44 this._inlines = []; 44 45 ··· 81 82 _pathIconColor: null, 82 83 _isLowImportance: null, 83 84 _isOwned: null, 85 + _isHidden: null, 84 86 85 87 getEditorURI: function() { 86 88 return this._editorURI; ··· 202 204 this._loaded = true; 203 205 this._sequence++; 204 206 205 - var params = this._getViewParameters(state); 206 - var pht = this.getChangesetList().getTranslations(); 207 - 208 - var workflow = new JX.Workflow(this._renderURI, params) 207 + var workflow = this._newReloadWorkflow(state) 209 208 .setHandler(JX.bind(this, this._onresponse, this._sequence)); 210 209 211 210 this._startContentWorkflow(workflow); 212 211 212 + var pht = this.getChangesetList().getTranslations(); 213 + 213 214 JX.DOM.setContent( 214 215 this._getContentFrame(), 215 216 JX.$N( ··· 218 219 pht('Loading...'))); 219 220 220 221 return this; 222 + }, 223 + 224 + _newReloadWorkflow: function(state) { 225 + var params = this._getViewParameters(state); 226 + return new JX.Workflow(this._renderURI, params); 221 227 }, 222 228 223 229 /** ··· 637 643 this._highlight = state.highlight; 638 644 this._characterEncoding = state.characterEncoding; 639 645 this._documentEngine = state.documentEngine; 646 + this._isHidden = state.isHidden; 647 + 648 + var is_hidden = !this.isVisible(); 649 + if (this._isHidden != is_hidden) { 650 + this.setVisible(!this._isHidden); 651 + } 652 + 653 + this._isLoading = false; 654 + this.getPathView().setIsLoading(this._isLoading); 640 655 }, 641 656 642 657 _getContentFrame: function() { ··· 844 859 }, 845 860 846 861 toggleVisibility: function() { 847 - this._visible = !this._visible; 862 + this.setVisible(!this._visible); 863 + 864 + var attrs = { 865 + hidden: this.isVisible() ? 0 : 1, 866 + discard: 1 867 + }; 868 + 869 + var workflow = this._newReloadWorkflow(attrs) 870 + .setHandler(JX.bag); 871 + 872 + this._startContentWorkflow(workflow); 873 + }, 874 + 875 + setVisible: function(visible) { 876 + this._visible = visible; 848 877 849 878 var diff = JX.DOM.find(this._node, 'table', 'differential-diff'); 850 879 var undo = this._getUndoNode(); ··· 858 887 } 859 888 860 889 JX.Stratcom.invoke('resize'); 890 + 891 + this.getPathView().setIsHidden(!this._visible); 861 892 }, 862 893 863 894 isVisible: function() { ··· 906 937 .setChangeset(this) 907 938 .setPath(this._pathParts) 908 939 .setIsLowImportance(this._isLowImportance) 909 - .setIsOwned(this._isOwned); 940 + .setIsOwned(this._isOwned) 941 + .setIsLoading(this._isLoading); 910 942 911 943 view.getIcon() 912 944 .setIcon(this._pathIconIcon)
+42 -2
webroot/rsrc/js/application/diff/DiffPathView.js
··· 23 23 _inlineNode: null, 24 24 _isDirectory: false, 25 25 _displayPath: null, 26 - _isOwned: false, 27 26 _isLowImportance: false, 27 + _isOwned: false, 28 + _isHidden: false, 29 + _isLoading: false, 28 30 29 31 getNode: function() { 30 32 if (!this._node) { ··· 142 144 return this; 143 145 }, 144 146 147 + setIsHidden: function(hidden) { 148 + this._isHidden = hidden; 149 + 150 + var node = this.getNode(); 151 + JX.DOM.alterClass(node, 'diff-tree-path-hidden', this._isHidden); 152 + 153 + return this; 154 + }, 155 + 156 + setIsLoading: function(loading) { 157 + this._isLoading = loading; 158 + 159 + var node = this.getNode(); 160 + JX.DOM.alterClass(node, 'diff-tree-path-loading', this._isLoading); 161 + 162 + return this; 163 + }, 164 + 145 165 _onclick: function(e) { 146 166 if (!e.isNormalClick()) { 147 167 return; ··· 163 183 164 184 var content = [ 165 185 this.getInlineNode(), 186 + this._getHiddenIconNode(), 166 187 this._getIconNode(), 167 188 this._getPathNode(), 168 189 ]; ··· 186 207 _getIconNode: function() { 187 208 if (!this._iconNode) { 188 209 var attrs = { 189 - className: 'diff-tree-path-icon', 210 + className: 'diff-tree-path-icon diff-tree-path-icon-kind', 190 211 }; 191 212 this._iconNode = JX.$N('div', attrs, this.getIcon().getNode()); 192 213 } 193 214 return this._iconNode; 215 + }, 216 + 217 + _getHiddenIconNode: function() { 218 + if (!this._hiddenIconNode) { 219 + var attrs = { 220 + className: 'diff-tree-path-icon diff-tree-path-icon-hidden', 221 + }; 222 + this._hiddenIconNode = 223 + JX.$N('div', attrs, this._getHiddenIcon().getNode()); 224 + } 225 + return this._hiddenIconNode; 226 + }, 227 + 228 + _getHiddenIcon: function() { 229 + if (!this._hiddenIcon) { 230 + this._hiddenIcon = new JX.PHUIXIconView() 231 + .setIcon('fa-times-circle-o'); 232 + } 233 + return this._hiddenIcon; 194 234 }, 195 235 196 236 getInlineNode: function() {