infopark_fiona7 1.5.5.5.1 → 1.6.1.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (67) hide show
  1. checksums.yaml +4 -4
  2. data/Rakefile +17 -0
  3. data/app/assets/javascripts/fiona7/task_list_dialog.js +2 -2
  4. data/app/assets/javascripts/fiona7/templates.js +1 -16
  5. data/app/assets/javascripts/fiona7/translations.js +22 -23
  6. data/app/assets/javascripts/fiona7_ui.js +56 -59
  7. data/app/assets/javascripts/scrivito_patches/base_obj_path.js +11 -5
  8. data/app/assets/javascripts/scrivito_patches/binary_request.js +53 -0
  9. data/app/assets/javascripts/scrivito_patches/client/ajax.js +122 -0
  10. data/app/assets/javascripts/scrivito_patches/{models/api → client}/basic_obj.js +150 -243
  11. data/app/assets/javascripts/scrivito_patches/client/cms_rest_api.js +209 -0
  12. data/app/assets/javascripts/scrivito_patches/components/sidebar/workspaces_panel.js +325 -0
  13. data/app/assets/javascripts/scrivito_patches/components/sidebar/workspaces_panel.js.jsx +294 -0
  14. data/app/assets/javascripts/scrivito_patches/models/{obj.js → legacy_obj.js} +27 -54
  15. data/app/assets/stylesheets/fiona7_ui.css.scss +2 -0
  16. data/app/controllers/fiona7/release_controller.rb +7 -6
  17. data/app/controllers/fiona7/sessions_controller.rb +10 -2
  18. data/app/controllers/fiona7/uploads_controller.rb +22 -0
  19. data/app/controllers/fiona7_login_page_controller.rb +3 -0
  20. data/app/controllers/scrivito/obj_class_controller.rb +28 -5
  21. data/app/views/fiona7/release/preview.html.erb +5 -38
  22. data/app/views/fiona7_login_page/index.html.erb +6 -0
  23. data/config/precedence_routes.rb +7 -7
  24. data/infopark_fiona7.gemspec +2 -2
  25. data/lib/fiona7/attribute_readers/number_as_string.rb +6 -1
  26. data/lib/fiona7/attribute_writers/binary_as_binary.rb +4 -2
  27. data/lib/fiona7/attribute_writers/binary_as_linklist.rb +4 -2
  28. data/lib/fiona7/builder/container_chain_builder.rb +50 -0
  29. data/lib/fiona7/builder/indirect_blob_builder.rb +7 -47
  30. data/lib/fiona7/builder/indirect_blob_builder_for_obj.rb +14 -0
  31. data/lib/fiona7/builder/lazy_blob_copier.rb +68 -14
  32. data/lib/fiona7/builder/obj_builder.rb +6 -32
  33. data/lib/fiona7/builder/obj_updater.rb +12 -4
  34. data/lib/fiona7/builder/widget_builder.rb +1 -1
  35. data/lib/fiona7/controllers/rest_api/blob_controller.rb +8 -2
  36. data/lib/fiona7/controllers/rest_api/obj_controller.rb +12 -8
  37. data/lib/fiona7/controllers/rest_api/workspace_controller.rb +6 -0
  38. data/lib/fiona7/engine.rb +49 -3
  39. data/lib/fiona7/forbidden_obj_classes.rb +14 -3
  40. data/lib/fiona7/linked_id_finder.rb +44 -0
  41. data/lib/fiona7/name_and_parent_from_path.rb +11 -0
  42. data/lib/fiona7/referenced_id_finder.rb +24 -0
  43. data/lib/fiona7/release_collector.rb +85 -0
  44. data/lib/fiona7/routers/rest_api.rb +2 -0
  45. data/lib/fiona7/scrivito_patches/cms_field_tag.rb +1 -0
  46. data/lib/fiona7/scrivito_patches/cms_rest_api.rb +16 -16
  47. data/lib/fiona7/scrivito_patches/cms_routing.rb +1 -0
  48. data/lib/fiona7/scrivito_patches/link_parser.rb +10 -7
  49. data/lib/fiona7/scrivito_patches/workspace.rb +0 -5
  50. data/lib/fiona7/super_id_finder.rb +68 -0
  51. data/lib/fiona7/super_object_finder.rb +5 -20
  52. data/lib/fiona7/temporary_uploader.rb +33 -0
  53. data/lib/fiona7/upload_path_selector.rb +17 -0
  54. data/lib/fiona7/verity_search_engine.rb +25 -12
  55. data/lib/fiona7/version.rb +1 -1
  56. metadata +23 -19
  57. data/app/assets/javascripts/fiona7/task_list_command.js +0 -15
  58. data/app/assets/javascripts/fiona7/task_list_menu_item.js +0 -30
  59. data/app/assets/javascripts/scrivito_patches/ajax.js +0 -225
  60. data/app/assets/javascripts/scrivito_patches/attribute_serializer.js +0 -259
  61. data/app/assets/javascripts/scrivito_patches/binary_utils.js +0 -33
  62. data/app/assets/javascripts/scrivito_patches/cms_rest_api.js +0 -371
  63. data/app/assets/javascripts/scrivito_patches/models/binary_field_element.js +0 -53
  64. data/app/assets/javascripts/scrivito_patches/obj_serializer.js +0 -91
  65. data/lib/fiona7/scrivito_patches/attribute_serializer.rb +0 -37
  66. data/lib/fiona7/scrivito_patches/model_library.rb +0 -19
  67. data/lib/fiona7/scrivito_patches/obj_params_parser.rb +0 -20
@@ -0,0 +1,209 @@
1
+ 'use strict';
2
+
3
+ var _createClass = (function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ('value' in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; })();
4
+
5
+ function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } }
6
+
7
+ (function () {
8
+ var MIN_REQUEST_TIME = 5;
9
+ var DEFAULT_REQUEST_TIMEOUT = 15000;
10
+ var backendEndpoint = undefined;
11
+ var tenant = undefined;
12
+
13
+ scrivito.CmsRestApi = {
14
+ init: function init(endpoint, initTenant) {
15
+ backendEndpoint = endpoint;
16
+ tenant = initTenant;
17
+ },
18
+
19
+ get: function get(path, requestParams) {
20
+ return fetch('GET', path, requestParams);
21
+ },
22
+
23
+ put: function put(path, requestParams) {
24
+ return fetch('PUT', path, requestParams);
25
+ },
26
+
27
+ post: function post(path, requestParams) {
28
+ return fetch('POST', path, requestParams);
29
+ },
30
+
31
+ 'delete': function _delete(path, requestParams) {
32
+ return fetch('DELETE', path, requestParams);
33
+ }
34
+ };
35
+
36
+ var Timer = (function () {
37
+ function Timer() {
38
+ var timeout = arguments.length <= 0 || arguments[0] === undefined ? DEFAULT_REQUEST_TIMEOUT : arguments[0];
39
+
40
+ _classCallCheck(this, Timer);
41
+
42
+ this.timesOutAt = Date.now() + timeout;
43
+ }
44
+
45
+ _createClass(Timer, [{
46
+ key: 'timedOut',
47
+ value: function timedOut() {
48
+ return this.remainingTime() < MIN_REQUEST_TIME;
49
+ }
50
+ }, {
51
+ key: 'remainingTime',
52
+ value: function remainingTime() {
53
+ return Math.max(this.timesOutAt - Date.now(), 0);
54
+ }
55
+ }, {
56
+ key: 'cover',
57
+ value: function cover(time) {
58
+ return time <= this.timesOutAt - MIN_REQUEST_TIME;
59
+ }
60
+ }]);
61
+
62
+ return Timer;
63
+ })();
64
+
65
+ function fetch(method, path, requestParams) {
66
+ return request(method, path, requestParams).then(function (result) {
67
+ if (result && result.task && _.size(result) === 1) {
68
+ return handleTask(result.task);
69
+ }
70
+ return result;
71
+ });
72
+ }
73
+
74
+ function request(method, path, requestParams) {
75
+ var timer = new Timer();
76
+ return retryOnceOnError(timer, method, function () {
77
+ return retryOnRateLimit(timer, function () {
78
+ return scrivito.SessionKeeper.performWithToken(function (token) {
79
+ var ajaxDeferred = ajax(method, path, requestParams, timer.remainingTime(), token);
80
+ return scrivito.Promise.resolve(ajaxDeferred)['catch'](checkAuthorization);
81
+ });
82
+ })['catch'](function (error) {
83
+ return raiseError(error);
84
+ });
85
+ });
86
+ }
87
+
88
+ function retryOnceOnError(timer, method, requestCallback) {
89
+ if (method === 'POST') {
90
+ return requestCallback();
91
+ }
92
+
93
+ return requestCallback()['catch'](function (error) {
94
+ if (!timer.timedOut()) {
95
+ if (error instanceof scrivito.BackendError) {
96
+ return requestCallback();
97
+ }
98
+ if (error instanceof scrivito.NetworkError) {
99
+ return requestCallback();
100
+ }
101
+ }
102
+ throw error;
103
+ });
104
+ }
105
+
106
+ function retryOnRateLimit(timer, requestCallback) {
107
+ var retry = function retry(retryCount) {
108
+ return requestCallback()['catch'](function (error) {
109
+ if (error.status === 429) {
110
+ var timeout = calculateTimeout(error.getResponseHeader('Retry-After'), retryCount);
111
+ if (timer.cover(Date.now() + timeout)) {
112
+ return scrivito.Promise.resolve(scrivito.waitMs(timeout)).then(function () {
113
+ return retry(retryCount + 1);
114
+ });
115
+ }
116
+ throw new scrivito.RateLimitExceededError('rate limit exceeded', 429);
117
+ }
118
+ throw error;
119
+ });
120
+ };
121
+
122
+ return retry(0);
123
+ }
124
+
125
+ function calculateTimeout(retryAfter, retryCount) {
126
+ var calculatedTimeout = Math.pow(2, retryCount) * 0.5 * 1000;
127
+ return Math.max(calculatedTimeout, retryAfter * 1000);
128
+ }
129
+
130
+ function raiseError(error) {
131
+ if (error.status === undefined || !_.isNumber(error.status)) {
132
+ throw error;
133
+ } else if (error.status === 0) {
134
+ throw new scrivito.NetworkError(error.statusText, error.status);
135
+ }
136
+
137
+ var errorBody = parseError(error);
138
+ var specificOutput = errorBody.error;
139
+
140
+ if (error.status === 403) {
141
+ throw new scrivito.AccessDeniedError(specificOutput, error.status, errorBody.code);
142
+ } else if (error.status.toString()[0] === '4' && specificOutput) {
143
+ throw new scrivito.ClientError(specificOutput, error.status, errorBody.code);
144
+ } else if (error.status === 500 && specificOutput) {
145
+ throw new scrivito.BackendError(specificOutput, error.status);
146
+ }
147
+ throw new scrivito.NetworkError(error.responseText, error.status);
148
+ }
149
+
150
+ function checkAuthorization(error) {
151
+ if (error.status === 401) {
152
+ var errorBody = parseError(error);
153
+ var specificOutput = errorBody.error;
154
+ throw new scrivito.UnauthorizedError(specificOutput, error.status, errorBody.code);
155
+ }
156
+ throw error;
157
+ }
158
+
159
+ function parseError(error) {
160
+ try {
161
+ return JSON.parse(error.responseText);
162
+ } catch (err) {
163
+ if (err instanceof SyntaxError) {
164
+ throw new scrivito.NetworkError(error.responseText, error.status);
165
+ }
166
+ throw err;
167
+ }
168
+ }
169
+
170
+ function prepareAjaxParams(method, path) {
171
+ var requestParams = arguments.length <= 2 || arguments[2] === undefined ? {} : arguments[2];
172
+
173
+ var ajaxParams = {
174
+ path: path,
175
+ verb: method,
176
+ params: requestParams
177
+ };
178
+
179
+ return ajaxParams;
180
+ }
181
+
182
+ function ajax(method, path, requestParams, timeout, token) {
183
+ // -- PATCH BEGINS HERE --
184
+ var url = '/_f7/tenants/' + tenant + '/perform';
185
+ // -- PATCH ENDS HERE --
186
+ var ajaxParams = prepareAjaxParams(method, path, requestParams);
187
+
188
+ // -- PATCH BEGINS HERE --
189
+ return scrivito.fetch(method, url, ajaxParams, timeout, null);
190
+ // -- PATCH ENDS HERE --
191
+ }
192
+
193
+ function handleTask(task) {
194
+ switch (task.status) {
195
+ case 'success':
196
+ return task.result;
197
+ case 'error':
198
+ throw new scrivito.ClientError(task.message, undefined, task.code);
199
+ case 'open':
200
+ return scrivito.wait(2).then(function () {
201
+ return request('GET', 'tasks/' + task.id).then(function (result) {
202
+ return handleTask(result);
203
+ });
204
+ });
205
+ default:
206
+ throw new scrivito.ScrivitoError('Invalid task response (unknown status)');
207
+ }
208
+ }
209
+ })();
@@ -0,0 +1,325 @@
1
+ "use strict";
2
+
3
+ function _toConsumableArray(arr) { if (Array.isArray(arr)) { for (var i = 0, arr2 = Array(arr.length); i < arr.length; i++) arr2[i] = arr[i]; return arr2; } else { return Array.from(arr); } }
4
+
5
+ (function () {
6
+ scrivito.Sidebar.WorkspacesPanel = scrivito.createReactClass({
7
+ propTypes: {
8
+ isActive: React.PropTypes.bool.isRequired
9
+ },
10
+
11
+ render: function render() {
12
+ if (!this.props.isActive) {
13
+ return null;
14
+ }
15
+
16
+ return React.createElement(
17
+ ReactCustomScrollbars.Scrollbars,
18
+ {
19
+ className: "scrivito_second_level_content scrivito_workspaces_panel scrivito_dark" },
20
+ React.createElement(CurrentWorkspaceGroup, null),
21
+ React.createElement(OtherWorkspacesGroup, null)
22
+ );
23
+ }
24
+ });
25
+
26
+ var GeneralWorkspacesGroup = scrivito.createReactClass({
27
+ render: function render() {
28
+ return React.createElement(
29
+ "div",
30
+ { className: "scrivito_general_workspaces_group" },
31
+ React.createElement(
32
+ "div",
33
+ { className: "scrivito_sidebar_separator" },
34
+ React.createElement(
35
+ "span",
36
+ null,
37
+ scrivito.t('sidebar.workspaces_panel.general_workspaces_group.title')
38
+ )
39
+ ),
40
+ React.createElement(
41
+ "ul",
42
+ { className: "scrivito_sidebar_action" },
43
+ React.createElement(CreateWorkspaceButton, null),
44
+ React.createElement(PublishHistoryButton, null)
45
+ )
46
+ );
47
+ }
48
+ });
49
+
50
+ var CurrentWorkspaceGroup = scrivito.createReactClass({
51
+ render: function render() {
52
+ var currentWorkspace = scrivito.Workspace.selected;
53
+
54
+ var currentWorkspaceButtons = undefined;
55
+
56
+ if (currentWorkspace.isEditable()) {
57
+ currentWorkspaceButtons = React.createElement(
58
+ "ul",
59
+ { className: "scrivito_sidebar_action" },
60
+ React.createElement(TasksButton, { workspace: currentWorkspace }),
61
+ React.createElement(ChangesButton, { workspace: currentWorkspace })
62
+ );
63
+ }
64
+
65
+ return React.createElement(
66
+ "div",
67
+ { className: "scrivito_current_workspace_group" },
68
+ React.createElement(
69
+ "div",
70
+ { className: "scrivito_sidebar_separator" },
71
+ React.createElement(
72
+ "span",
73
+ null,
74
+ scrivito.t('sidebar.workspaces_panel.current_workspace_group.title')
75
+ )
76
+ ),
77
+ React.createElement(scrivito.Sidebar.WorkspaceList, { workspaces: [currentWorkspace], isActive: true }),
78
+ currentWorkspaceButtons
79
+ );
80
+ }
81
+ });
82
+
83
+ var OtherWorkspacesGroup = scrivito.createReactClass({
84
+ render: function render() {
85
+ return React.createElement(
86
+ "div",
87
+ { className: "scrivito_other_workspaces_group" },
88
+ React.createElement(
89
+ "div",
90
+ { className: "scrivito_sidebar_separator" },
91
+ React.createElement(
92
+ "span",
93
+ null,
94
+ scrivito.t('sidebar.workspaces_panel.other_workspaces_group.title')
95
+ )
96
+ ),
97
+ React.createElement(OtherWorkspacesList, null)
98
+ );
99
+ }
100
+ });
101
+
102
+ var OtherWorkspacesList = scrivito.createReactClass({
103
+ shouldRenderLoader: true,
104
+
105
+ render: function render() {
106
+ var currentWorkspace = scrivito.Workspace.selected;
107
+
108
+ var otherWorkspaces = currentWorkspace.otherEditableWorkspaces;
109
+
110
+ if (currentWorkspace.isEditable()) {
111
+ otherWorkspaces = [scrivito.Workspace.published].concat(_toConsumableArray(otherWorkspaces));
112
+ }
113
+
114
+ return React.createElement(scrivito.Sidebar.WorkspaceList, { workspaces: otherWorkspaces });
115
+ }
116
+ });
117
+
118
+ var CreateWorkspaceButton = scrivito.createReactClass({
119
+ render: function render() {
120
+ return React.createElement(
121
+ "li",
122
+ { className: this._buttonClassName(), title: this._buttonHint(),
123
+ onClick: this._onClick },
124
+ React.createElement("i", { className: "scrivito_icon scrivito_icon_inv_plus scrivito_green" }),
125
+ React.createElement(
126
+ "span",
127
+ null,
128
+ scrivito.t('sidebar.workspaces_panel.create_workspace_button.title')
129
+ )
130
+ );
131
+ },
132
+
133
+ _onClick: function _onClick(e) {
134
+ if (this._isEnabled()) {
135
+ scrivito.create_workspace_command().execute();
136
+ }
137
+
138
+ e.stopPropagation();
139
+ },
140
+
141
+ _buttonClassName: function _buttonClassName() {
142
+ var className = 'scrivito_create_workspace_button scrivito_sidebar_action_item';
143
+
144
+ if (!this._isEnabled()) {
145
+ className += ' scrivito_disabled';
146
+ }
147
+
148
+ return className;
149
+ },
150
+
151
+ _buttonHint: function _buttonHint() {
152
+ if (!this._isEnabled()) {
153
+ return scrivito.t('sidebar.workspaces_panel.create_workspace_button.is_disabled');
154
+ }
155
+
156
+ return scrivito.t('sidebar.workspaces_panel.create_workspace_button.hint');
157
+ },
158
+
159
+ _isEnabled: function _isEnabled() {
160
+ return scrivito.User.current.can('create');
161
+ }
162
+ });
163
+
164
+ var PublishHistoryButton = scrivito.createReactClass({
165
+ render: function render() {
166
+ return React.createElement(
167
+ "li",
168
+ { className: "scrivito_publish_history_button scrivito_sidebar_action_item",
169
+ title: scrivito.t('sidebar.workspaces_panel.publish_history_button.hint'),
170
+ onClick: this._onClick },
171
+ React.createElement("i", { className: "scrivito_icon scrivito_icon_history" }),
172
+ React.createElement(
173
+ "span",
174
+ null,
175
+ scrivito.t('sidebar.workspaces_panel.publish_history_button.title')
176
+ )
177
+ );
178
+ },
179
+
180
+ _onClick: function _onClick(e) {
181
+ scrivito.PublishHistoryDialog.open();
182
+ e.stopPropagation();
183
+ }
184
+ });
185
+
186
+ var ChangesButton = createWorkspaceButtonClass({
187
+ name: 'changes',
188
+ icon: 'edited',
189
+ verb: 'read',
190
+ onClick: function onClick() {
191
+ scrivito.openWorkspaceChanges();
192
+ }
193
+ });
194
+
195
+ var PublishButton = createWorkspaceButtonClass({
196
+ name: 'publish',
197
+ verb: 'publish',
198
+ color: 'green',
199
+
200
+ onClick: function onClick(workspace) {
201
+ var publisher = new scrivito.WorkspacePublisher(workspace);
202
+ scrivito.publishWorkspace(workspace, publisher);
203
+ }
204
+ });
205
+
206
+ /* PATCH BEGINS HERE */
207
+ var TasksButton = createWorkspaceButtonClass({
208
+ name: 'tasks',
209
+ icon: 'clipboard',
210
+ verb: 'read',
211
+ onClick: function onClick() {
212
+ scrivito.task_list_dialog.open();
213
+ }
214
+ });
215
+ /* PATCH ENDS HERE */
216
+
217
+ var SettingsButton = createWorkspaceButtonClass({
218
+ name: 'settings',
219
+ verb: 'invite_to',
220
+ onClick: function onClick(workspace) {
221
+ scrivito.openWorkspaceSettings(workspace);
222
+ }
223
+ });
224
+
225
+ var RebaseButton = createWorkspaceButtonClass({
226
+ name: 'rebase',
227
+ icon: 'refresh',
228
+ verb: 'write',
229
+
230
+ isButtonDisabled: function isButtonDisabled(workspace) {
231
+ return workspace.isAutoUpdate();
232
+ },
233
+
234
+ onClick: function onClick(workspace) {
235
+ var legacyWorkspace = scrivito.legacy_workspace.fromWorkspace(workspace);
236
+ scrivito.rebase_workspace_command(legacyWorkspace).execute();
237
+ }
238
+ });
239
+
240
+ function createWorkspaceButtonClass(_ref) {
241
+ var name = _ref.name;
242
+ var icon = _ref.icon;
243
+ var color = _ref.color;
244
+ var verb = _ref.verb;
245
+ var isButtonDisabled = _ref.isButtonDisabled;
246
+ var onClick = _ref.onClick;
247
+
248
+ return scrivito.createReactClass({
249
+ propTypes: {
250
+ workspace: React.PropTypes.instanceOf(scrivito.Workspace).isRequired
251
+ },
252
+
253
+ render: function render() {
254
+ if (isButtonDisabled && isButtonDisabled(this.props.workspace)) {
255
+ return null;
256
+ }
257
+
258
+ return React.createElement(
259
+ "li",
260
+ { className: this._buttonClassName(),
261
+ title: this._title(),
262
+ onClick: this._onClick },
263
+ React.createElement("i", { className: this._iconClassName() }),
264
+ React.createElement(
265
+ "span",
266
+ null,
267
+ scrivito.t("sidebar.workspaces_panel." + name + "_button.title")
268
+ )
269
+ );
270
+ },
271
+
272
+ _buttonClassName: function _buttonClassName() {
273
+ var className = "scrivito_sidebar_action_item scrivito_" + name + "_button";
274
+
275
+ if (!this._canAccessWorkspace()) {
276
+ className += ' scrivito_disabled';
277
+ }
278
+
279
+ return className;
280
+ },
281
+
282
+ _iconClassName: function _iconClassName() {
283
+ var className = "scrivito_icon scrivito_icon_" + (icon || name);
284
+
285
+ if (color) {
286
+ className += " scrivito_" + color;
287
+ }
288
+
289
+ return className;
290
+ },
291
+
292
+ _title: function _title() {
293
+ var localesPrefix = "sidebar.workspaces_panel." + name + "_button";
294
+
295
+ if (!this._canAccessWorkspace()) {
296
+ return scrivito.t(localesPrefix + ".is_forbidden");
297
+ }
298
+
299
+ return scrivito.t(localesPrefix + ".hint");
300
+ },
301
+
302
+ _canAccessWorkspace: function _canAccessWorkspace() {
303
+ return scrivito.User.current.can(verb, this.props.workspace);
304
+ },
305
+
306
+ _onClick: function _onClick(e) {
307
+ if (this._canAccessWorkspace()) {
308
+ onClick(this.props.workspace);
309
+ }
310
+
311
+ e.stopPropagation();
312
+ }
313
+ });
314
+ }
315
+ })();
316
+ /*
317
+ PATCH BEGINS HERE
318
+ <GeneralWorkspacesGroup />
319
+ PATCH ENDS HERE
320
+ */ /* PATCH BEINGS HERE */ /*
321
+ <PublishButton workspace={currentWorkspace} />
322
+ <ChangesButton workspace={currentWorkspace }/>
323
+ <SettingsButton workspace={currentWorkspace} />
324
+ <RebaseButton workspace={currentWorkspace} />
325
+ */ /* PATCH ENDS HERE */