Skip to content
Snippets Groups Projects
Commit a212b194 authored by jan.bednarik's avatar jan.bednarik
Browse files

Clean Redmine 5 with ruby-dev

parent f4154b4b
No related branches found
No related tags found
No related merge requests found
Pipeline #19076 canceled
Showing
with 2 additions and 3088 deletions
[submodule "themes/PurpleMine2"]
path = themes/PurpleMine2
url = https://github.com/mrliptontea/PurpleMine2.git
[submodule "plugins/redmine_pivot_table"]
path = plugins/redmine_pivot_table
url = https://github.com/deecay/redmine_pivot_table.git
[submodule "plugins/issue_charts"]
path = plugins/issue_charts
url = https://github.com/masweetman/issue_charts.git
[submodule "plugins/redmine_zulip"]
path = plugins/redmine_zulip
url = https://github.com/zulip/zulip-redmine-plugin.git
[submodule "plugins/redmine-signals-plugin"]
path = plugins/traffic_lights
url = https://gitlab.pirati.cz/sperling/redmine-signals-plugin.git
[submodule "plugins/redmine_theme_changer"]
path = plugins/redmine_theme_changer
url = https://github.com/haru/redmine_theme_changer.git
[submodule "plugins/redmine_work_time"]
path = plugins/redmine_work_time
url = https://github.com/tkusukawa/redmine_work_time.git
[submodule "plugins/sparkline"]
path = plugins/sparkline
url = https://gitlab.pirati.cz/sperling/redmine-sparkline-plugin.git
FROM redmine:4.2.10-passenger
FROM redmine:5.1.3
MAINTAINER Andrej Ramašeuski <andrej.ramaseuski@pirati.cz>
RUN apt-get update && \
apt-get install -y --no-install-recommends \
build-essential && \
apt-get remove -y libgs9 ghostscript libgs9-common
COPY ./themes/ /usr/src/redmine/public/themes/
COPY ./plugins/ /usr/src/redmine/plugins/
RUN apt update && apt install ruby-dev
gem 'redmine_extensions' unless Dir.exist?(File.expand_path('../../easyproject', __FILE__))
= Easy MindMup
Mind map library compatible with EasyProject and Redmine
\ No newline at end of file
app_dir = File.join(File.dirname(__FILE__), 'app')
lib_dir = File.join(File.dirname(__FILE__), 'lib', 'easy_mindmup')
RedmineExtensions::Reloader.to_prepare do
require 'easy_mindmup/easy_mindmup'
end
class EasyMindmupController < ApplicationController
accept_api_auth :update_layout
before_action :find_project_by_project_id
before_action :authorize
# Save mindmup layout
#
# PUT update_layout
# {
# easy_setting: {
# *_layout: { ... }
# }
# }
#
def update_layout
if params[:easy_setting].is_a?(Hash)
params[:easy_setting].each do |name, value|
next unless name.end_with?('_layout')
next unless value.is_a?(Hash)
# Convert `ActionController::Parameters` to `Hash`
value = value.to_hash
setting = EasySetting.find_or_initialize_by(name: name, project_id: @project.id)
setting.value = value
setting.save
end
end
respond_to do |format|
format.api { render_api_ok }
end
end
private
def authorize
unless User.current.allowed_to?(:edit_project, @project)
return render_403
end
end
end
module EasyMindmupHelper
# def avatar_url_from_avatar(avatar_html)
# start_index = avatar_html.index('src="')
# return '' if start_index.nil?
# start_index += 5
# end_index = avatar_html.index('"', start_index)
# avatar_html[start_index, end_index - start_index]
# end
def mindmup_avatar_url(user)
if defined?(avatar_url)
avatar_url(user)
elsif Setting.gravatar_enabled?
gravatar_url(user.mail.to_s.downcase, size: 64, default: Setting.gravatar_default)
else
''
end
end
end
<div class="mindmup-hotkeys-source" style="display:none">
<h3 class="title"><%= l(:title_shortcuts, :scope => [:easy_mindmup, :hotkeys]) %></h3>
<h1><%= l(:title_key_shortcuts, :scope => [:easy_mindmup, :hotkeys]) %></h1>
<p><%= l(:info_mac_metakey, :scope => [:easy_mindmup, :hotkeys]) %></p>
<table class="table table-striped">
<colgroup><col width="30%"></col><col width="70%"></col></colgroup>
<tbody>
<% l(:keyboard, :scope => [:easy_mindmup, :hotkeys]).each do |group| %>
<tr>
<td colspan="2"><h2><%= group[:title] %></h2></td>
</tr>
<% group[:hotkeys].each do |item| %>
<tr>
<td><%= item[:hotkey] %></td>
<td><%= item[:info] %></td>
</tr>
<% end
end %>
</tbody>
</table>
<h1><%= l(:title_mouse_shortcuts, :scope => [:easy_mindmup, :hotkeys]) %></h1>
<table class="table table-striped">
<colgroup><col width="20%"></col><col width="80%"></col></colgroup>
<% l(:mouse, :scope => [:easy_mindmup, :hotkeys]).each do |item| %>
<tr>
<td><%= item[:action] %></td>
<td><%= item[:gesture] %></td>
</tr>
<% end %>
</table>
</div>
\ No newline at end of file
<% include_calendar_headers_tags %>
<% heads_for_wiki_formatter %>
<% if defined?(EasyExtensions) %>
<%= stylesheet_link_tag('easy_mindmup', :media => 'all') %>
<% else %>
<%= stylesheet_link_tag('generated/easy_mindmup', :plugin => 'easy_mindmup', :media => 'all') %>
<%#= stylesheet_link_tag('easy_mindmup', :plugin => 'easy_mindmup', :media => 'all') %>
<%= stylesheet_link_tag('context_menu', :media => 'all') %>
<% end %>
<%= javascript_include_tag('external', :plugin => 'easy_mindmup') %>
<% if false && defined?(EasyExtensions) %>
<%= javascript_include_tag('easy_wbs', :plugin => 'easy_mindmup') %>
<% else %>
<script type="application/javascript">
window.easyDartLoaders = window.easyDartLoaders || [];
</script>
<%= begin javascript_include_tag(
'mindmup/mapjs',
'mindmup/clipboard',
'mindmup/content',
'mindmup/dom-map-view',
'mindmup/dom-map-widget',
'mindmup/hammer-draggable',
'mindmup/image-drop-widget',
'mindmup/layout',
#'mindmup/link-edit-widget',
'mindmup/map-model',
'mindmup/map-toolbar-widget',
'mindmup/observable',
'mindmup/url-helper', :plugin => 'easy_mindmup')
end %>
<%= begin javascript_include_tag(
:libs,
:polyfill,
:utils,
:main,
:mapjs_init,
:event_bus,
:redrawer,
:toolbar,
:history,
:data,
:links,
:loader,
# :last_state,
:saver,
:autosave,
:save_progress,
:save_info,
:filter,
:node_patch,
:dom_patch,
:map_model_patch,
:model_classes,
:after_change,
:styles,
:logger,
# :gateway,
# :modals,
:validator,
:storage,
:legend,
:legend_events,
:expand_all,
:print,
:mm_context_menu,
:layout_patch,
:content_patch,
:links,
:link_edit_widget, :plugin => 'easy_mindmup')
end %>
<% end %>
<% if defined?(EasyExtensions)
include_front_end_commons if respond_to? :include_front_end_commons
end %>
<script type="text/javascript">
window.easyMindMupSetting = <%= {
easyRedmine: EasyMindmup.easy_extensions?,
rootID: @project.id,
apiKey: User.current.api_key,
noSave: params[:nosave].present?,
allIcons: false,
paths: {
root: home_path
},
labels: {
free: {
headerNotAvailable: l('easy_mindmup.free.header_not_available'),
buttonUpgrade: l('easy_mindmup.free.button_upgrade')
},
errors: {
warning_delete_node: l('easy_mindmup.warning_delete_node'),
warning_delete_nodes: l('easy_mindmup.warning_delete_nodes')
},
types: {},
gateway: {
multiSuccess: l('easy_mindmup.info_all_saved'),
multiFail: l('easy_mindmup.info_any_failed'),
PUTfail: l('easy_mindmup.error_update'),
POSTfail: l('easy_mindmup.error_create'),
DELETEfail: l('easy_mindmup.error_delete'),
response_403: l('easy_mindmup.info_no_permission'),
notProperlySaved: l('easy_mindmup.warning_not_saved')
},
legend: {},
buttons: {
close: l(:button_close),
button_yes: l(:general_text_Yes),
button_no: l(:general_text_No)
},
context: {
expand: l('easy_mindmup.button_expand'),
collapse: l('easy_mindmup.button_collapse'),
goto: l('easy_mindmup.label_go_to'),
rename: l(:button_rename),
editData: l('easy_mindmup.button_edit_data'),
add: l(:button_add),
addChild: l('easy_mindmup.button_add_child'),
addSibling: l('easy_mindmup.button_add_sibling'),
addParent: l('easy_mindmup.button_add_parent'),
remove: l(:button_delete),
},
links: {
},
save_info: {
initial: l('easy_mindmup.save_info.loaded'),
saved: l('easy_mindmup.save_info.saved'),
autosaved: l('easy_mindmup.save_info.autosaved'),
at: l('easy_mindmup.save_info.at')
},
titleNodeChanged: l('easy_mindmup.title_node_changed')
},
templates: {
legendTemplate: %{
{{#filter}}
<div class="mindmup-legend__filter_cont">
<a class="easy-mindmup__icon easy-mindmup__icon--cancel_filter mindmup-legend__filter_cancel_icon"></a>
<a class="easy-mindmup__icon easy-mindmup__icon--filter mindmup-legend__filter_icon"></a>
</div>
{{/filter}}
{{#items}}
{{{.}}}
{{/items}}
<a href="javascript:void(0)" class="mindmup-legend-used mindmup-legend-used-used--{{active}}">#{l('easy_mindmup.label_show_unused')}</a>
<a href="javascript:void(0)" class="mindmup-legend-used mindmup-legend-used-all--{{active}}">#{l('easy_mindmup.label_hide_unused')}</a>
<div class="hotkey_link"><a href="javascript:void(0)">#{l('easy_mindmup.button_hotkeys')}</a></div>
},
upgrade: %{
<h3 class="title">#{l('easy_mindmup.free.header_not_available')}</h3>
<p>
{{#filtering}}
#{l('easy_mindmup.free.feature_filtering')}
{{/filtering}}
{{#coloring}}
#{l('easy_mindmup.free.feature_coloring')}
{{/coloring}}
{{#context_menu}}
#{l('easy_mindmup.free.feature_context_menu')}
{{/context_menu}}
{{#dnd_property}}
#{l('easy_mindmup.free.feature_dnd_property')}
{{/dnd_property}}
{{text}}
</p>
<a id="upgrade_link" style="display:none" href="{{href}}">link</a>
},
reloadErrors: %{
{{#.}}
<li>
{{#isProject}}#{l(:label_project)}{{/isProject}}
{{^isProject}}#{l(:label_issue)}{{/isProject}}
{{#changed}}
"{{name}}" #{l('easy_mindmup.last_state_modal.message_changed')}
{{/changed}}
{{#moved}}
"{{name}}" #{l('easy_mindmup.last_state_modal.message_moved')}
{{/moved}}
{{#present}}
"{{name}}" #{l('easy_mindmup.last_state_modal.message_present')}
{{/present}}
{{#missing}}
"{{name}}" #{l('easy_mindmup.last_state_modal.message_missing')}
{{/missing}}
</li>
{{/.}}
},
lastStateModal: %{
<h3 class="title">#{l('easy_mindmup.last_state_modal.title')}</h3>
<h4>#{l('easy_mindmup.last_state_modal.label_differencies')}:</h4>
<ul class="mindmup-last-modal-diffs">
{{{differences}}}
</ul>
<p>#{l('easy_mindmup.last_state_modal.text_reload_appeal')}</p>
},
storedModal: %{
<h3 class="title">#{l('easy_mindmup.stored_modal.title')}</h3>
<p>#{l('easy_mindmup.stored_modal.text_load_appeal')}</p>
<button id="stored_state_modal_local">#{l('easy_mindmup.stored_modal.button_local')}</button>
<button id="stored_state_modal_server">#{l('easy_mindmup.stored_modal.button_server')}</button>
},
saveProgressModal: %{
<div class="mindmup-progress-modal">
<div class="mindmup-progress-title"><h3>#{l('easy_mindmup.label_save_progress')}</h3></div>
<div class="mindmup-progress-cont">
<div class="mindmup-progress-bar">
</div>
</div>
</div>
}
}
}.to_json.html_safe %>
$(document).ready(function(){
$("p.nodata").remove()
})
</script>
File deleted
File deleted
Source diff could not be displayed: it is too large. Options to address this: view the blob.
File deleted
File deleted
File deleted
plugins/easy_mindmup/assets/images/person.gif

875 B

(function () {
/**
* Class responsible for all callbacks after any change in model
* @param {MindMup} ysy
* @constructor
*/
function AfterChange(ysy) {
this.ysy = ysy;
this.init();
}
AfterChange.prototype.init = function () {
var self = this;
var executeByEvent = function (method, args) {
if (!self[method]) return;
return self[method].apply(self, args);
};
this.ysy.eventBus.register("TreeLoaded", /** @param {RootIdea} idea*/function (idea) {
idea.addEventListener('changed', function (method, args) {
if (method === "batch") {
if (args && args.length) {
for (var i = 0; i < args.length; i++) {
var arg = args[i];
if (arg && arg.length) {
executeByEvent(arg[0], arg.slice(1));
}
}
}
} else {
executeByEvent(method, args);
}
}, 5);
});
};
AfterChange.prototype.removeSubIdea = function (id) {
var node = this.ysy.getLayoutNode(id);
if (!node) return;
var saver = this.ysy.saver;
if (saver.deleteStack) {
saver.deleteStack.push(new window.easyMindMupClasses.ModelEntity().extend(node));
}
};
AfterChange.prototype.paste = function (parentIdeaId, jsonToPaste, newIdeaId) {
this._upgradeToModelEntity(newIdeaId);
};
AfterChange.prototype.insertIntermediate = function (inFrontOfIdeaId, title, newIdeaId) {
var idea = this._upgradeToModelEntity(newIdeaId);
idea.attr.isFresh = true;
};
AfterChange.prototype.addSubIdea = function (parentId, ideaTitle, ideaId) {
var idea = this._upgradeToModelEntity(ideaId);
idea.attr.isFresh = true;
};
/**
* Function, which converts Object generated by MindMup component into ModelEntity
* @param {number} ideaId
* @private
*/
AfterChange.prototype._upgradeToModelEntity = function (ideaId) {
/** @type {MindMup} */
var ysy = this.ysy;
// var rootIdea = ysy.idea;
var idea = ysy.util.findWhere(ysy.idea, function (/** @type {ModelEntity} */ node) {
return node.id === ideaId;
});
return ysy.upgradeToModelEntity(idea);
};
window.easyMindMupClasses.AfterChange = AfterChange;
})();
(function () {
/**
* Autosave feature - there are three phases - long, render and short
* 'hidden' period is there for off-screen detection to prevent saving in background
* In 'short' period, any user action triggers Save.
*
* @param {MindMup} ysy
* @constructor
*/
function Autosave(ysy) {
this.phase = null;
this.ysy = ysy;
this.shortTimeout = 0;
this.longTimeout = 0;
this.init();
}
Autosave.prototype.longPeriod = 10 * 60 * 1000;
Autosave.prototype.shortPeriod = 2 * 60 * 1000;
// Autosave.prototype.longPeriod = 3 * 1000;
// Autosave.prototype.shortPeriod = 2 * 1000;
Autosave.prototype.init = function () {
var self = this;
var ysy = this.ysy;
var testing = false;
/** called when change in mindMap is detected and at the end of short period */
var changeWatcher = function () {
if (self.phase !== 'short') return;
// probably unnecessary, but can prevent multiple firing
ysy.idea.removeEventListener('changed', self.changeWatcher);
if (testing) {
ysy.log.debug(new Date().toISOString() + " saving", "autosave");
startLongPhase(); // "TreeLoaded" event already calls startLongPhase()
} else {
ysy.saver.save(true);
}
};
self.changeWatcher = changeWatcher;
var startShortPhase = function () {
if (self.phase === 'short') return;
if (self.longTimeout) {
window.clearTimeout(self.longTimeout);
self.longTimeout = 0;
}
self.phase = 'short';
ysy.log.debug("short period", "autosave");
ysy.idea.removeEventListener('changed', changeWatcher);
ysy.idea.addEventListener('changed', changeWatcher);
self.shortTimeout = setTimeout(changeWatcher, self.shortPeriod);
};
var userReturned = function () {
document.removeEventListener("visibilitychange", userReturned);
startShortPhase();
};
var startHiddenPhase = function () {
if (document.hidden !== true) return startShortPhase();
self.phase = 'hidden';
ysy.log.debug("hidden period", "autosave");
document.addEventListener("visibilitychange", userReturned);
};
var startLongPhase = function () {
if (self.shortTimeout) {
window.clearTimeout(self.shortTimeout);
self.shortTimeout = 0;
}
if (self.longTimeout) {
window.clearTimeout(self.longTimeout);
}
self.phase = 'long';
ysy.log.debug("long period", "autosave");
self.longTimeout = setTimeout(startHiddenPhase, self.longPeriod);
};
ysy.eventBus.register("IdeaConstructed", function () {
startLongPhase();
});
};
window.easyMindMupClasses.Autosave = Autosave;
})();
/**
* Created by hosekp on 11/8/16.
*/
(function () {
/**
*
* @param {MindMup} ysy
* @constructor
*/
function LastStateChecker(ysy) {
this.ysy = ysy;
}
/** @type {Array.<String>} */
LastStateChecker.prototype.lastStateKeys = null;
LastStateChecker.prototype.getDiffMessages = function (diff, idea, isOld, constructs) {
if (diff && diff.attr && diff.attr.data) {
var dataDiff = diff.attr.data;
var dataKeys = _.intersection(_.keys(dataDiff), this.lastStateKeys);
if (dataKeys.length) {
var changedKeys = [];
var changedValues = {};
for (var i = 0; i < dataKeys.length; i++) {
var key = dataKeys[i];
changedKeys.push(key);
changedValues[key] = dataDiff[key];
// subMessages.push(key + ": " + oldDataDiff[key] + " => " + newDataDiff[key]);
}
var id = idea.attr.data.id;
if (!constructs[id]) {
constructs[id] = {
isProject: idea.attr.isProject,
name: idea.title,
changed: true
}
}
if (constructs[id].changedKeys) {
constructs[id].changedKeys = _.uniq(constructs[id].changedKeys.concat(changedKeys));
} else {
constructs[id].changedKeys = changedKeys;
}
if (isOld) {
constructs[id].oldValues = changedValues;
} else {
constructs[id].newValues = changedValues;
}
}
}
if (diff.ideas) {
var ideasDiff = diff.ideas;
dataKeys = _.keys(ideasDiff);
for (i = 0; i < dataKeys.length; i++) {
var rank = dataKeys[i];
var child = ideasDiff[rank];
if (child.id) {
id = this.ysy.getData(child).id;
if (!constructs[id]) {
constructs[id] = {
entityType: child.attr.entityType,
name: child.title
}
}
if (isOld) {
constructs[id].fromId = idea.attr.data.id;
constructs[id].from = idea.title;
} else {
constructs[id].toId = idea.attr.data.id;
constructs[id].to = idea.title;
}
} else {
this.getDiffMessages(ideasDiff[rank], idea.ideas[rank], isOld, constructs);
}
}
}
};
LastStateChecker.prototype.processLastStateMessages = function (constructs) {
var ids = _.keys(constructs);
var messages = [];
for (var i = 0; i < ids.length; i++) {
var id = ids[i];
var construct = constructs[id];
var message;
if (construct.changedKeys) {
if (construct.from || construct.to) {
message = _.extend({}, construct);
} else {
message = construct;
}
if (!construct.oldValues) construct.oldValues = {};
if (!construct.newValues) construct.newValues = {};
var changes = [];
for (var j = 0; j < construct.changedKeys.length; j++) {
var key = construct.changedKeys[j];
changes.push(key + ": " + construct.oldValues[key] + " => " + construct.newValues[key]);
}
message.changes = changes;
messages.push(message);
}
if (construct.from || construct.to) {
construct.missing = construct.from && !construct.to;
construct.present = !construct.from && construct.to;
construct.moved = construct.from && construct.to;
messages.push(construct);
}
}
return messages;
};
LastStateChecker.prototype.prepareLastStateMessages = function (diff, last, initedData) {
if (this.lastStateKeys == null)throw "lastStateKeys is not defined";
if (!diff) return false;
if (!last) return false;
var constructs = {};
this.getDiffMessages(diff.oldDiff, last, true, constructs);
this.getDiffMessages(diff.newDiff, initedData, false, constructs);
var messagePacks = this.processLastStateMessages(constructs);
if (messagePacks.length === 0) return false;
var template = this.ysy.settings.templates.reloadErrors;
var errorsHtml = Mustache.render(template, messagePacks);
this.ysy.util.showMessage(errorsHtml, "warning");
// this.openLastStateModal(errorsHtml, initedData);
return true;
};
/**
*
* @param {RootIdea} last
* @param {RootIdea} serverState
*/
LastStateChecker.prototype.openStoredModal = function (last, serverState) {
var $target = this.ysy.util.getModal("form-modal", "50%");
//var template = ysy.settings.templates.lastStateModal;
var self = this;
var template = self.ysy.settings.templates.storedModal;
//var obj = $.extend({}, ysy.view.getLabel("reloadModal"),{errors:errors});
//var rendered = Mustache.render(template, {});
$target.html(template);
var labels = {};
$target.find("button").each(function(){
labels[this.id]=$(this).text();
}).remove();
var loadServerIdea = function () {
self.ysy.setIdea(serverState);
$target.dialog("close");
};
showModal("form-modal");
$target.dialog({
buttons: [
{
id: "last_state_modal_local",
text: labels["last_state_modal_local"],
class: "wbs-last-modal-button button-1",
click: function () {
$target.dialog("close");
self.ysy.setIdea(MAPJS.content(last));
}
},
{
id: "last_state_modal_server",
text: labels["last_state_modal_server"],
class: "wbs-last-modal-button button-2",
click: loadServerIdea
}
]
})
.on('dialogclose', loadServerIdea);
$("#last_state_modal_yes").focus();
};
window.easyMindMupClasses.LastStateChecker = LastStateChecker;
})();
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment