mirror of
https://github.com/anteo/redmine_custom_workflows.git
synced 2026-01-26 00:04:20 +00:00
#1: Need save and restore abilities
This commit is contained in:
parent
fc6b11c953
commit
f336a2c244
@ -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" }
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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">
|
||||
|
||||
@ -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)) -%>
|
||||
|
||||
@ -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>
|
||||
@ -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
BIN
assets/images/export.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 265 B |
BIN
assets/images/import.png
Normal file
BIN
assets/images/import.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 279 B |
@ -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); }
|
||||
|
||||
@ -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
|
||||
@ -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 файле при экспорте
|
||||
@ -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
|
||||
|
||||
@ -0,0 +1,6 @@
|
||||
class AddAuthorAndTimestampsToCustomWorkflows < ActiveRecord::Migration
|
||||
def change
|
||||
add_column :custom_workflows, :author, :string, :null => true
|
||||
add_timestamps :custom_workflows
|
||||
end
|
||||
end
|
||||
Loading…
x
Reference in New Issue
Block a user