#1: Need save and restore abilities

This commit is contained in:
Anton Argirov 2015-05-25 16:57:02 +06:00
parent fc6b11c953
commit f336a2c244
13 changed files with 117 additions and 30 deletions

View File

@ -2,7 +2,7 @@ class CustomWorkflowsController < ApplicationController
layout 'admin'
before_filter :require_admin
before_filter :find_workflow, :only => [:show, :edit, :update, :destroy]
before_filter :find_workflow, :only => [:show, :edit, :update, :destroy, :export]
def index
@workflows = CustomWorkflow.includes(:projects).all
@ -11,6 +11,10 @@ class CustomWorkflowsController < ApplicationController
end
end
def export
send_data @workflow.export_as_xml, :filename => @workflow.name + '.xml', :type => :xml
end
def show
respond_to do |format|
format.html { redirect_to edit_custom_workflow_path }
@ -22,16 +26,36 @@ class CustomWorkflowsController < ApplicationController
def new
@workflow = CustomWorkflow.new
@workflow.author = cookies[:custom_workflows_author]
respond_to do |format|
format.html
end
end
def import
xml = params[:file].read
begin
@workflow = CustomWorkflow.import_from_xml(xml)
if @workflow.save
flash[:notice] = l(:notice_successful_import)
else
flash[:error] = @workflow.errors.full_messages.to_sentence
end
rescue Exception => e
Rails.logger.warn "Workflow import error: #{e.message}\n #{e.backtrace.join("\n ")}"
flash[:error] = l(:error_failed_import)
end
respond_to do |format|
format.html { redirect_to(custom_workflows_path) }
end
end
def create
@workflow = CustomWorkflow.new(params[:custom_workflow])
respond_to do |format|
if @workflow.save
flash[:notice] = l(:notice_successful_create)
cookies[:custom_workflows_author] = @workflow.author
format.html { redirect_to(custom_workflows_path) }
else
format.html { render :action => "new" }

View File

@ -1,5 +1,6 @@
class WorkflowError < StandardError
attr_accessor :error
def initialize(message)
@error = message.dup
super message
@ -19,6 +20,14 @@ class CustomWorkflow < ActiveRecord::Base
default_scope { order(:position => :asc) }
scope :for_all, lambda { where(:is_for_all => true) }
class << self
def import_from_xml(xml)
attributes = Hash.from_xml(xml).values.first
attributes.delete('exported_at')
CustomWorkflow.new(attributes)
end
end
def validate_syntax
issue = Issue.new
issue.send :instance_variable_set, :@issue, issue # compatibility with 0.0.1
@ -36,6 +45,12 @@ class CustomWorkflow < ActiveRecord::Base
end
end
def export_as_xml
to_xml :only => [:author, :name, :description, :before_save, :after_save, :created_at] do |xml|
xml.tag! 'exported-at', Time.current.xmlschema
end
end
def <=>(other)
self.position <=> other.position
end

View File

@ -1,12 +1,13 @@
<div class="splitcontent">
<div class="splitcontentleft box">
<p><%= f.text_field :name, :required => true, :size => 50 %></p>
<p><%= f.text_area :description, :cols => 40, :rows => 5 %></p>
<p>
<label><%= f.check_box :is_for_all, :onclick => "checkAndDisable('custom_workflow_enabled_projects', this.checked);", :no_label => true %> <%= l(:field_enabled_for_all_projects) %></label>
</p>
<div class="splitcontentleft">
<div class="box tabular">
<p><%= f.text_field :name, :required => true, :size => 50 %></p>
<p><%= f.text_field :author, :size => 50, :label => :field_custom_workflow_author %>
<em class="info"><%= l(:text_custom_workflow_author) %></em>
</p>
<p><%= f.text_area :description, :cols => 40, :rows => 5 %></p>
<p><%= f.check_box :is_for_all, :onclick => "checkAndDisable('custom_workflow_enabled_projects', this.checked);", :label => :field_enabled_for_all_projects %></p>
</div>
</div>
<div class="splitcontentright">

View File

@ -2,11 +2,9 @@
<%= error_messages_for 'workflow' %>
<% form = form_for @workflow, :builder => (TabularFormBuilder rescue Redmine::Views::LabelledFormBuilder) do |f| %>
<%= labelled_form_for @workflow do |f| %>
<%= render :partial => 'form', :locals => {:f => f} %>
<%= submit_tag l(:button_save) %>
<% end %>
<%= form if Redmine::VERSION::MAJOR >= 2 %>
<% html_title(l(:label_custom_workflow_plural), @workflow, l(:label_administration)) -%>

View File

@ -1,6 +1,7 @@
<% html_title(l(:label_custom_workflow_plural)) -%>
<div class="contextual">
<%= link_to l(:label_custom_workflow_new), new_custom_workflow_path, :class => 'icon icon-add' %>
<%= link_to l(:label_custom_workflow_import), '#', :class => 'icon icon-import', :onclick => "showModal('import-dialog', '450px'); return false;" %>
<%= link_to l(:label_custom_workflow_new), new_custom_workflow_path, :class => 'icon icon-add' %>
</div>
<h2><%=l(:label_custom_workflow_plural)%></h2>
@ -12,6 +13,7 @@
<tr>
<th><%=l(:field_name)%></th>
<th><%=l(:field_description)%></th>
<th><%=l(:field_author)%></th>
<th><%=l(:label_project_plural)%></th>
<th style="width:15%;"><%= l(:button_sort) %></th>
<th style="width:10%;"></th>
@ -21,8 +23,9 @@
<% @workflows.each do |workflow| %>
<tr class="<%= cycle("odd", "even") %>">
<td class="name"><%= link_to(workflow.name, edit_custom_workflow_path(workflow)) %></td>
<td><%= textilizable(workflow.description) %></td>
<td align="center">
<td class="description"><%= textilizable(workflow.description) %></td>
<td class="author"><%= workflow.author %></td>
<td>
<% if workflow.is_for_all? %>
<%= l(:field_enabled_for_all_projects) %>
<% elsif workflow.projects.empty? %>
@ -33,6 +36,7 @@
</td>
<td align="center"><%= reorder_links("custom_workflow", {:action => 'update', :id => workflow}) %></td>
<td class="buttons">
<%= link_to(l(:label_custom_workflow_export), export_custom_workflow_path(workflow), :class => 'icon icon-export', :method => :get) %>
<%= link_to(l(:button_delete), workflow, :class => 'icon icon-del', :data => {:confirm => l(:text_are_you_sure)}, :confirm => l(:text_are_you_sure), :method => :delete) %>
</td>
</tr>
@ -42,4 +46,22 @@
<% else %>
<p class="nodata"><%= l(:label_no_data) %></p>
<% end %>
</div>
<div id="import-dialog" style="display: none">
<h3 class="title"><%= l(:label_custom_workflow_import) %></h3>
<%= form_tag import_custom_workflow_path, :multipart => true do %>
<p>
<%= l(:field_custom_workflow_file) %>:
</p>
<p>
<%= file_field_tag 'file', :accept => 'application/xml' %>
</p>
<p class="buttons">
<%= submit_tag l(:button_import), :name => nil, :onclick => "hideModal(this);" %>
<%= submit_tag l(:button_cancel), :name => nil, :onclick => "hideModal(this);", :type => 'button' %>
</p>
<% end %>
</div>

View File

@ -1,4 +1,4 @@
<% form = form_for @project do |f| %>
<%= form_for @project do |f| %>
<%= hidden_field_tag :tab, 'custom_workflow' %>
<%= hidden_field_tag 'project[custom_workflow_ids][]', '' %>
<fieldset>
@ -17,4 +17,3 @@
<%= submit_tag l(:button_save) %>
<% end %>
<%= form if Redmine::VERSION::MAJOR >= 2 %>

BIN
assets/images/export.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 265 B

BIN
assets/images/import.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 279 B

View File

@ -6,6 +6,10 @@ table.list.custom-workflows td {
vertical-align: middle;
}
table.list.custom-workflows td.description {
text-align: left;
}
#custom_workflow_description, #custom_workflow_name {
width: 98%;
}
@ -19,3 +23,6 @@ table.list.custom-workflows td {
max-height: 200px;
overflow-y: auto;
}
.icon-export { background-image: url(../images/export.png); }
.icon-import { background-image: url(../images/import.png); }

View File

@ -1,20 +1,29 @@
en:
project_module_custom_workflows_module: "Custom workflows"
permission_manage_project_workflow: "Manage project custom workflows"
label_custom_workflow: "Custom workflows"
label_custom_workflow_plural: "Custom workflows"
label_custom_workflow_new: "Create a custom workflow"
label_workflow_scripts: "Workflow scripts"
label_enabled_projects: "Enabled for project(s)"
label_custom_workflow_export: "Export"
label_custom_workflow_import: "Import workflow"
button_import: "Import"
field_after_save: "Workflow script executable after saving the issue"
field_before_save: "Workflow script executable before saving the issue"
field_is_enabled: "Enabled"
field_enabled_for_all_projects: "Enabled for all projects"
field_custom_workflow_author: "Custom workflow's author"
field_custom_workflow_file: "Select the XML file previously exported process"
field_custom_workflow:
script: "Workflow script"
notice_successful_import: "Custom workflow has successfully imported"
error_failed_import: "Error importing custom workflow (unknown format? please see log)"
activerecord:
errors:
messages:
@ -26,4 +35,5 @@ en:
text_custom_workflow_before_save_note: You can change properties of the issues here. Do not create or update related issues in this script. To finish with error, use raise WorkflowError, "Message to user".
text_custom_workflow_after_save_note: You can update or create related issues here. Note that this script will be also executed for the newly created issues. So make appropriate checks to prevent infinite recursion.
text_custom_workflow_general_note: Both scripts are executed in the context of the issue like ordinary before_save and after_save callbacks. So use methods and properties of the issue directly (or through "self"). Instance variables (@variable) are also allowed and may be used if needed.
text_no_enabled_projects: No projects
text_no_enabled_projects: No projects
text_custom_workflow_author: Will be included in exported XML

View File

@ -1,20 +1,29 @@
ru:
project_module_custom_workflows_module: "Пользовательские рабочие процессы"
permission_manage_project_workflow: "Управление пользовательскими рабочими процессами в проекте"
label_custom_workflow: "Пользовательский рабочий процесс"
label_custom_workflow_plural: "Пользовательские рабочие процессы"
label_custom_workflow_new: "Новый процесс"
label_workflow_scripts: "Сценарии"
label_enabled_projects: "Разрешен в проектах"
label_custom_workflow_export: "Экспорт"
label_custom_workflow_import: "Импорт процесса"
button_import: "Импортировать"
field_after_save: "Сценарий выполняемый после сохранения задачи"
field_before_save: "Сценарий выполняемый перед сохранением задачи"
field_is_enabled: "Разрешено"
field_enabled_for_all_projects: "Разрешен для всех проектов"
field_custom_workflow_author: "Автор рабочего процесса"
field_custom_workflow_file: "Выберите XML файл ранее экспортированного процесса"
field_custom_workflow:
script: "Сценарий"
notice_successful_import: "Рабочий процесс успешно импортирован"
error_failed_import: "Ошибка импорта рабочего процесса (неверный формат? смотри журнал)"
activerecord:
errors:
messages:
@ -27,3 +36,4 @@ ru:
text_custom_workflow_after_save_note: Вы можете обновлять и создавать задачи (в том числе и связанные задачи) здесь. Обратите внимание, что данный сценарий будет также выполняться и для вновь создаваемых задач. Поэтому используйте дополнительные проверки, чтобы избежать бесконечной рекурсии.
text_custom_workflow_general_note: Оба сценария исполняются в контексте задачи, как и обычные обратные вызовы before_save и after_save. Поэтому используйте методы и свойства задачи напрямую или через ключевое слово self.
text_no_enabled_projects: Нет проектов
text_custom_workflow_author: Будет использован в XML файле при экспорте

View File

@ -1,11 +1,6 @@
if Redmine::VERSION::MAJOR >= 2
RedmineApp::Application.routes.draw do
resources :custom_workflows
post '/custom_workflows/:id', :to => 'custom_workflows#update'
end
else
ActionController::Routing::Routes.draw do |map|
map.resources :custom_workflows
map.connect '/custom_workflows/:id', :controller => 'custom_workflows', :action => 'update', :conditions => { :method => :post }
end
RedmineApp::Application.routes.draw do
post '/custom_workflows/import', :to => 'custom_workflows#import', :as => 'import_custom_workflow'
resources :custom_workflows
post '/custom_workflows/:id', :to => 'custom_workflows#update'
get '/custom_workflows/:id/export', :to => 'custom_workflows#export', :as => 'export_custom_workflow'
end

View File

@ -0,0 +1,6 @@
class AddAuthorAndTimestampsToCustomWorkflows < ActiveRecord::Migration
def change
add_column :custom_workflows, :author, :string, :null => true
add_timestamps :custom_workflows
end
end