diff --git a/app/controllers/users/settings/user_settings_controller.rb b/app/controllers/users/settings/user_settings_controller.rb
index ec56c576a..2b106bc17 100644
--- a/app/controllers/users/settings/user_settings_controller.rb
+++ b/app/controllers/users/settings/user_settings_controller.rb
@@ -14,7 +14,14 @@ module Users
key = setting[:key]
data = setting[:data]
- current_user.settings[key] = data if Extends::WHITELISTED_USER_SETTINGS.include?(key.to_s)
+ next unless Extends::WHITELISTED_USER_SETTINGS.include?(key.to_s)
+
+ case key.to_s
+ when 'task_step_states'
+ update_task_step_states(data)
+ else
+ current_user.settings[key] = data
+ end
end
if current_user.save
@@ -24,6 +31,22 @@ module Users
status: :unprocessable_entity
end
end
+
+ private
+
+ def update_task_step_states(task_step_states_data)
+ current_states = current_user.settings.fetch('task_step_states', {})
+
+ task_step_states_data.each do |step_id, collapsed|
+ if collapsed
+ current_states[step_id] = true
+ else
+ current_states.delete(step_id)
+ end
+ end
+
+ current_user.settings['task_step_states'] = current_states
+ end
end
end
end
diff --git a/app/javascript/vue/protocol/container.vue b/app/javascript/vue/protocol/container.vue
index 0d43309d0..30a1e9cb5 100644
--- a/app/javascript/vue/protocol/container.vue
+++ b/app/javascript/vue/protocol/container.vue
@@ -183,6 +183,7 @@
@step:move_attachment="reloadStep"
@step:drag_enter="dragEnter"
:reorderStepUrl="steps.length > 1 ? urls.reorder_steps_url : null"
+ :userSettingsUrl="userSettingsUrl"
:assignableMyModuleId="protocol.attributes.assignable_my_module_id"
/>
@@ -237,7 +238,7 @@ import ReorderableItemsModal from '../shared/reorderable_items_modal.vue';
import PublishProtocol from './modals/publish_protocol.vue';
import clipboardPasteModal from '../shared/content/attachments/clipboard_paste_modal.vue';
import AssetPasteMixin from '../shared/content/attachments/mixins/paste.js';
-
+import axios from '../../packs/custom_axios';
import UtilsMixin from '../mixins/utils.js';
import stackableHeadersMixin from '../mixins/stackableHeadersMixin';
import moduleNameObserver from '../mixins/moduleNameObserver';
@@ -277,10 +278,12 @@ export default {
reordering: false,
publishing: false,
stepToReload: null,
- activeDragStep: null
+ activeDragStep: null,
+ userSettingsUrl: null
};
},
mounted() {
+ this.userSettingsUrl = document.querySelector('meta[name="user-settings-url"]').getAttribute('content');
$.get(this.protocolUrl, (result) => {
this.protocol = result.data;
this.$nextTick(() => {
@@ -309,9 +312,24 @@ export default {
},
collapseSteps() {
$('.step-container .collapse').collapse('hide');
+ this.updateStepStateSettings(true);
},
expandSteps() {
$('.step-container .collapse').collapse('show');
+ this.updateStepStateSettings(false);
+ },
+ updateStepStateSettings(newState) {
+ const updatedData = this.steps.reduce((acc, currentStep) => {
+ acc[currentStep.id] = newState;
+ return acc;
+ }, {});
+
+ const settings = {
+ key: 'task_step_states',
+ data: updatedData
+ };
+
+ axios.put(this.userSettingsUrl, { settings: [settings] });
},
deleteSteps() {
$.post(this.urls.delete_steps_url, () => {
diff --git a/app/javascript/vue/protocol/step.vue b/app/javascript/vue/protocol/step.vue
index 6806bba67..448e93abf 100644
--- a/app/javascript/vue/protocol/step.vue
+++ b/app/javascript/vue/protocol/step.vue
@@ -183,6 +183,9 @@
reorderStepUrl: {
required: false
},
+ userSettingsUrl: {
+ required: false
+ },
assignableMyModuleId: {
type: Number,
required: false
@@ -249,6 +252,15 @@
}
},
mounted() {
+ this.$nextTick(() => {
+ const stepId = `#stepBody${this.step.id}`;
+ this.isCollapsed = this.step.attributes.collapsed;
+ if (this.isCollapsed) {
+ $(stepId).collapse('hide');
+ } else {
+ $(stepId).collapse('show');
+ }
+ });
$(this.$refs.comments).data('closeCallback', this.closeCommentsSidebar);
$(this.$refs.comments).data('openCallback', this.closeCommentsSidebar);
$(this.$refs.actionsDropdownButton).on('shown.bs.dropdown hidden.bs.dropdown', () => {
@@ -402,6 +414,13 @@
},
toggleCollapsed() {
this.isCollapsed = !this.isCollapsed;
+
+ const settings = {
+ key: 'task_step_states',
+ data: { [this.step.id]: this.isCollapsed }
+ };
+
+ axios.put(this.userSettingsUrl, { settings: [settings] });
},
showDeleteModal() {
this.confirmingDelete = true;
diff --git a/app/serializers/step_serializer.rb b/app/serializers/step_serializer.rb
index 6da21dcbb..91851d85b 100644
--- a/app/serializers/step_serializer.rb
+++ b/app/serializers/step_serializer.rb
@@ -10,7 +10,12 @@ class StepSerializer < ActiveModel::Serializer
attributes :name, :position, :completed, :attachments_manageble, :urls, :assets_view_mode,
:marvinjs_enabled, :marvinjs_context, :created_by, :created_at, :assets_order,
:wopi_enabled, :wopi_context, :comments_count, :unseen_comments, :storage_limit,
- :type, :open_vector_editor_context
+ :type, :open_vector_editor_context, :collapsed
+
+ def collapsed
+ step_states = @instance_options[:user].settings.fetch('task_step_states', {})
+ step_states[object.id.to_s] == true
+ end
def marvinjs_enabled
MarvinJsService.enabled?
diff --git a/config/initializers/extends.rb b/config/initializers/extends.rb
index b7a391da2..10aab7add 100644
--- a/config/initializers/extends.rb
+++ b/config/initializers/extends.rb
@@ -650,6 +650,7 @@ class Extends
ReportTemplates_archived_state
Repositories_active_state
Repositories_archived_state
+ task_step_states
).freeze
end