Merge pull request #129 from picman/devel-1.4.6
Approval workflow copied from 1.5.0 devel
@ -255,8 +255,22 @@ class DmsfController < ApplicationController
|
||||
redirect_to params[:current] ? params[:current] :
|
||||
{:controller => "dmsf", :action => "show", :id => @project, :folder_id => @folder.folder}
|
||||
end
|
||||
|
||||
|
||||
|
||||
def assign
|
||||
end
|
||||
|
||||
def assignment
|
||||
revision = DmsfFileRevision.find_by_id params[:dmsf_file_revision_id]
|
||||
if revision
|
||||
revision.set_workflow(params[:dmsf_workflow_id], params[:action])
|
||||
revision.assign_workflow(params[:dmsf_workflow_id])
|
||||
if request.post? && revision.save
|
||||
flash[:notice] = l(:notice_successful_create)
|
||||
end
|
||||
end
|
||||
redirect_to params[:current] ? params[:current] :
|
||||
{:controller => "dmsf", :action => "show", :id => @project, :folder_id => @folder.folder}
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
|
||||
@ -26,6 +26,7 @@ class DmsfFilesController < ApplicationController
|
||||
before_filter :authorize
|
||||
|
||||
helper :all
|
||||
helper :dmsf_workflows
|
||||
|
||||
def show
|
||||
# download is put here to provide more clear and usable links
|
||||
@ -82,7 +83,7 @@ class DmsfFilesController < ApplicationController
|
||||
|
||||
@revision.major_version = last_revision.major_version
|
||||
@revision.minor_version = last_revision.minor_version
|
||||
@revision.workflow = last_revision.workflow
|
||||
#@revision.workflow = last_revision.workflow
|
||||
version = params[:version].to_i
|
||||
file_upload = params[:file_upload]
|
||||
if file_upload.nil?
|
||||
@ -96,13 +97,14 @@ class DmsfFilesController < ApplicationController
|
||||
@revision.disk_filename = @revision.new_storage_filename
|
||||
@revision.mime_type = Redmine::MimeType.of(file_upload.original_filename)
|
||||
end
|
||||
@revision.set_workflow(params[:workflow])
|
||||
@revision.set_workflow(params[:dmsf_workflow_id], params[:commit])
|
||||
|
||||
@file.name = @revision.name
|
||||
@file.folder = @revision.folder
|
||||
|
||||
if @revision.valid? && @file.valid?
|
||||
@revision.save!
|
||||
@revision.assign_workflow(params[:dmsf_workflow_id])
|
||||
unless file_upload.nil?
|
||||
@revision.copy_file_content(file_upload)
|
||||
end
|
||||
|
||||
@ -26,6 +26,7 @@ class DmsfUploadController < ApplicationController
|
||||
before_filter :find_folder, :except => [:upload_file]
|
||||
|
||||
helper :all
|
||||
helper :dmsf_workflows
|
||||
|
||||
def upload_files
|
||||
uploaded_files = params[:uploaded_files]
|
||||
@ -107,7 +108,7 @@ class DmsfUploadController < ApplicationController
|
||||
new_revision.source_revision = last_revision
|
||||
new_revision.major_version = last_revision.major_version
|
||||
new_revision.minor_version = last_revision.minor_version
|
||||
new_revision.workflow = last_revision.workflow
|
||||
#new_revision.workflow = last_revision.workflow
|
||||
end
|
||||
|
||||
commited_disk_filepath = "#{DmsfHelper.temp_dir}/#{commited_file["disk_filename"].gsub(/[\/\\]/,'')}"
|
||||
@ -120,8 +121,8 @@ class DmsfUploadController < ApplicationController
|
||||
new_revision.title = commited_file["title"]
|
||||
new_revision.description = commited_file["description"]
|
||||
new_revision.comment = commited_file["comment"]
|
||||
new_revision.increase_version(commited_file["version"].to_i, true)
|
||||
new_revision.set_workflow(commited_file["workflow"])
|
||||
new_revision.increase_version(commited_file["version"].to_i, true)
|
||||
new_revision.set_workflow(commited_file[:dmsf_workflow_id], nil)
|
||||
new_revision.mime_type = Redmine::MimeType.of(new_revision.name)
|
||||
new_revision.size = File.size(commited_disk_filepath)
|
||||
|
||||
@ -147,6 +148,7 @@ class DmsfUploadController < ApplicationController
|
||||
end
|
||||
|
||||
if new_revision.save
|
||||
new_revision.assign_workflow(commited_file[:dmsf_workflow_id])
|
||||
file.reload
|
||||
|
||||
new_revision.copy_file_content(file_upload)
|
||||
|
||||
216
app/controllers/dmsf_workflows_controller.rb
Normal file
@ -0,0 +1,216 @@
|
||||
# Redmine plugin for Document Management System "Features"
|
||||
#
|
||||
# Copyright (C) 2013 Karel Picman <karel.picman@kontron.com>
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU General Public License
|
||||
# as published by the Free Software Foundation; either version 2
|
||||
# of the License, or (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
|
||||
class DmsfWorkflowsController < ApplicationController
|
||||
unloadable
|
||||
layout :workflows_layout
|
||||
|
||||
before_filter :find_workflow, :except => [:create, :new, :index, :assign, :assignment]
|
||||
before_filter :find_project, :except => [:start]
|
||||
before_filter :authorize_global
|
||||
|
||||
def index
|
||||
if @project
|
||||
@workflow_pages, @workflows = paginate DmsfWorkflow.where(:project_id => @project.id), :per_page => 25
|
||||
else
|
||||
@workflow_pages, @workflows = paginate DmsfWorkflow.where(:project_id => nil), :per_page => 25
|
||||
end
|
||||
end
|
||||
|
||||
def action
|
||||
end
|
||||
|
||||
def new_action
|
||||
if params[:commit] == l(:button_submit)
|
||||
action = DmsfWorkflowStepAction.new(
|
||||
:dmsf_workflow_step_assignment_id => params[:dmsf_workflow_step_assignment_id],
|
||||
:action => params[:step_action],
|
||||
:note => params[:note])
|
||||
if request.post?
|
||||
if action.save
|
||||
@workflow.try_finish params[:dmsf_file_revision_id], action, params[:user_id]
|
||||
flash[:notice] = l(:notice_successful_update)
|
||||
else
|
||||
flash[:error] = l(:error_empty_note)
|
||||
end
|
||||
end
|
||||
end
|
||||
redirect_to :back
|
||||
end
|
||||
|
||||
def assign
|
||||
end
|
||||
|
||||
def assignment
|
||||
if params[:commit] == l(:button_submit)
|
||||
revision = DmsfFileRevision.find_by_id params[:dmsf_file_revision_id]
|
||||
if revision
|
||||
revision.set_workflow(params[:dmsf_workflow_id], params[:action])
|
||||
revision.assign_workflow(params[:dmsf_workflow_id])
|
||||
if request.post?
|
||||
if revision.save
|
||||
flash[:notice] = l(:notice_successful_update)
|
||||
else
|
||||
flash[:error] = l(:error_workflow_assign)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
redirect_to :back
|
||||
end
|
||||
|
||||
def log
|
||||
end
|
||||
|
||||
def new
|
||||
@workflow = DmsfWorkflow.new
|
||||
end
|
||||
|
||||
def create
|
||||
@workflow = DmsfWorkflow.new(:name => params[:dmsf_workflow][:name], :project_id => params[:project_id])
|
||||
if request.post? && @workflow.save
|
||||
flash[:notice] = l(:notice_successful_create)
|
||||
if @project
|
||||
redirect_to settings_project_path(@project, :tab => 'dmsf')
|
||||
else
|
||||
redirect_to dmsf_workflows_path
|
||||
end
|
||||
else
|
||||
render :action => 'new'
|
||||
end
|
||||
end
|
||||
|
||||
def edit
|
||||
end
|
||||
|
||||
def update
|
||||
if request.put? && @workflow.update_attributes({:name => params[:dmsf_workflow][:name]})
|
||||
flash[:notice] = l(:notice_successful_update)
|
||||
if @project
|
||||
redirect_to settings_project_path(@project, :tab => 'dmsf')
|
||||
else
|
||||
redirect_to dmsf_workflows_path
|
||||
end
|
||||
else
|
||||
render :action => 'edit'
|
||||
end
|
||||
end
|
||||
|
||||
def destroy
|
||||
begin
|
||||
@workflow.destroy
|
||||
flash[:notice] = l(:notice_successful_delete)
|
||||
rescue
|
||||
flash[:error] = l(:error_unable_delete_dmsf_workflow)
|
||||
end
|
||||
if @project
|
||||
redirect_to settings_project_path(@project, :tab => 'dmsf')
|
||||
else
|
||||
redirect_to dmsf_workflows_path
|
||||
end
|
||||
end
|
||||
|
||||
def autocomplete_for_user
|
||||
render :layout => false
|
||||
end
|
||||
|
||||
def add_step
|
||||
if request.post?
|
||||
users = User.find_all_by_id(params[:user_ids])
|
||||
if params[:step] == '0'
|
||||
if @workflow.steps.count > 0
|
||||
step = @workflow.steps.last + 1
|
||||
else
|
||||
step = 1
|
||||
end
|
||||
else
|
||||
step = params[:step].to_i
|
||||
end
|
||||
operator = (params[:commit] == l(:dmsf_and)) ? DmsfWorkflowStep::OPERATOR_AND : DmsfWorkflowStep::OPERATOR_OR
|
||||
users.each do |user|
|
||||
@workflow.dmsf_workflow_steps << DmsfWorkflowStep.new(
|
||||
:dmsf_workflow_id => @workflow.id,
|
||||
:step => step,
|
||||
:user_id => user.id,
|
||||
:operator => operator)
|
||||
end
|
||||
@workflow.save
|
||||
end
|
||||
respond_to do |format|
|
||||
format.html
|
||||
end
|
||||
end
|
||||
|
||||
def remove_step
|
||||
if request.delete?
|
||||
DmsfWorkflowStep.where(:dmsf_workflow_id => @workflow.id, :step => params[:step]).each do |ws|
|
||||
@workflow.dmsf_workflow_steps.delete(ws)
|
||||
end
|
||||
@workflow.dmsf_workflow_steps.each do |ws|
|
||||
n = ws.step.to_i
|
||||
if n > params[:step].to_i
|
||||
ws.step = n - 1
|
||||
ws.save
|
||||
end
|
||||
end
|
||||
end
|
||||
respond_to do |format|
|
||||
format.html
|
||||
end
|
||||
end
|
||||
|
||||
def reorder_steps
|
||||
if request.put?
|
||||
@workflow.reorder_steps params[:step].to_i, params[:workflow_step][:move_to]
|
||||
end
|
||||
respond_to do |format|
|
||||
format.html
|
||||
end
|
||||
end
|
||||
|
||||
def start
|
||||
revision = DmsfFileRevision.find_by_id(params[:dmsf_file_revision_id])
|
||||
if revision
|
||||
revision.set_workflow(@workflow.id, params[:action])
|
||||
if request.post? && revision.save
|
||||
flash[:notice] = l(:notice_successful_update)
|
||||
end
|
||||
end
|
||||
redirect_to :back
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def find_workflow
|
||||
@workflow = DmsfWorkflow.find_by_id(params[:id])
|
||||
end
|
||||
|
||||
def find_project
|
||||
if @workflow && @workflow.project
|
||||
@project = @workflow.project
|
||||
elsif params[:project_id].present?
|
||||
@project = Project.find_by_id params[:project_id]
|
||||
end
|
||||
end
|
||||
|
||||
def workflows_layout
|
||||
find_workflow
|
||||
find_project
|
||||
@project ? 'base' : 'admin'
|
||||
end
|
||||
end
|
||||
66
app/helpers/dmsf_workflows_helper.rb
Normal file
@ -0,0 +1,66 @@
|
||||
# Redmine plugin for Document Management System "Features"
|
||||
#
|
||||
# Copyright (C) 2013 Karel Picman <karel.picman@kontron.com>
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU General Public License
|
||||
# as published by the Free Software Foundation; either version 2
|
||||
# of the License, or (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
|
||||
module DmsfWorkflowsHelper
|
||||
|
||||
def render_principals_for_new_dmsf_workflow_users(workflow, dmsf_workflow_step_assignment_id, dmsf_file_revision_id)
|
||||
scope = workflow.delegates(params[:q], dmsf_workflow_step_assignment_id, dmsf_file_revision_id, nil)
|
||||
principal_count = scope.count
|
||||
principal_pages = Redmine::Pagination::Paginator.new principal_count, 10, params['page']
|
||||
principals = scope.offset(principal_pages.offset).limit(principal_pages.per_page).all
|
||||
|
||||
if dmsf_workflow_step_assignment_id
|
||||
s = content_tag('div', principals_radio_button_tags('step_action', principals), :id => 'users_for_delegate')
|
||||
else
|
||||
s = content_tag('div', principals_check_box_tags('user_ids[]', principals), :id => 'users')
|
||||
end
|
||||
|
||||
links = pagination_links_full(principal_pages, principal_count, :per_page_links => false) {|text, parameters, options|
|
||||
link_to text, autocomplete_for_user_dmsf_workflow_path(workflow, parameters.merge(:q => params[:q], :format => 'js')), :remote => true
|
||||
}
|
||||
|
||||
s + content_tag('p', links, :class => 'pagination')
|
||||
s.html_safe
|
||||
end
|
||||
|
||||
def dmsf_workflow_steps_options_for_select(steps)
|
||||
options = Array.new
|
||||
options << [l(:dmsf_new_step), 0]
|
||||
steps.each do |step|
|
||||
options << [step.to_s, step]
|
||||
end
|
||||
options_for_select(options, 0)
|
||||
end
|
||||
|
||||
def dmsf_workflows_for_select(project, dmsf_workflow_id)
|
||||
options = Array.new
|
||||
options << [l(:option_workflow_none), nil]
|
||||
DmsfWorkflow.where(['project_id = ? OR project_id IS NULL', project.id]).each do |wf|
|
||||
options << [wf.name, wf.id]
|
||||
end
|
||||
options_for_select(options, :selected => dmsf_workflow_id)
|
||||
end
|
||||
|
||||
def principals_radio_button_tags(name, principals)
|
||||
s = ''
|
||||
principals.each do |principal|
|
||||
s << "<label>#{ radio_button_tag name, principal.id, false, :id => nil } #{h principal}</label>\n"
|
||||
end
|
||||
s.html_safe
|
||||
end
|
||||
end
|
||||
@ -25,6 +25,7 @@ class DmsfFileRevision < ActiveRecord::Base
|
||||
belongs_to :deleted_by_user, :class_name => "User", :foreign_key => "deleted_by_user_id"
|
||||
belongs_to :project
|
||||
has_many :access, :class_name => "DmsfFileRevisionAccess", :foreign_key => "dmsf_file_revision_id", :dependent => :destroy
|
||||
has_many :dmsf_workflow_step_assignment, :dependent => :destroy
|
||||
|
||||
#Returns a list of revisions that are not deleted here, or deleted at parent level either
|
||||
scope :visible, lambda {|*args| joins(:file).where(DmsfFile.visible_condition(args.shift || User.current, *args)).where("#{self.table_name}.deleted = :false", :false => false ).readonly(false) }
|
||||
@ -154,32 +155,52 @@ class DmsfFileRevision < ActiveRecord::Base
|
||||
|
||||
return new_revision
|
||||
end
|
||||
|
||||
#TODO: validate if it isn't doubled or move it to view
|
||||
def workflow_str
|
||||
|
||||
def workflow_str(name)
|
||||
if name && dmsf_workflow_id
|
||||
wf = DmsfWorkflow.find_by_id(dmsf_workflow_id)
|
||||
str = "#{wf.name} - " if wf
|
||||
else
|
||||
str = ''
|
||||
end
|
||||
case workflow
|
||||
when 1 then l(:title_waiting_for_approval)
|
||||
when 2 then l(:title_approved)
|
||||
else nil
|
||||
when DmsfWorkflow::STATE_WAITING_FOR_APPROVAL
|
||||
str + l(:title_waiting_for_approval)
|
||||
when DmsfWorkflow::STATE_APPROVED
|
||||
str + l(:title_approved)
|
||||
when DmsfWorkflow::STATE_DRAFT
|
||||
str + l(:title_draft)
|
||||
when DmsfWorkflow::STATE_REJECTED
|
||||
str + l(:title_rejected)
|
||||
else
|
||||
str
|
||||
end
|
||||
end
|
||||
|
||||
def set_workflow(workflow)
|
||||
def set_workflow(dmsf_workflow_id, commit)
|
||||
if User.current.allowed_to?(:file_approval, self.file.project)
|
||||
self.workflow = workflow
|
||||
else
|
||||
if self.source_revision.nil?
|
||||
self.workflow = workflow == 2 ? 1 : workflow
|
||||
else
|
||||
if workflow == 2 || self.source_revision.workflow == 1 || self.source_revision.workflow == 2
|
||||
self.workflow = 1
|
||||
unless dmsf_workflow_id.blank?
|
||||
self.dmsf_workflow_id = dmsf_workflow_id
|
||||
if commit == 'start'
|
||||
self.workflow = DmsfWorkflow::STATE_WAITING_FOR_APPROVAL
|
||||
self.dmsf_workflow_started_by = User.current.id if User.current
|
||||
self.dmsf_workflow_started_at = DateTime.now
|
||||
else
|
||||
self.workflow = workflow
|
||||
end
|
||||
self.workflow = DmsfWorkflow::STATE_DRAFT
|
||||
self.dmsf_workflow_assigned_by = User.current.id if User.current
|
||||
self.dmsf_workflow_assigned_at = DateTime.now
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def assign_workflow(dmsf_workflow_id)
|
||||
if User.current.allowed_to?(:file_approval, self.file.project)
|
||||
wf = DmsfWorkflow.find_by_id(dmsf_workflow_id)
|
||||
wf.assign(self.id) if wf && self.id
|
||||
end
|
||||
end
|
||||
|
||||
def increase_version(version_to_increase, new_content)
|
||||
if new_content
|
||||
self.minor_version = case version_to_increase
|
||||
|
||||
183
app/models/dmsf_workflow.rb
Normal file
@ -0,0 +1,183 @@
|
||||
# Redmine plugin for Document Management System "Features"
|
||||
#
|
||||
# Copyright (C) 2013 Karel Picman <karel.picman@kontron.com>
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU General Public License
|
||||
# as published by the Free Software Foundation; either version 2
|
||||
# of the License, or (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
|
||||
class DmsfWorkflow < ActiveRecord::Base
|
||||
has_many :dmsf_workflow_steps, :dependent => :destroy, :order => 'step ASC, operator DESC'
|
||||
|
||||
validates_uniqueness_of :name
|
||||
validates :name, :presence => true
|
||||
validates_length_of :name, :maximum => 255
|
||||
|
||||
STATE_NONE = nil
|
||||
STATE_DRAFT = 3
|
||||
STATE_WAITING_FOR_APPROVAL = 1
|
||||
STATE_APPROVED = 2
|
||||
STATE_REJECTED = 4
|
||||
|
||||
def self.workflows(project)
|
||||
project ? where(:project_id => project) : where('project_id IS NULL')
|
||||
end
|
||||
|
||||
def project
|
||||
Project.find_by_id(project_id) if project_id
|
||||
end
|
||||
|
||||
def to_s
|
||||
name
|
||||
end
|
||||
|
||||
def approvals(step)
|
||||
wa = Array.new
|
||||
dmsf_workflow_steps.each do |s|
|
||||
if s.step == step
|
||||
wa << s
|
||||
end
|
||||
end
|
||||
wa
|
||||
end
|
||||
|
||||
def steps
|
||||
ws = Array.new
|
||||
dmsf_workflow_steps.each do |s|
|
||||
unless ws.include? s.step
|
||||
ws << s.step
|
||||
end
|
||||
end
|
||||
ws
|
||||
end
|
||||
|
||||
def reorder_steps(step, move_to)
|
||||
case move_to
|
||||
when 'highest'
|
||||
unless step == 1
|
||||
dmsf_workflow_steps.each do |ws|
|
||||
if ws.step < step
|
||||
ws.update_attribute('step', ws.step + 1)
|
||||
elsif ws.step == step
|
||||
ws.update_attribute('step', 1)
|
||||
end
|
||||
end
|
||||
end
|
||||
when 'higher'
|
||||
unless step == 1
|
||||
dmsf_workflow_steps.each do |ws|
|
||||
if ws.step == step - 1
|
||||
ws.update_attribute('step', step)
|
||||
elsif ws.step == step
|
||||
ws.update_attribute('step', step - 1)
|
||||
end
|
||||
end
|
||||
end
|
||||
when 'lower'
|
||||
unless step == steps.count
|
||||
dmsf_workflow_steps.each do |ws|
|
||||
if ws.step == step + 1
|
||||
ws.update_attribute('step', step)
|
||||
elsif ws.step == step
|
||||
ws.update_attribute('step', step + 1)
|
||||
end
|
||||
end
|
||||
end
|
||||
when 'lowest'
|
||||
size = steps.count
|
||||
unless step == size
|
||||
dmsf_workflow_steps.each do |ws|
|
||||
if ws.step > step
|
||||
ws.update_attribute('step', ws.step - 1)
|
||||
elsif ws.step == step
|
||||
ws.update_attribute('step', size)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def delegates(q, dmsf_workflow_step_assignment_id, dmsf_file_revision_id, project_id)
|
||||
if project_id
|
||||
sql = ['id IN (SELECT user_id FROM members WHERE project_id = ?', project_id]
|
||||
elsif dmsf_workflow_step_assignment_id && dmsf_file_revision_id
|
||||
sql = [
|
||||
'id NOT IN (SELECT a.user_id FROM dmsf_workflow_step_assignments a WHERE id = ?) AND id IN (SELECT m.user_id FROM members m JOIN dmsf_file_revisions r ON m.project_id = r.project_id WHERE r.id = ?)',
|
||||
dmsf_workflow_step_assignment_id,
|
||||
dmsf_file_revision_id]
|
||||
else
|
||||
sql = '1=1'
|
||||
end
|
||||
|
||||
unless q.nil? || q.empty?
|
||||
User.active.sorted.where(sql).like(q)
|
||||
else
|
||||
User.active.sorted.where(sql)
|
||||
end
|
||||
end
|
||||
|
||||
def next_assignments(dmsf_file_revision_id)
|
||||
self.dmsf_workflow_steps.each do |step|
|
||||
unless step.finished?(dmsf_file_revision_id)
|
||||
return step.next_assignments(dmsf_file_revision_id)
|
||||
end
|
||||
end
|
||||
return nil
|
||||
end
|
||||
|
||||
def self.assignments_to_users_str(assignments)
|
||||
str = ''
|
||||
if assignments
|
||||
assignments.each_with_index do |assignment, index|
|
||||
user = User.find_by_id assignment.user_id
|
||||
if user
|
||||
if index > 0
|
||||
str << ', '
|
||||
end
|
||||
str << user.name
|
||||
end
|
||||
end
|
||||
end
|
||||
str
|
||||
end
|
||||
|
||||
def assign(dmsf_file_revision_id)
|
||||
dmsf_workflow_steps.each do |ws|
|
||||
ws.assign(dmsf_file_revision_id)
|
||||
end
|
||||
end
|
||||
|
||||
def try_finish(dmsf_file_revision_id, action, user_id)
|
||||
res = nil
|
||||
case action.action
|
||||
when DmsfWorkflowStepAction::ACTION_APPROVE
|
||||
self.dmsf_workflow_steps.each do |step|
|
||||
res = step.result dmsf_file_revision_id
|
||||
unless step.finished? dmsf_file_revision_id
|
||||
return
|
||||
end
|
||||
end
|
||||
when DmsfWorkflowStepAction::ACTION_REJECT
|
||||
res = DmsfWorkflow::STATE_REJECTED
|
||||
when DmsfWorkflowStepAction::ACTION_DELEGATE
|
||||
assignment = DmsfWorkflowStepAssignment.find_by_id(action.dmsf_workflow_step_assignment_id)
|
||||
assignment.update_attribute(:user_id, user_id) if assignment
|
||||
end
|
||||
|
||||
if res
|
||||
revision = DmsfFileRevision.find_by_id dmsf_file_revision_id
|
||||
revision.update_attribute(:workflow, res) if revision
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
96
app/models/dmsf_workflow_step.rb
Normal file
@ -0,0 +1,96 @@
|
||||
# Redmine plugin for Document Management System "Features"
|
||||
#
|
||||
# Copyright (C) 2013 Karel Picman <karel.picman@kontron.com>
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU General Public License
|
||||
# as published by the Free Software Foundation; either version 2
|
||||
# of the License, or (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
|
||||
class DmsfWorkflowStep < ActiveRecord::Base
|
||||
belongs_to :workflow
|
||||
|
||||
has_many :dmsf_workflow_step_assignments, :dependent => :destroy
|
||||
|
||||
validates :dmsf_workflow_id, :presence => true
|
||||
validates :step, :presence => true
|
||||
validates :user_id, :presence => true
|
||||
validates :operator, :presence => true
|
||||
validates_uniqueness_of :user_id, :scope => [:dmsf_workflow_id, :step]
|
||||
|
||||
OPERATOR_OR = 0
|
||||
OPERATOR_AND = 1
|
||||
|
||||
def soperator
|
||||
operator == 1 ? l(:dmsf_and) : l(:dmsf_or)
|
||||
end
|
||||
|
||||
def user
|
||||
User.find(user_id)
|
||||
end
|
||||
|
||||
def assign(dmsf_file_revision_id)
|
||||
step_assignment = DmsfWorkflowStepAssignment.new(
|
||||
:dmsf_workflow_step_id => id,
|
||||
:user_id => user_id,
|
||||
:dmsf_file_revision_id => dmsf_file_revision_id)
|
||||
step_assignment.save
|
||||
end
|
||||
|
||||
def finished?(dmsf_file_revision_id)
|
||||
res = self.result(dmsf_file_revision_id)
|
||||
res == DmsfWorkflow::STATE_APPROVED || res == DmsfWorkflow::STATE_REJECTED
|
||||
end
|
||||
|
||||
def result(dmsf_file_revision_id)
|
||||
assignments = DmsfWorkflowStepAssignment.where(
|
||||
:dmsf_workflow_step_id => self.id, :dmsf_file_revision_id => dmsf_file_revision_id).all
|
||||
assignments.each do |assignment|
|
||||
actions = DmsfWorkflowStepAction.where(
|
||||
:dmsf_workflow_step_assignment_id => assignment.id).all
|
||||
if actions.empty?
|
||||
return
|
||||
end
|
||||
actions.each do |action|
|
||||
if DmsfWorkflowStepAction.is_finished?(action.action)
|
||||
case action.action
|
||||
when DmsfWorkflowStepAction::ACTION_APPROVE
|
||||
return DmsfWorkflow::STATE_APPROVED
|
||||
when DmsfWorkflowStepAction::ACTION_REJECT
|
||||
return DmsfWorkflow::STATE_REJECTED
|
||||
else
|
||||
return
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def next_assignments(dmsf_file_revision_id)
|
||||
results = Array.new
|
||||
assignments = DmsfWorkflowStepAssignment.where(
|
||||
:dmsf_workflow_step_id => self.id,
|
||||
:dmsf_file_revision_id => dmsf_file_revision_id)
|
||||
assignments.each do |assignment|
|
||||
add = true
|
||||
assignment.dmsf_workflow_step_actions.each do |action|
|
||||
if action.is_finished?
|
||||
add = false
|
||||
break
|
||||
end
|
||||
end
|
||||
results << assignment if add
|
||||
end
|
||||
return results
|
||||
end
|
||||
|
||||
end
|
||||
65
app/models/dmsf_workflow_step_action.rb
Normal file
@ -0,0 +1,65 @@
|
||||
# Redmine plugin for Document Management System "Features"
|
||||
#
|
||||
# Copyright (C) 2013 Karel Picman <karel.picman@kontron.com>
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU General Public License
|
||||
# as published by the Free Software Foundation; either version 2
|
||||
# of the License, or (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
|
||||
class DmsfWorkflowStepAction < ActiveRecord::Base
|
||||
|
||||
belongs_to :dmsf_workflow_step_assignment
|
||||
|
||||
validates :dmsf_workflow_step_assignment_id, :presence => true
|
||||
validates :action, :presence => true
|
||||
validates :note, :presence => true, :unless => lambda { self.action == DmsfWorkflowStepAction::ACTION_APPROVE }
|
||||
validates :author_id, :presence => true
|
||||
|
||||
ACTION_APPROVE = 1
|
||||
ACTION_REJECT = 2
|
||||
ACTION_DELEGATE = 3
|
||||
ACTION_ASSIGN = 4
|
||||
ACTION_START = 5
|
||||
|
||||
def initialize(*args)
|
||||
super
|
||||
self.author_id = User.current.id if User.current
|
||||
end
|
||||
|
||||
def self.is_finished?(action)
|
||||
action == DmsfWorkflowStepAction::ACTION_APPROVE ||
|
||||
action == DmsfWorkflowStepAction::ACTION_REJECT
|
||||
end
|
||||
|
||||
def is_finished?
|
||||
DmsfWorkflowStepAction.is_finished? self.action
|
||||
end
|
||||
|
||||
def self.action_str(action)
|
||||
if action
|
||||
case action.to_i
|
||||
when ACTION_APPROVE
|
||||
l(:title_approved)
|
||||
when ACTION_REJECT
|
||||
l(:title_rejected)
|
||||
when ACTION_DELEGATE
|
||||
l(:title_delegated)
|
||||
when ACTION_ASSIGN
|
||||
l(:title_assigned)
|
||||
when ACTION_START
|
||||
l(:title_started)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
27
app/models/dmsf_workflow_step_assignment.rb
Normal file
@ -0,0 +1,27 @@
|
||||
# Redmine plugin for Document Management System "Features"
|
||||
#
|
||||
# Copyright (C) 2013 Karel Picman <karel.picman@kontron.com>
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU General Public License
|
||||
# as published by the Free Software Foundation; either version 2
|
||||
# of the License, or (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
|
||||
class DmsfWorkflowStepAssignment < ActiveRecord::Base
|
||||
belongs_to :dmsf_workflow_step
|
||||
|
||||
has_many :dmsf_workflow_step_actions, :dependent => :destroy
|
||||
has_one :dmsf_workflow_step_assignment
|
||||
|
||||
validates :dmsf_workflow_step_id, :presence => true
|
||||
validates :dmsf_file_revision_id, :presence => true
|
||||
end
|
||||
@ -27,8 +27,9 @@
|
||||
<p>
|
||||
<%= label_tag("", l(:field_folder) + ":") %>
|
||||
<%= f.select(:dmsf_folder_id,
|
||||
options_for_select(DmsfFolder.directory_tree(@project, @folder),
|
||||
:selected => @folder.nil? ? (@pathfolder.id unless @pathfolder.nil?) : (@folder.folder.id unless @folder.folder.nil?))) %>
|
||||
options_for_select(DmsfFolder.directory_tree(@project, @folder),
|
||||
:selected => @parent? @parent.id : (@pathfolder.id if @pathfolder)))
|
||||
%>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@ -43,6 +43,9 @@
|
||||
</div>
|
||||
<%= render "custom_fields", :object => @folder %>
|
||||
</div>
|
||||
|
||||
<%= error_messages_for('dmsf_workflow') %>
|
||||
|
||||
<%= form_tag({:action => :entries_operation, :id => @project, :folder_id => @folder}, :method => :post,
|
||||
:class => "dmfs_entries", :id => "entries_form") do %>
|
||||
<%= hidden_field_tag("action") %>
|
||||
@ -62,8 +65,9 @@
|
||||
<th><%= l(:link_title) %></th>
|
||||
<th><%= l(:link_size) %></th>
|
||||
<th><%= l(:link_modified) %></th>
|
||||
<th><%= l(:link_ver) %></th>
|
||||
<th><%= l(:link_author) %></th>
|
||||
<th title="<%= l(:label_version) %>"><%= l(:link_ver) %></th>
|
||||
<th><%= l(:link_workflow) %></th>
|
||||
<th><%= l(:link_author) %></th>
|
||||
<th></th>
|
||||
<th class="hidden"></th>
|
||||
<th class="hidden"></th>
|
||||
@ -91,10 +95,11 @@
|
||||
<% end %>
|
||||
</td>
|
||||
<td class="version"></td>
|
||||
<td class="workflow"></td>
|
||||
<td class="author"><%= h(subfolder.user) %></td>
|
||||
<td class="actions">
|
||||
<% if User.current.allowed_to?(:file_approval, @project) %>
|
||||
<div class="right_icon_box">
|
||||
<div class="right_icon_box" style="width:26px;">
|
||||
<% if subfolder.notification %>
|
||||
<%= link_to_function(image_tag("notify.png", :plugin => :redmine_dmsf),
|
||||
"manipulation_link('#{url_for(:action => 'notify_deactivate', :id => @project, :folder_id => subfolder)}')",
|
||||
@ -103,7 +108,7 @@
|
||||
<%= link_to_function(image_tag("notifynot.png", :plugin => :redmine_dmsf),
|
||||
"manipulation_link('#{url_for(:action => 'notify_activate', :id => @project, :folder_id => subfolder)}')",
|
||||
:title => l(:title_notifications_not_active_activate)) %>
|
||||
<% end %>
|
||||
<% end %>
|
||||
</div>
|
||||
<% end %>
|
||||
<div class="right_icon_box" style="width: 70px;">
|
||||
@ -145,6 +150,7 @@
|
||||
</tr>
|
||||
<% end %>
|
||||
<% @files.each do |file| %>
|
||||
<% wf = DmsfWorkflow.find_by_id(file.last_revision.dmsf_workflow_id) %>
|
||||
<tr class="file">
|
||||
<td class="check"><%= check_box_tag("files[]", file.id, false, :title => l(:title_check_for_zip_download_or_email)) %></td>
|
||||
<td class="title">
|
||||
@ -168,19 +174,23 @@
|
||||
<%= image_tag("lockedbycurrent.png", :title => l(:title_locked_by_you), :plugin => :redmine_dmsf) %>
|
||||
<% end %>
|
||||
</td>
|
||||
<td class="version">
|
||||
<%= file.last_revision.version %>
|
||||
<% case file.last_revision.workflow
|
||||
when 1 then %><%= image_tag("waitingforapproval.png", :title => l(:title_waiting_for_approval),
|
||||
:plugin => :redmine_dmsf) %>
|
||||
<% when 2 then %><%= image_tag("approved.png", :title => l(:title_approved),
|
||||
:plugin => :redmine_dmsf) %>
|
||||
<% end %>
|
||||
<td class="version"><%= file.last_revision.version %></td>
|
||||
<td class="workflow">
|
||||
<% if wf %>
|
||||
<%= link_to(
|
||||
file.last_revision.workflow_str(false),
|
||||
log_dmsf_workflow_path(
|
||||
:project_id => @project.id,
|
||||
:id => wf.id,
|
||||
:dmsf_file_revision_id => file.last_revision.id),
|
||||
:title => DmsfWorkflow.assignments_to_users_str(wf.next_assignments(file.last_revision.id)),
|
||||
:remote => true) %>
|
||||
<% end %>
|
||||
</td>
|
||||
<td class="author"><%= h(file.last_revision.user) %></td>
|
||||
<td class="actions">
|
||||
<% if User.current.allowed_to?(:file_approval, @project) %>
|
||||
<div class="right_icon_box">
|
||||
<div class="right_icon_box" style="width:26px;">
|
||||
<% if file.notification %>
|
||||
<%= link_to_function(image_tag("notify.png", :plugin => :redmine_dmsf),
|
||||
"manipulation_link('#{url_for(:controller => "dmsf_files", :action => 'notify_deactivate', :id => file)}')",
|
||||
@ -190,9 +200,51 @@
|
||||
"manipulation_link('#{url_for(:controller => "dmsf_files", :action => 'notify_activate', :id => file)}')",
|
||||
:title => l(:title_notifications_not_active_activate)) %>
|
||||
<% end %>
|
||||
</div>
|
||||
<% case file.last_revision.workflow %>
|
||||
<% when DmsfWorkflow::STATE_WAITING_FOR_APPROVAL %>
|
||||
<% if wf %>
|
||||
<% assignments = wf.next_assignments(file.last_revision.id) %>
|
||||
<% index = assignments.find_index{|assignment| assignment.user_id == User.current.id} if assignments %>
|
||||
<% if index %>
|
||||
<%= link_to(
|
||||
image_tag('waiting_for_approval.png', :plugin => :redmine_dmsf),
|
||||
action_dmsf_workflow_path(
|
||||
:project_id => @project.id,
|
||||
:id => wf.id,
|
||||
:dmsf_workflow_step_assignment_id => assignments[index].id,
|
||||
:dmsf_file_revision_id => file.last_revision.id),
|
||||
:title => l(:title_waiting_for_approval),
|
||||
:remote => true) %>
|
||||
<% else %>
|
||||
<%= image_tag('waiting_for_approval.png', :title => "#{l(:label_dmsf_wokflow_action_approve)} #{l(:label_dmsf_wokflow_action_reject)} #{l(:label_dmsf_wokflow_action_delegate)}", :plugin => :redmine_dmsf) %>
|
||||
<% end %>
|
||||
<% end %>
|
||||
<% when DmsfWorkflow::STATE_APPROVED %>
|
||||
<%= image_tag('approved.png', :title => l(:title_approved), :plugin => :redmine_dmsf) %>
|
||||
<% when DmsfWorkflow::STATE_DRAFT %>
|
||||
<% if User.current && (file.last_revision.dmsf_workflow_assigned_by == User.current.id) %>
|
||||
<%= link_to_function(image_tag('draft.png', :plugin => :redmine_dmsf),
|
||||
"manipulation_link('#{start_dmsf_workflow_path(
|
||||
:id => file.last_revision.dmsf_workflow_id,
|
||||
:dmsf_file_revision_id => file.last_revision.id)}')",
|
||||
:title => l(:label_dmsf_wokflow_action_start)) %>
|
||||
<% else %>
|
||||
<%= image_tag('draft.png', :title => l(:label_dmsf_wokflow_action_start), :plugin => :redmine_dmsf) %>
|
||||
<% end %>
|
||||
<% when DmsfWorkflow::STATE_REJECTED %>
|
||||
<%= image_tag('rejected.png', :title => l(:title_rejected), :plugin => :redmine_dmsf) %>
|
||||
<% else %>
|
||||
<%= link_to(
|
||||
image_tag('none.png', :plugin => :redmine_dmsf),
|
||||
assign_dmsf_workflow_path(
|
||||
:project_id => @project.id,
|
||||
:dmsf_file_revision_id => file.last_revision.id),
|
||||
:title => l(:label_dmsf_wokflow_action_assign),
|
||||
:remote => true) %>
|
||||
<% end %>
|
||||
</div>
|
||||
<% end %>
|
||||
<div class="right_icon_box" style="width: 70px;">
|
||||
<div class="right_icon_box" style="width: 70px">
|
||||
<div style="float: left">
|
||||
<%= link_to(image_tag("filedetails.png", :plugin => :redmine_dmsf, :class =>"detail_icon"),
|
||||
{:controller => "dmsf_files", :action => :show, :id => file },
|
||||
@ -219,7 +271,7 @@
|
||||
<%= link_to_function(image_tag("delete.png", :plugin => :redmine_dmsf),
|
||||
"confirmation_link('#{url_for(:controller => "dmsf_files", :action => 'delete', :id => file)}')",
|
||||
:title => l(:title_delete)) %>
|
||||
<% end %>
|
||||
<% end %>
|
||||
</div>
|
||||
</div>
|
||||
<br class="clear" />
|
||||
@ -257,7 +309,7 @@ sUrl = "jquery.dataTables/#{I18n.locale.to_s.downcase}.json" if I18n.locale && !
|
||||
%>
|
||||
|
||||
<% content_for :header_tags do %>
|
||||
<%= stylesheet_link_tag "jquery-ui/jquery-ui-1.8.13.css", :plugin => "redmine_dmsf" %>
|
||||
<%= stylesheet_link_tag "jquery-ui/jquery-ui-1.9.2.css", :plugin => "redmine_dmsf" %>
|
||||
<%= stylesheet_link_tag "plupload/jquery.ui.plupload.css", :plugin => "redmine_dmsf" %>
|
||||
<%= stylesheet_link_tag "jquery.dataTables/jquery-ui.dataTables.css", :plugin => "redmine_dmsf" %>
|
||||
<%= stylesheet_link_tag "dmsf", :plugin => "redmine_dmsf" %>
|
||||
@ -278,9 +330,9 @@ sUrl = "jquery.dataTables/#{I18n.locale.to_s.downcase}.json" if I18n.locale && !
|
||||
"aaSorting": [[1,'asc']],
|
||||
"aaSortingFixed": [[7,'asc']],
|
||||
"aoColumnDefs": [
|
||||
{ "bSearchable": false, "aTargets": [0, 6, 7, 8] },
|
||||
{ "bSortable": false, "aTargets": [0, 6, 7] },
|
||||
{ "iDataSort": 8, "aTargets": [ 2 ] }
|
||||
{ "bSearchable": false, "aTargets": [0, 7, 8, 9] },
|
||||
{ "bSortable": false, "aTargets": [0, 7, 8] },
|
||||
{ "iDataSort": 9, "aTargets": [ 2 ] }
|
||||
],
|
||||
"fnInitComplete": function() {
|
||||
jQuery("div.controls").prependTo(jQuery("#browser_wrapper div.fg-toolbar")[0]);
|
||||
|
||||
@ -4,21 +4,6 @@
|
||||
<% if @file.locked_for_user? %>
|
||||
<p class="warning"><%= l(:info_file_locked) %></p>
|
||||
<% else %>
|
||||
<%
|
||||
disabled_workflow = []
|
||||
selected_workflow = nil
|
||||
if !User.current.allowed_to?(:file_approval, @project)
|
||||
disabled_workflow << 2
|
||||
current_workflow = @file.last_revision.workflow
|
||||
if current_workflow == 1 || current_workflow == 2
|
||||
disabled_workflow << nil
|
||||
selected_workflow = 1
|
||||
end
|
||||
else
|
||||
selected_workflow = @file.last_revision.workflow
|
||||
end
|
||||
%>
|
||||
|
||||
<%= form_for(@revision, :url => {:action => "create_revision", :id => @file},
|
||||
:html => {:method=>:post, :multipart => true, :id => "new_revision_form"}) do |f| %>
|
||||
<div class="clear">
|
||||
@ -57,16 +42,7 @@ end
|
||||
<%= @file.last_revision.major_version %>.<%= @file.last_revision.minor_version + 1 %> <%= l(:option_version_minor) %><br />
|
||||
<%= radio_button_tag("version", 2, @revision.major_version != @file.last_revision.major_version) %>
|
||||
<%= @file.last_revision.major_version + 1 %>.0 <%= l(:option_version_major) %><br />
|
||||
</div>
|
||||
<p>
|
||||
<%= label_tag("workflow", l(:label_workflow) + ":") %>
|
||||
<%= select_tag("workflow",
|
||||
options_for_select([
|
||||
[l(:option_workflow_none), nil],
|
||||
[l(:option_workflow_waiting_for_approval), 1],
|
||||
[l(:option_workflow_approved), 2]],
|
||||
:selected => selected_workflow, :disabled => disabled_workflow)) %>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="splitcontentright clear">
|
||||
<p>
|
||||
@ -78,7 +54,7 @@ end
|
||||
(<%= l(:label_max_size) %>: <%= number_to_human_size(Setting.attachment_max_size.to_i.kilobytes) %>)
|
||||
</small>
|
||||
</div>
|
||||
</p>
|
||||
</p>
|
||||
</div>
|
||||
<br style="clear: both"/>
|
||||
<div class="custom_fields">
|
||||
@ -96,6 +72,7 @@ end
|
||||
</div>
|
||||
<br />
|
||||
<%= submit_tag(l(:submit_create)) %>
|
||||
|
||||
<% end %>
|
||||
<% end %>
|
||||
</div>
|
||||
|
||||
@ -57,77 +57,72 @@
|
||||
|
||||
<h3><%= l(:heading_revisions) %></h3>
|
||||
<% @file.revisions.visible[@revision_pages.current.offset,@revision_pages.items_per_page].each do |revision| %>
|
||||
<div class="box dmsf_detail">
|
||||
<div style="float:right">
|
||||
<%= link_to(image_tag("download.png", :plugin => "redmine_dmsf"),
|
||||
{:action => "show", :id => @file, :download => revision},
|
||||
:title => l(:title_title_version_version_download, :title => h(revision.title), :version => revision.version)) %>
|
||||
<% if User.current.allowed_to?(:file_approval, @project) %>
|
||||
|
||||
<%= link_to_function(image_tag("delete.png", :plugin => "redmine_dmsf"),
|
||||
"confirmation_link('#{url_for(:action => 'delete_revision', :id => revision)}', '#{l(:question_do_you_really_want_to_delete_this_revision)}')",
|
||||
:title => l(:title_delete_revision)) %>
|
||||
<% end %>
|
||||
</div>
|
||||
<p class="no-ident">
|
||||
<%=label_tag("", (revision.source_revision.nil? ? l(:label_created) : l(:label_changed)) + ":")%>
|
||||
<%= l(:info_changed_by_user, :changed => format_time(revision.updated_at), :user => h(revision.user)) %>
|
||||
</p>
|
||||
<div class="clear">
|
||||
<div class="splitcontentleft">
|
||||
<p>
|
||||
<%= label_tag("", l(:label_title) + ":") %>
|
||||
<%= h(revision.title) %>
|
||||
</p>
|
||||
</div>
|
||||
<div class="splitcontentright">
|
||||
<p>
|
||||
<%= label_tag("", l(:label_file) + ":") %>
|
||||
<%= (h(revision.folder.dmsf_path_str) + "/") unless revision.folder.nil? %><%= h(revision.name) %>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<p class="no-ident">
|
||||
<%= label_tag("", l(:label_description) + ":") %>
|
||||
</p>
|
||||
<div class="wiki clear" style="margin-left: 110px">
|
||||
<%= textilizable(revision.description) %>
|
||||
</div>
|
||||
|
||||
<div class="splitcontentleft">
|
||||
<p>
|
||||
<%= label_tag("", l(:label_version) + ":") %>
|
||||
<%= revision.major_version %>.<%= revision.minor_version %>
|
||||
</p>
|
||||
<p>
|
||||
<%= label_tag("", l(:label_workflow) + ":") %>
|
||||
<%= case revision.workflow
|
||||
when 1 then l(:option_workflow_waiting_for_approval)
|
||||
when 2 then l(:option_workflow_approved)
|
||||
else l(:option_workflow_none)
|
||||
end %>
|
||||
</p>
|
||||
</div>
|
||||
<div class="splitcontentright clear">
|
||||
<p>
|
||||
<%= label_tag("", l(:label_mime) + ":") %>
|
||||
<%= h(revision.mime_type) %>
|
||||
</p>
|
||||
<p>
|
||||
<%= label_tag("", l(:label_size) + ":") %>
|
||||
<%= number_to_human_size(revision.size) %>
|
||||
</p>
|
||||
</div>
|
||||
<br style="clear: both"/>
|
||||
<div class="no-ident clear">
|
||||
<%= render "dmsf/custom_fields", :object => revision %>
|
||||
</div>
|
||||
<p class="no-ident clear">
|
||||
<%= label_tag("", l(:label_comment) + ":") %>
|
||||
<%= h(revision.comment) %>
|
||||
</p>
|
||||
<%= render(:partial => "revision_access", :locals => {:revision => revision}) if User.current.allowed_to?(:file_approval, @file.project) %>
|
||||
</div>
|
||||
<div class="revision_box dmsf_detail dataTables_wrapper">
|
||||
<div class="fg-toolbar ui-toolbar ui-widget-header ui-corner-tl ui-corner-tr ui-helper-clearfix">
|
||||
<div class="dataTables_lenght">
|
||||
<div class="controls" style="float: right">
|
||||
<%= link_to_function(image_tag('rev_downloads.png', :plugin => 'redmine_dmsf'), "$('#revision_access-#{revision.id}').toggle()", :title => 'Download entries')%>
|
||||
<%= link_to(image_tag('rev_download.png', :plugin => 'redmine_dmsf'),
|
||||
{:action => 'show', :id => @file, :download => revision},
|
||||
:title => l(:title_title_version_version_download, :title => h(revision.title), :version => revision.version)) %>
|
||||
<% if User.current.allowed_to?(:file_approval, @project) %>
|
||||
<%= link_to_function(image_tag('rev_delete.png', :plugin => 'redmine_dmsf'),
|
||||
"confirmation_link('#{url_for(:action => 'delete_revision', :id => revision)}', '#{l(:question_do_you_really_want_to_delete_this_revision)}')",
|
||||
:title => l(:title_delete_revision)) %>
|
||||
<% end %>
|
||||
</div>
|
||||
<i><%= l(:info_revision, :rev => revision.id) %></i>
|
||||
<%= (revision.source_revision.nil? ? l(:label_created) : l(:label_changed)).downcase %>
|
||||
<%= l(:info_changed_by_user, :changed => format_time(revision.updated_at)) %>
|
||||
<%= link_to(revision.user) %>
|
||||
</div>
|
||||
</div>
|
||||
<div style="border: 1px solid #e4e4e4;">
|
||||
<div class="clear">
|
||||
<div class="splitcontentleft">
|
||||
<%= label_tag("", l(:label_title) + ":") %>
|
||||
<%= h(revision.title) %>
|
||||
</div>
|
||||
<div class="splitcontentright">
|
||||
<%= label_tag("", l(:label_file) + ":") %>
|
||||
<%= (h(revision.folder.dmsf_path_str) + "/") unless revision.folder.nil? %><%= h(revision.name) %>
|
||||
</div>
|
||||
</div>
|
||||
<p class="no-ident">
|
||||
<%= label_tag("", l(:label_description) + ":") %>
|
||||
</p>
|
||||
<div class="wiki clear" style="margin-left: 110px">
|
||||
<%= textilizable(revision.description) %>
|
||||
</div>
|
||||
<div class="splitcontentleft">
|
||||
<%= label_tag("", l(:label_version) + ":") %>
|
||||
<%= revision.major_version %>.<%= revision.minor_version %>
|
||||
<br/>
|
||||
<%= label_tag('', l(:label_workflow) + ':') %>
|
||||
<%= revision.workflow_str true %>
|
||||
</div>
|
||||
<div class="splitcontentright clear">
|
||||
<%= label_tag("", l(:label_mime) + ":") %>
|
||||
<%= h(revision.mime_type) %>
|
||||
<br/>
|
||||
<%= label_tag("", l(:label_size) + ":") %>
|
||||
<%= number_to_human_size(revision.size) %>
|
||||
</div>
|
||||
<div class="no-ident clear">
|
||||
<%= render "dmsf/custom_fields", :object => revision %>
|
||||
</div>
|
||||
<div class="splitcontentleft clear">
|
||||
<%= label_tag("", l(:label_comment) + ":") %>
|
||||
<%= h(revision.comment) %>
|
||||
</div>
|
||||
<br/>
|
||||
<div id="<%= "revision_access-#{revision.id}" %>" style="display:none">
|
||||
<%= render(:partial => "revision_access", :locals => {:revision => revision}) if User.current.allowed_to?(:file_approval, @file.project) %>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<br/>
|
||||
<br/>
|
||||
<% end %>
|
||||
|
||||
<p class="pagination"><%= pagination_links_full @revision_pages, @file.revisions.visible.count %></p>
|
||||
@ -176,7 +171,7 @@ sUrl = "jquery.dataTables/#{I18n.locale.to_s.downcase}.json" if I18n.locale && !
|
||||
<% end %>
|
||||
|
||||
<% content_for :header_tags do %>
|
||||
<%= stylesheet_link_tag "jquery-ui/jquery-ui-1.8.13.css", :plugin => "redmine_dmsf" %>
|
||||
<%= stylesheet_link_tag "jquery-ui/jquery-ui-1.9.2.css", :plugin => "redmine_dmsf" %>
|
||||
<%= stylesheet_link_tag "jquery.dataTables/jquery-ui.dataTables.css", :plugin => "redmine_dmsf" %>
|
||||
<%= stylesheet_link_tag "dmsf", :plugin => "redmine_dmsf" %>
|
||||
<%= javascript_include_tag "jquery-1.6.1.min.js", :plugin => "redmine_dmsf" %>
|
||||
|
||||
@ -13,7 +13,7 @@
|
||||
:download => ""}) %> (<%= file.name %>),
|
||||
<%= number_to_human_size(file.last_revision.size) %>,
|
||||
version: <%= file.last_revision.major_version %>.<%= file.last_revision.minor_version %>,
|
||||
<%= "#{file.last_revision.workflow_str}," unless file.last_revision.workflow_str.blank? %>
|
||||
<%= "#{file.last_revision.workflow_str(true)}," unless file.last_revision.workflow_str(true).blank? %>
|
||||
<%= link_to("Details",
|
||||
{:only_path => false, :controller => "dmsf_files", :action => "show", :id => file}) %>
|
||||
<% unless file.last_revision.comment.blank? %>
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
User <%= @user %> actualized DMSF files in project <%= @project.name %>:
|
||||
<% @files.each do |file| %>
|
||||
<%= file.dmsf_path_str %> (<%= file.name %>), <%= number_to_human_size(file.last_revision.size) %>, version: <%= file.last_revision.major_version %>.<%= file.last_revision.minor_version %><%= ", #{file.last_revision.workflow_str}" unless file.last_revision.workflow_str.blank? %>
|
||||
<%= file.dmsf_path_str %> (<%= file.name %>), <%= number_to_human_size(file.last_revision.size) %>, version: <%= file.last_revision.major_version %>.<%= file.last_revision.minor_version %><%= ", #{file.last_revision.workflow_str(true)}" unless file.last_revision.workflow_str(true).blank? %>
|
||||
<%= url_for({:only_path => false, :controller => "dmsf_files", :action => "show", :id => file}) %>
|
||||
<% unless file.last_revision.comment.blank? %> comment: <%= file.last_revision.comment %><% end %>
|
||||
<% end %>
|
||||
@ -13,7 +13,7 @@
|
||||
:download => ""}) %> (<%= file.name %>),
|
||||
<%= number_to_human_size(file.last_revision.size) %>,
|
||||
version: <%= file.last_revision.major_version %>.<%= file.last_revision.minor_version %>,
|
||||
<%= "#{file.last_revision.workflow_str}," unless file.last_revision.workflow_str.blank? %>
|
||||
<%= "#{file.last_revision.workflow_str(true)}," unless file.last_revision.workflow_str(true).blank? %>
|
||||
<%= link_to("Details",
|
||||
{:only_path => false, :controller => "dmsf_files", :action => "show", :id => file}) %>
|
||||
<% unless file.last_revision.comment.blank? %>
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
User <%= @user %> actualized DMSF files in project <%= @project.name %>:
|
||||
<% @files.each do |file| %>
|
||||
<%= file.dmsf_path_str %> (<%= file.name %>), <%= number_to_human_size(file.last_revision.size) %>, version: <%= file.last_revision.major_version %>.<%= file.last_revision.minor_version %><%= ", #{file.last_revision.workflow_str}" unless file.last_revision.workflow_str.blank? %>
|
||||
<%= file.dmsf_path_str %> (<%= file.name %>), <%= number_to_human_size(file.last_revision.size) %>, version: <%= file.last_revision.major_version %>.<%= file.last_revision.minor_version %><%= ", #{file.last_revision.workflow_str(true)}" unless file.last_revision.workflow_str(true).blank? %>
|
||||
<%= url_for({:only_path => false, :controller => "dmsf_files", :action => "show", :id => file}) %>
|
||||
<% unless file.last_revision.comment.blank? %> comment: <%= file.last_revision.comment %><% end %>
|
||||
<% end %>
|
||||
@ -1,17 +1,4 @@
|
||||
<%
|
||||
disabled_workflow = []
|
||||
selected_workflow = nil
|
||||
unless User.current.allowed_to?(:file_approval, @project)
|
||||
disabled_workflow << 2
|
||||
current_workflow = upload.workflow
|
||||
if current_workflow == 1 || current_workflow == 2
|
||||
disabled_workflow << nil
|
||||
selected_workflow = 1
|
||||
end
|
||||
else
|
||||
selected_workflow = upload.workflow
|
||||
end
|
||||
%>
|
||||
|
||||
<div class="box dmsf_detail">
|
||||
<%= hidden_field_tag("commited_files[#{i}][disk_filename]", upload.disk_filename) %>
|
||||
<div class="clear">
|
||||
@ -44,16 +31,7 @@ end
|
||||
<%= upload.major_version %>.<%= upload.minor_version + 1 %> <%= l(:option_version_minor) %><br />
|
||||
<%= radio_button_tag("commited_files[#{i}][version]", 2) %>
|
||||
<%= upload.major_version + 1 %>.0 <%= l(:option_version_major) %><br />
|
||||
</div>
|
||||
<p>
|
||||
<%= label_tag("commited_files[#{i}][workflow]", l(:label_workflow) + ":") %>
|
||||
<%= select_tag("commited_files[#{i}][workflow]",
|
||||
options_for_select([
|
||||
[l(:option_workflow_none), nil],
|
||||
[l(:option_workflow_waiting_for_approval), 1],
|
||||
[l(:option_workflow_approved), 2]],
|
||||
:selected => selected_workflow, :disabled => disabled_workflow)) %>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="splitcontentright clear">
|
||||
<p>
|
||||
|
||||
@ -27,15 +27,7 @@
|
||||
<p>
|
||||
<%= label_tag("", l(:label_version) + ":") %>
|
||||
<%= upload.major_version %>.<%= upload.minor_version %>
|
||||
</p>
|
||||
<p>
|
||||
<%= label_tag("", l(:label_workflow) + ":") %>
|
||||
<%= case upload.workflow
|
||||
when 1 then l(:option_workflow_waiting_for_approval)
|
||||
when 2 then l(:option_workflow_approved)
|
||||
else l(:option_workflow_none)
|
||||
end %>
|
||||
</p>
|
||||
</p>
|
||||
</div>
|
||||
<div class="splitcontentright clear">
|
||||
<p>
|
||||
|
||||
27
app/views/dmsf_workflows/_action.html.erb
Normal file
@ -0,0 +1,27 @@
|
||||
<h3 class="title"><%= l(:label_dmsf_workflow) %></h3>
|
||||
|
||||
<%= form_tag({:controller => 'dmsf_workflows', :action => 'new_action'},
|
||||
:method => :post,
|
||||
:id => 'new-action-form') do %>
|
||||
|
||||
<%= hidden_field_tag :dmsf_workflow_step_assignment_id, params[:dmsf_workflow_step_assignment_id] %>
|
||||
<%= hidden_field_tag :dmsf_file_revision_id, params[:dmsf_file_revision_id] %>
|
||||
<p><label><%= radio_button_tag 'step_action', DmsfWorkflowStepAction::ACTION_APPROVE, true %> <%= l(:label_dmsf_wokflow_action_approve) %></label><br/></p>
|
||||
|
||||
<p>
|
||||
<label><%= radio_button_tag 'step_action', DmsfWorkflowStepAction::ACTION_REJECT %> <%= l(:label_dmsf_wokflow_action_reject) %></label><br/>
|
||||
<%= text_area_tag :note, '', :placeholder => l(:message_dmsf_wokflow_note), :size => '38x2' %>
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<%= label_tag 'delegate', l(:label_dmsf_wokflow_action_delegate) %><br/>
|
||||
<%= text_field_tag 'user_search', nil %>
|
||||
<%= javascript_tag "observeSearchfield('user_search', 'users_for_delegate', '#{ escape_javascript autocomplete_for_user_dmsf_workflow_path(@workflow, :dmsf_workflow_step_assignment_id => params[:dmsf_workflow_step_assignment_id], :dmsf_file_revision_id => params[:dmsf_file_revision_id]) }')" %>
|
||||
<%= content_tag('div', principals_radio_button_tags('step_action', @workflow.delegates(nil, params[:dmsf_workflow_step_assignment_id], params[:dmsf_file_revision_id], nil)), :id => 'users_for_delegate') %>
|
||||
</p>
|
||||
|
||||
<p class="buttons">
|
||||
<%= submit_tag l(:button_submit), :name => 'commit', :onclick => 'hideModal(this);' %>
|
||||
<%= submit_tag l(:button_cancel), :name => 'commit', :onclick => 'hideModal(this);' %>
|
||||
</p>
|
||||
<% end %>
|
||||
16
app/views/dmsf_workflows/_assign.html.erb
Normal file
@ -0,0 +1,16 @@
|
||||
<h3 class="title"><%= l(:label_dmsf_workflow) %></h3>
|
||||
<%= form_tag({:controller => 'dmsf_workflows', :action => 'assignment'},
|
||||
:method => :post,
|
||||
:id => 'assignment-form') do %>
|
||||
<%= hidden_field_tag :dmsf_file_revision_id, params[:dmsf_file_revision_id] %>
|
||||
<p>
|
||||
<%= label_tag('workflow', l(:label_workflow) + ':') %>
|
||||
<%= select_tag(
|
||||
'dmsf_workflow_id',
|
||||
dmsf_workflows_for_select(@project, nil))%>
|
||||
</p>
|
||||
<p class="buttons">
|
||||
<%= submit_tag l(:button_submit), :name => 'commit', :onclick => 'hideModal(this);' %>
|
||||
<%= submit_tag l(:button_cancel), :name => 'commit', :onclick => 'hideModal(this);' %>
|
||||
</p>
|
||||
<% end %>
|
||||
57
app/views/dmsf_workflows/_log.html.erb
Normal file
@ -0,0 +1,57 @@
|
||||
<h3 class="title"><%= l(:title_dmsf_workflow_log) %></h3>
|
||||
<p>
|
||||
<% if params[:dmsf_file_revision_id].present? %>
|
||||
<% revision = DmsfFileRevision.find_by_id(params[:dmsf_file_revision_id]) %>
|
||||
<% if revision %>
|
||||
<div class="log_header_box">
|
||||
<div class="log_header_left">
|
||||
<%= label_tag 'workflow_name', "#{l(:field_name)}: " %>
|
||||
<%= link_to @workflow.name, edit_dmsf_workflow_path(@workflow) %>
|
||||
</div>
|
||||
<div>
|
||||
<%= label_tag 'workflow_status', "#{l(:field_status)}: " %>
|
||||
<%= revision.workflow_str false %>
|
||||
</div>
|
||||
</div>
|
||||
<div class="tab-content" id="tab-content-members">
|
||||
<table class="list">
|
||||
<thead><tr>
|
||||
<th><%= l(:label_dmsf_workflow_step) %></th>
|
||||
<th><%= l(:label_user) %> </th>
|
||||
<th><%= l(:label_action) %></th>
|
||||
<th><%= l(:label_note) %></th>
|
||||
<th><%=l(:label_date)%></th>
|
||||
</tr></thead>
|
||||
<tbody>
|
||||
<tr id="step-0" class="odd">
|
||||
<td class="step"></td>
|
||||
<td class="user"><%= link_to_user User.find_by_id(revision.dmsf_workflow_assigned_by) if revision.dmsf_workflow_assigned_by %></td>
|
||||
<td class="action"><%= DmsfWorkflowStepAction.action_str(DmsfWorkflowStepAction::ACTION_ASSIGN) %></td>
|
||||
<td class="note"></td>
|
||||
<td class="date" align="center"><%= format_time(revision.dmsf_workflow_assigned_at) if revision.dmsf_workflow_assigned_at %></td>
|
||||
</tr>
|
||||
<tr id="step-1" class="even">
|
||||
<td class="step"></td>
|
||||
<td class="user"><%= link_to_user User.find_by_id(revision.dmsf_workflow_started_by) if revision.dmsf_workflow_started_by %></td>
|
||||
<td class="action"><%= DmsfWorkflowStepAction.action_str(DmsfWorkflowStepAction::ACTION_START) %></td>
|
||||
<td class="note"></td>
|
||||
<td class="date" align="center"><%= format_time(revision.dmsf_workflow_started_at) if revision.dmsf_workflow_started_at %></td>
|
||||
</tr>
|
||||
<% sql = "SELECT c.action, c.note, c.created_at, c.author_id, a.user_id, s.step FROM dmsf_workflow_step_actions c RIGHT JOIN dmsf_workflow_step_assignments a ON a.id = c.dmsf_workflow_step_assignment_id JOIN dmsf_workflow_steps s ON s.id = a.dmsf_workflow_step_id WHERE a.dmsf_file_revision_id = #{revision.id} ORDER BY s.step, c.created_at" %>
|
||||
<% result = DmsfWorkflowStep.connection.execute sql %>
|
||||
<% result.each_with_index do |row, i| %>
|
||||
<tr id="step-<%= i + 2 %> " class="<%= cycle 'odd', 'even' %>">
|
||||
<td class="step"><%= row[5] %></td>
|
||||
<td class="user"><%= link_to_user User.find_by_id(row[3].present? ? row[3] : row[4]) %></td>
|
||||
<td class="action"><%= DmsfWorkflowStepAction.action_str(row[0]) %></td>
|
||||
<td class="note"><%= row[1] %></td>
|
||||
<td class="date" align="center"><%= format_time(row[2]) if row[2].present? %></td>
|
||||
</tr>
|
||||
<% end; reset_cycle %>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<% end %>
|
||||
<% end %>
|
||||
</p>
|
||||
|
||||
32
app/views/dmsf_workflows/_main.html.erb
Normal file
@ -0,0 +1,32 @@
|
||||
<% @workflows = DmsfWorkflow.where(:project_id => @project.id) if @project && @workflows.nil? %>
|
||||
|
||||
<div class="contextual">
|
||||
<% if @project %>
|
||||
<%= link_to l(:label_dmsf_workflow_new), new_dmsf_workflow_path(:project_id => @project.id), :class => 'icon icon-add' %>
|
||||
<% else %>
|
||||
<%= link_to l(:label_dmsf_workflow_new), new_dmsf_workflow_path, :class => 'icon icon-add' %>
|
||||
<% end %>
|
||||
</div>
|
||||
|
||||
<h2><%=l(:label_dmsf_workflow_plural)%></h2>
|
||||
|
||||
<table class="list">
|
||||
<thead><tr>
|
||||
<th><%=l(:field_name)%></th>
|
||||
<th></th>
|
||||
</tr></thead>
|
||||
<tbody>
|
||||
<% for workflow in @workflows %>
|
||||
<tr id="workflow-<%= workflow.id %>" class="<%= cycle('odd', 'even') %>">
|
||||
<td><%= link_to(h(workflow.name), edit_dmsf_workflow_path(workflow)) %></td>
|
||||
<td class="buttons">
|
||||
<%= delete_link dmsf_workflow_path(workflow) %>
|
||||
</td>
|
||||
</tr>
|
||||
<% end %>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<% if @workflow_pages %>
|
||||
<p class="pagination"><%= pagination_links_full @workflow_pages %></p>
|
||||
<% end %>
|
||||
81
app/views/dmsf_workflows/_steps.html.erb
Normal file
@ -0,0 +1,81 @@
|
||||
<% if @workflow.project %>
|
||||
<h2><%= link_to l(:label_dmsf_workflow_plural), settings_project_path(@project, :tab => 'dmsf') %> » <%=h @workflow %></h2>
|
||||
<% else %>
|
||||
<h2><%= link_to l(:label_dmsf_workflow_plural), dmsf_workflows_path %> » <%=h @workflow %></h2>
|
||||
<% end %>
|
||||
|
||||
<% if @project %>
|
||||
<div class="contextual">
|
||||
<%= link_to 'Action', action_dmsf_workflow_path(:project_id => @project.id, :id => @workflow, :step => 1), :remote => true %>
|
||||
</div>
|
||||
<% end %>
|
||||
|
||||
<%= labelled_form_for @workflow do |f| %>
|
||||
<%= error_messages_for 'workflow' %>
|
||||
<div class="box tabular">
|
||||
<p><%= f.text_field :name, :required => true %><%= submit_tag l(:button_save) %></p>
|
||||
</div>
|
||||
<% end %>
|
||||
|
||||
<div class="tab-content" id="tab-content-members">
|
||||
|
||||
<div class="splitcontentleft">
|
||||
<% if @workflow.steps.any? %>
|
||||
<table class="list steps">
|
||||
<thead><tr>
|
||||
<th><%= l(:label_dmsf_workflow_step) %></th>
|
||||
<th><%= l(:label_dmsf_workflow_approval_plural) %></th>
|
||||
<th><%=l(:button_sort)%></th>
|
||||
<th style="width:15%"></th>
|
||||
</tr></thead>
|
||||
<tbody>
|
||||
<% @workflow.steps.each do |step| %>
|
||||
<tr id="step-<%= step %>" class="<%= cycle 'odd', 'even' %> step">
|
||||
<td class="step"><%= step %></td>
|
||||
<td class="approval">
|
||||
<% @workflow.approvals(step).each_with_index do |approval, i| %>
|
||||
<% if i != 0 %>
|
||||
<b><%= approval.soperator %></b> 
|
||||
<% end %>
|
||||
<%= link_to_user approval.user %>
|
||||
<% end %>
|
||||
</td>
|
||||
<td align="center" style="width:15%;">
|
||||
<%= reorder_links('workflow_step', {:action => 'edit', :id => @workflow, :step => step}, :put) %>
|
||||
</td>
|
||||
<td class="buttons">
|
||||
<%= delete_link edit_dmsf_workflow_path(@workflow, :step => step) %>
|
||||
</td>
|
||||
</tr>
|
||||
<% end; reset_cycle %>
|
||||
</tbody>
|
||||
</table>
|
||||
<% else %>
|
||||
<p class="nodata"><%= l(:label_no_data) %></p>
|
||||
<% end %>
|
||||
</div>
|
||||
|
||||
<div class="splitcontentright">
|
||||
<%= form_for(@workflow, :url => edit_dmsf_workflow_path(@workflow),
|
||||
:html => {:method => :post}) do |f| %>
|
||||
<fieldset><legend><%=l(:label_user_new)%></legend>
|
||||
|
||||
<p><%= label_tag 'user_search', l(:label_user_search) %><%= text_field_tag 'user_search', nil %></p>
|
||||
<%= javascript_tag "observeSearchfield('user_search', 'users', '#{ escape_javascript autocomplete_for_user_dmsf_workflow_path(@workflow, :dmsf_workflow_step_assignment_id => nil, :dmsf_file_revision_id => nil, :project_id => @project ? @project.id : nil) }')" %>
|
||||
|
||||
<div id="users">
|
||||
<%= render_principals_for_new_dmsf_workflow_users(@workflow, nil, nil) %>
|
||||
</div>
|
||||
|
||||
<p>
|
||||
<%= l(:label_dmsf_workflow_step) %>
|
||||
<%= select_tag 'step',
|
||||
dmsf_workflow_steps_options_for_select(@workflow.steps),
|
||||
:id => 'selected_step', :style => "width:100px" %>
|
||||
</p>
|
||||
<p><%= submit_tag l(:dmsf_and) %> <%= submit_tag l(:dmsf_or) %></p>
|
||||
</fieldset>
|
||||
<% end %>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
3
app/views/dmsf_workflows/action.js.erb
Normal file
@ -0,0 +1,3 @@
|
||||
$('#ajax-modal').html('<%= escape_javascript(render :partial => 'action', :locals => {:workflow => @workflow}) %>');
|
||||
showModal('ajax-modal', '400px');
|
||||
$('#ajax-modal').addClass('new-action');
|
||||
1
app/views/dmsf_workflows/add_step.html.erb
Normal file
@ -0,0 +1 @@
|
||||
<%= render 'steps' %>
|
||||
3
app/views/dmsf_workflows/assign.js.erb
Normal file
@ -0,0 +1,3 @@
|
||||
$('#ajax-modal').html('<%= escape_javascript(render :partial => 'assign', :locals => {:workflow => @workflow}) %>');
|
||||
showModal('ajax-modal', '400px');
|
||||
$('#ajax-modal').addClass('assignment');
|
||||
1
app/views/dmsf_workflows/autocomplete_for_user.html.erb
Normal file
@ -0,0 +1 @@
|
||||
<%= render_principals_for_new_dmsf_workflow_users(@workflow, params[:dmsf_workflow_step_assignment_id], params[:dmsf_file_revision_id]) %>
|
||||
1
app/views/dmsf_workflows/edit.html.erb
Normal file
@ -0,0 +1 @@
|
||||
<%= render 'steps' %>
|
||||
1
app/views/dmsf_workflows/index.html.erb
Normal file
@ -0,0 +1 @@
|
||||
<%= render 'main' %>
|
||||
3
app/views/dmsf_workflows/log.js.erb
Normal file
@ -0,0 +1,3 @@
|
||||
$('#ajax-modal').html('<%= escape_javascript(render :partial => 'log', :locals => {:workflow => @workflow}) %>');
|
||||
showModal('ajax-modal', '640px');
|
||||
$('#ajax-modal').addClass('workflow-log');
|
||||
12
app/views/dmsf_workflows/new.html.erb
Normal file
@ -0,0 +1,12 @@
|
||||
<h2><%= link_to l(:label_dmsf_workflow_plural), dmsf_workflows_path %> » <%=l(:label_dmsf_workflow_new)%></h2>
|
||||
|
||||
<%= labelled_form_for @workflow do |f| %>
|
||||
<%= error_messages_for 'workflow' %>
|
||||
<div class="box tabular">
|
||||
<p><%= f.text_field :name, :required => true %></p>
|
||||
<% if params[:project_id] %>
|
||||
<p><%= hidden_field_tag :project_id, params[:project_id] %></p>
|
||||
<% end %>
|
||||
</div>
|
||||
<%= submit_tag l(:button_create) %>
|
||||
<% end %>
|
||||
1
app/views/dmsf_workflows/remove_step.html.erb
Normal file
@ -0,0 +1 @@
|
||||
<%= render 'steps' %>
|
||||
1
app/views/dmsf_workflows/reorder_steps.html.erb
Normal file
@ -0,0 +1 @@
|
||||
<%= render 'steps' %>
|
||||
|
Before Width: | Height: | Size: 535 B |
|
Before Width: | Height: | Size: 262 B After Width: | Height: | Size: 752 B |
|
Before Width: | Height: | Size: 641 B |
BIN
assets/images/draft.png
Normal file
|
After Width: | Height: | Size: 459 B |
BIN
assets/images/none.png
Normal file
|
After Width: | Height: | Size: 776 B |
BIN
assets/images/rejected.png
Normal file
|
After Width: | Height: | Size: 631 B |
BIN
assets/images/rev_delete.png
Normal file
|
After Width: | Height: | Size: 647 B |
BIN
assets/images/rev_download.png
Normal file
|
After Width: | Height: | Size: 656 B |
BIN
assets/images/rev_downloads.png
Normal file
|
After Width: | Height: | Size: 642 B |
BIN
assets/images/ticket_go.png
Normal file
|
After Width: | Height: | Size: 608 B |
BIN
assets/images/waiting_for_approval.png
Normal file
|
After Width: | Height: | Size: 630 B |
|
Before Width: | Height: | Size: 412 B |
|
Before Width: | Height: | Size: 1.4 KiB |
@ -14,17 +14,17 @@ table.entries {
|
||||
}
|
||||
|
||||
table.entries td.modified {
|
||||
min-width: 140px;
|
||||
width: 140px;
|
||||
min-width: 104px;
|
||||
width: 104px;
|
||||
}
|
||||
|
||||
table.entries td.actions {
|
||||
min-width: 108px;
|
||||
width: 108px;
|
||||
min-width: 116px;
|
||||
width: 116px;
|
||||
}
|
||||
|
||||
table.entries td.title {
|
||||
width: 50%;
|
||||
width: 40%;
|
||||
}
|
||||
|
||||
table.entries th.check, table.entries td.check {
|
||||
@ -136,6 +136,11 @@ td.version img {
|
||||
vertical-align:text-top;
|
||||
}
|
||||
|
||||
td.workflow {
|
||||
font-size: 0.8em;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
/* DMSF entries list icons */
|
||||
|
||||
div.right_icon_box {
|
||||
@ -233,3 +238,48 @@ table.access-table tbody td, table.access-table tbody tr:hover td {
|
||||
display: block;
|
||||
float: left;
|
||||
}
|
||||
|
||||
/* Approval workflow */
|
||||
#admin-menu a.approvalworkflows { background-image: url(../images/ticket_go.png); }
|
||||
#users_for_delegate {height: 200px; overflow:auto;}
|
||||
#users_for_delegate label {display: block;}
|
||||
|
||||
.revision_box{
|
||||
padding: 0px 0px 0px 0px;
|
||||
margin-bottom: 10px;
|
||||
background-color:#f6f6f6;
|
||||
color:#505050;
|
||||
line-height:1.5em;
|
||||
}
|
||||
|
||||
div.revision_box .ui-widget-header {
|
||||
font-weight: normal;
|
||||
}
|
||||
|
||||
table.list td.note {
|
||||
width: 30%;
|
||||
}
|
||||
|
||||
table.list td.step, td.date {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.log_header_box{
|
||||
padding:6px;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
.log_header_left {
|
||||
width: 50%;
|
||||
float: left;
|
||||
}
|
||||
|
||||
.log_header_box label{
|
||||
font-weight: bold;
|
||||
margin-left: 0px;
|
||||
margin-right: 3px;
|
||||
padding: 3px 0 3px 0;
|
||||
}
|
||||
|
||||
.modal a, a:link, a:visited{ color: #169; text-decoration: none; }
|
||||
.modal a:hover, a:active{ color: #c61a1a; text-decoration: underline;}
|
||||
.modal{ font-size: 12px}
|
||||
|
After Width: | Height: | Size: 260 B |
|
After Width: | Height: | Size: 251 B |
|
After Width: | Height: | Size: 178 B |
|
After Width: | Height: | Size: 113 B |
|
After Width: | Height: | Size: 104 B |
|
After Width: | Height: | Size: 3.9 KiB |
|
After Width: | Height: | Size: 90 B |
|
After Width: | Height: | Size: 126 B |
BIN
assets/stylesheets/jquery-ui/images/ui-icons_759fcf_256x240.png
Normal file
|
After Width: | Height: | Size: 4.3 KiB |
BIN
assets/stylesheets/jquery-ui/images/ui-icons_ffd27a_256x240.png
Normal file
|
After Width: | Height: | Size: 4.3 KiB |
BIN
assets/stylesheets/jquery-ui/images/ui-icons_ffffff_256x240.png
Normal file
|
After Width: | Height: | Size: 4.3 KiB |
578
assets/stylesheets/jquery-ui/jquery-ui-1.8.13.css
vendored
@ -1,578 +0,0 @@
|
||||
/*
|
||||
* jQuery UI CSS Framework 1.8.13
|
||||
*
|
||||
* Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
|
||||
* Dual licensed under the MIT or GPL Version 2 licenses.
|
||||
* http://jquery.org/license
|
||||
*
|
||||
* http://docs.jquery.com/UI/Theming/API
|
||||
*/
|
||||
|
||||
/* Layout helpers
|
||||
----------------------------------*/
|
||||
.ui-helper-hidden { display: none; }
|
||||
.ui-helper-hidden-accessible { position: absolute !important; clip: rect(1px 1px 1px 1px); clip: rect(1px,1px,1px,1px); }
|
||||
.ui-helper-reset { margin: 0; padding: 0; border: 0; outline: 0; line-height: 1.3; text-decoration: none; font-size: 100%; list-style: none; }
|
||||
.ui-helper-clearfix:after { content: "."; display: block; height: 0; clear: both; visibility: hidden; }
|
||||
.ui-helper-clearfix { display: inline-block; }
|
||||
/* required comment for clearfix to work in Opera \*/
|
||||
* html .ui-helper-clearfix { height:1%; }
|
||||
.ui-helper-clearfix { display:block; }
|
||||
/* end clearfix */
|
||||
.ui-helper-zfix { width: 100%; height: 100%; top: 0; left: 0; position: absolute; opacity: 0; filter:Alpha(Opacity=0); }
|
||||
|
||||
|
||||
/* Interaction Cues
|
||||
----------------------------------*/
|
||||
.ui-state-disabled { cursor: default !important; }
|
||||
|
||||
|
||||
/* Icons
|
||||
----------------------------------*/
|
||||
|
||||
/* states and images */
|
||||
.ui-icon { display: block; text-indent: -99999px; overflow: hidden; background-repeat: no-repeat; }
|
||||
|
||||
|
||||
/* Misc visuals
|
||||
----------------------------------*/
|
||||
|
||||
/* Overlays */
|
||||
.ui-widget-overlay { position: absolute; top: 0; left: 0; width: 100%; height: 100%; }
|
||||
|
||||
|
||||
/*
|
||||
* jQuery UI CSS Framework 1.8.13
|
||||
*
|
||||
* Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
|
||||
* Dual licensed under the MIT or GPL Version 2 licenses.
|
||||
* http://jquery.org/license
|
||||
*
|
||||
* http://docs.jquery.com/UI/Theming/API
|
||||
*
|
||||
* To view and modify this theme, visit http://jqueryui.com/themeroller/?ffDefault=Verdana,Arial,sans-serif&fwDefault=normal&fsDefault=1.1em&cornerRadius=4px&bgColorHeader=cccccc&bgTextureHeader=03_highlight_soft.png&bgImgOpacityHeader=75&borderColorHeader=aaaaaa&fcHeader=222222&iconColorHeader=222222&bgColorContent=ffffff&bgTextureContent=01_flat.png&bgImgOpacityContent=75&borderColorContent=aaaaaa&fcContent=222222&iconColorContent=222222&bgColorDefault=e6e6e6&bgTextureDefault=02_glass.png&bgImgOpacityDefault=75&borderColorDefault=d3d3d3&fcDefault=555555&iconColorDefault=888888&bgColorHover=dadada&bgTextureHover=02_glass.png&bgImgOpacityHover=75&borderColorHover=999999&fcHover=212121&iconColorHover=454545&bgColorActive=ffffff&bgTextureActive=02_glass.png&bgImgOpacityActive=65&borderColorActive=aaaaaa&fcActive=212121&iconColorActive=454545&bgColorHighlight=fbf9ee&bgTextureHighlight=02_glass.png&bgImgOpacityHighlight=55&borderColorHighlight=fcefa1&fcHighlight=363636&iconColorHighlight=2e83ff&bgColorError=fef1ec&bgTextureError=02_glass.png&bgImgOpacityError=95&borderColorError=cd0a0a&fcError=cd0a0a&iconColorError=cd0a0a&bgColorOverlay=aaaaaa&bgTextureOverlay=01_flat.png&bgImgOpacityOverlay=0&opacityOverlay=30&bgColorShadow=aaaaaa&bgTextureShadow=01_flat.png&bgImgOpacityShadow=0&opacityShadow=30&thicknessShadow=8px&offsetTopShadow=-8px&offsetLeftShadow=-8px&cornerRadiusShadow=8px
|
||||
*/
|
||||
|
||||
|
||||
/* Component containers
|
||||
----------------------------------*/
|
||||
.ui-widget { font-family: Verdana,Arial,sans-serif; font-size: 1.1em; }
|
||||
.ui-widget .ui-widget { font-size: 1em; }
|
||||
.ui-widget input, .ui-widget select, .ui-widget textarea, .ui-widget button { font-family: Verdana,Arial,sans-serif; font-size: 1em; }
|
||||
.ui-widget-content { border: 1px solid #aaaaaa; background: #ffffff url(images/ui-bg_flat_75_ffffff_40x100.png) 50% 50% repeat-x; color: #222222; }
|
||||
.ui-widget-content a { color: #222222; }
|
||||
.ui-widget-header { border: 1px solid #aaaaaa; background: #cccccc url(images/ui-bg_highlight-soft_75_cccccc_1x100.png) 50% 50% repeat-x; color: #222222; font-weight: bold; }
|
||||
.ui-widget-header a { color: #222222; }
|
||||
|
||||
/* Interaction states
|
||||
----------------------------------*/
|
||||
.ui-state-default, .ui-widget-content .ui-state-default, .ui-widget-header .ui-state-default { border: 1px solid #d3d3d3; background: #e6e6e6 url(images/ui-bg_glass_75_e6e6e6_1x400.png) 50% 50% repeat-x; font-weight: normal; color: #555555; }
|
||||
.ui-state-default a, .ui-state-default a:link, .ui-state-default a:visited { color: #555555; text-decoration: none; }
|
||||
.ui-state-hover, .ui-widget-content .ui-state-hover, .ui-widget-header .ui-state-hover, .ui-state-focus, .ui-widget-content .ui-state-focus, .ui-widget-header .ui-state-focus { border: 1px solid #999999; background: #dadada url(images/ui-bg_glass_75_dadada_1x400.png) 50% 50% repeat-x; font-weight: normal; color: #212121; }
|
||||
.ui-state-hover a, .ui-state-hover a:hover { color: #212121; text-decoration: none; }
|
||||
.ui-state-active, .ui-widget-content .ui-state-active, .ui-widget-header .ui-state-active { border: 1px solid #aaaaaa; background: #ffffff url(images/ui-bg_glass_65_ffffff_1x400.png) 50% 50% repeat-x; font-weight: normal; color: #212121; }
|
||||
.ui-state-active a, .ui-state-active a:link, .ui-state-active a:visited { color: #212121; text-decoration: none; }
|
||||
.ui-widget :active { outline: none; }
|
||||
|
||||
/* Interaction Cues
|
||||
----------------------------------*/
|
||||
.ui-state-highlight, .ui-widget-content .ui-state-highlight, .ui-widget-header .ui-state-highlight {border: 1px solid #fcefa1; background: #fbf9ee url(images/ui-bg_glass_55_fbf9ee_1x400.png) 50% 50% repeat-x; color: #363636; }
|
||||
.ui-state-highlight a, .ui-widget-content .ui-state-highlight a,.ui-widget-header .ui-state-highlight a { color: #363636; }
|
||||
.ui-state-error, .ui-widget-content .ui-state-error, .ui-widget-header .ui-state-error {border: 1px solid #cd0a0a; background: #fef1ec url(images/ui-bg_glass_95_fef1ec_1x400.png) 50% 50% repeat-x; color: #cd0a0a; }
|
||||
.ui-state-error a, .ui-widget-content .ui-state-error a, .ui-widget-header .ui-state-error a { color: #cd0a0a; }
|
||||
.ui-state-error-text, .ui-widget-content .ui-state-error-text, .ui-widget-header .ui-state-error-text { color: #cd0a0a; }
|
||||
.ui-priority-primary, .ui-widget-content .ui-priority-primary, .ui-widget-header .ui-priority-primary { font-weight: bold; }
|
||||
.ui-priority-secondary, .ui-widget-content .ui-priority-secondary, .ui-widget-header .ui-priority-secondary { opacity: .7; filter:Alpha(Opacity=70); font-weight: normal; }
|
||||
.ui-state-disabled, .ui-widget-content .ui-state-disabled, .ui-widget-header .ui-state-disabled { opacity: .35; filter:Alpha(Opacity=35); background-image: none; }
|
||||
|
||||
/* Icons
|
||||
----------------------------------*/
|
||||
|
||||
/* states and images */
|
||||
.ui-icon { width: 16px; height: 16px; background-image: url(images/ui-icons_222222_256x240.png); }
|
||||
.ui-widget-content .ui-icon {background-image: url(images/ui-icons_222222_256x240.png); }
|
||||
.ui-widget-header .ui-icon {background-image: url(images/ui-icons_222222_256x240.png); }
|
||||
.ui-state-default .ui-icon { background-image: url(images/ui-icons_888888_256x240.png); }
|
||||
.ui-state-hover .ui-icon, .ui-state-focus .ui-icon {background-image: url(images/ui-icons_454545_256x240.png); }
|
||||
.ui-state-active .ui-icon {background-image: url(images/ui-icons_454545_256x240.png); }
|
||||
.ui-state-highlight .ui-icon {background-image: url(images/ui-icons_2e83ff_256x240.png); }
|
||||
.ui-state-error .ui-icon, .ui-state-error-text .ui-icon {background-image: url(images/ui-icons_cd0a0a_256x240.png); }
|
||||
|
||||
/* positioning */
|
||||
.ui-icon-carat-1-n { background-position: 0 0; }
|
||||
.ui-icon-carat-1-ne { background-position: -16px 0; }
|
||||
.ui-icon-carat-1-e { background-position: -32px 0; }
|
||||
.ui-icon-carat-1-se { background-position: -48px 0; }
|
||||
.ui-icon-carat-1-s { background-position: -64px 0; }
|
||||
.ui-icon-carat-1-sw { background-position: -80px 0; }
|
||||
.ui-icon-carat-1-w { background-position: -96px 0; }
|
||||
.ui-icon-carat-1-nw { background-position: -112px 0; }
|
||||
.ui-icon-carat-2-n-s { background-position: -128px 0; }
|
||||
.ui-icon-carat-2-e-w { background-position: -144px 0; }
|
||||
.ui-icon-triangle-1-n { background-position: 0 -16px; }
|
||||
.ui-icon-triangle-1-ne { background-position: -16px -16px; }
|
||||
.ui-icon-triangle-1-e { background-position: -32px -16px; }
|
||||
.ui-icon-triangle-1-se { background-position: -48px -16px; }
|
||||
.ui-icon-triangle-1-s { background-position: -64px -16px; }
|
||||
.ui-icon-triangle-1-sw { background-position: -80px -16px; }
|
||||
.ui-icon-triangle-1-w { background-position: -96px -16px; }
|
||||
.ui-icon-triangle-1-nw { background-position: -112px -16px; }
|
||||
.ui-icon-triangle-2-n-s { background-position: -128px -16px; }
|
||||
.ui-icon-triangle-2-e-w { background-position: -144px -16px; }
|
||||
.ui-icon-arrow-1-n { background-position: 0 -32px; }
|
||||
.ui-icon-arrow-1-ne { background-position: -16px -32px; }
|
||||
.ui-icon-arrow-1-e { background-position: -32px -32px; }
|
||||
.ui-icon-arrow-1-se { background-position: -48px -32px; }
|
||||
.ui-icon-arrow-1-s { background-position: -64px -32px; }
|
||||
.ui-icon-arrow-1-sw { background-position: -80px -32px; }
|
||||
.ui-icon-arrow-1-w { background-position: -96px -32px; }
|
||||
.ui-icon-arrow-1-nw { background-position: -112px -32px; }
|
||||
.ui-icon-arrow-2-n-s { background-position: -128px -32px; }
|
||||
.ui-icon-arrow-2-ne-sw { background-position: -144px -32px; }
|
||||
.ui-icon-arrow-2-e-w { background-position: -160px -32px; }
|
||||
.ui-icon-arrow-2-se-nw { background-position: -176px -32px; }
|
||||
.ui-icon-arrowstop-1-n { background-position: -192px -32px; }
|
||||
.ui-icon-arrowstop-1-e { background-position: -208px -32px; }
|
||||
.ui-icon-arrowstop-1-s { background-position: -224px -32px; }
|
||||
.ui-icon-arrowstop-1-w { background-position: -240px -32px; }
|
||||
.ui-icon-arrowthick-1-n { background-position: 0 -48px; }
|
||||
.ui-icon-arrowthick-1-ne { background-position: -16px -48px; }
|
||||
.ui-icon-arrowthick-1-e { background-position: -32px -48px; }
|
||||
.ui-icon-arrowthick-1-se { background-position: -48px -48px; }
|
||||
.ui-icon-arrowthick-1-s { background-position: -64px -48px; }
|
||||
.ui-icon-arrowthick-1-sw { background-position: -80px -48px; }
|
||||
.ui-icon-arrowthick-1-w { background-position: -96px -48px; }
|
||||
.ui-icon-arrowthick-1-nw { background-position: -112px -48px; }
|
||||
.ui-icon-arrowthick-2-n-s { background-position: -128px -48px; }
|
||||
.ui-icon-arrowthick-2-ne-sw { background-position: -144px -48px; }
|
||||
.ui-icon-arrowthick-2-e-w { background-position: -160px -48px; }
|
||||
.ui-icon-arrowthick-2-se-nw { background-position: -176px -48px; }
|
||||
.ui-icon-arrowthickstop-1-n { background-position: -192px -48px; }
|
||||
.ui-icon-arrowthickstop-1-e { background-position: -208px -48px; }
|
||||
.ui-icon-arrowthickstop-1-s { background-position: -224px -48px; }
|
||||
.ui-icon-arrowthickstop-1-w { background-position: -240px -48px; }
|
||||
.ui-icon-arrowreturnthick-1-w { background-position: 0 -64px; }
|
||||
.ui-icon-arrowreturnthick-1-n { background-position: -16px -64px; }
|
||||
.ui-icon-arrowreturnthick-1-e { background-position: -32px -64px; }
|
||||
.ui-icon-arrowreturnthick-1-s { background-position: -48px -64px; }
|
||||
.ui-icon-arrowreturn-1-w { background-position: -64px -64px; }
|
||||
.ui-icon-arrowreturn-1-n { background-position: -80px -64px; }
|
||||
.ui-icon-arrowreturn-1-e { background-position: -96px -64px; }
|
||||
.ui-icon-arrowreturn-1-s { background-position: -112px -64px; }
|
||||
.ui-icon-arrowrefresh-1-w { background-position: -128px -64px; }
|
||||
.ui-icon-arrowrefresh-1-n { background-position: -144px -64px; }
|
||||
.ui-icon-arrowrefresh-1-e { background-position: -160px -64px; }
|
||||
.ui-icon-arrowrefresh-1-s { background-position: -176px -64px; }
|
||||
.ui-icon-arrow-4 { background-position: 0 -80px; }
|
||||
.ui-icon-arrow-4-diag { background-position: -16px -80px; }
|
||||
.ui-icon-extlink { background-position: -32px -80px; }
|
||||
.ui-icon-newwin { background-position: -48px -80px; }
|
||||
.ui-icon-refresh { background-position: -64px -80px; }
|
||||
.ui-icon-shuffle { background-position: -80px -80px; }
|
||||
.ui-icon-transfer-e-w { background-position: -96px -80px; }
|
||||
.ui-icon-transferthick-e-w { background-position: -112px -80px; }
|
||||
.ui-icon-folder-collapsed { background-position: 0 -96px; }
|
||||
.ui-icon-folder-open { background-position: -16px -96px; }
|
||||
.ui-icon-document { background-position: -32px -96px; }
|
||||
.ui-icon-document-b { background-position: -48px -96px; }
|
||||
.ui-icon-note { background-position: -64px -96px; }
|
||||
.ui-icon-mail-closed { background-position: -80px -96px; }
|
||||
.ui-icon-mail-open { background-position: -96px -96px; }
|
||||
.ui-icon-suitcase { background-position: -112px -96px; }
|
||||
.ui-icon-comment { background-position: -128px -96px; }
|
||||
.ui-icon-person { background-position: -144px -96px; }
|
||||
.ui-icon-print { background-position: -160px -96px; }
|
||||
.ui-icon-trash { background-position: -176px -96px; }
|
||||
.ui-icon-locked { background-position: -192px -96px; }
|
||||
.ui-icon-unlocked { background-position: -208px -96px; }
|
||||
.ui-icon-bookmark { background-position: -224px -96px; }
|
||||
.ui-icon-tag { background-position: -240px -96px; }
|
||||
.ui-icon-home { background-position: 0 -112px; }
|
||||
.ui-icon-flag { background-position: -16px -112px; }
|
||||
.ui-icon-calendar { background-position: -32px -112px; }
|
||||
.ui-icon-cart { background-position: -48px -112px; }
|
||||
.ui-icon-pencil { background-position: -64px -112px; }
|
||||
.ui-icon-clock { background-position: -80px -112px; }
|
||||
.ui-icon-disk { background-position: -96px -112px; }
|
||||
.ui-icon-calculator { background-position: -112px -112px; }
|
||||
.ui-icon-zoomin { background-position: -128px -112px; }
|
||||
.ui-icon-zoomout { background-position: -144px -112px; }
|
||||
.ui-icon-search { background-position: -160px -112px; }
|
||||
.ui-icon-wrench { background-position: -176px -112px; }
|
||||
.ui-icon-gear { background-position: -192px -112px; }
|
||||
.ui-icon-heart { background-position: -208px -112px; }
|
||||
.ui-icon-star { background-position: -224px -112px; }
|
||||
.ui-icon-link { background-position: -240px -112px; }
|
||||
.ui-icon-cancel { background-position: 0 -128px; }
|
||||
.ui-icon-plus { background-position: -16px -128px; }
|
||||
.ui-icon-plusthick { background-position: -32px -128px; }
|
||||
.ui-icon-minus { background-position: -48px -128px; }
|
||||
.ui-icon-minusthick { background-position: -64px -128px; }
|
||||
.ui-icon-close { background-position: -80px -128px; }
|
||||
.ui-icon-closethick { background-position: -96px -128px; }
|
||||
.ui-icon-key { background-position: -112px -128px; }
|
||||
.ui-icon-lightbulb { background-position: -128px -128px; }
|
||||
.ui-icon-scissors { background-position: -144px -128px; }
|
||||
.ui-icon-clipboard { background-position: -160px -128px; }
|
||||
.ui-icon-copy { background-position: -176px -128px; }
|
||||
.ui-icon-contact { background-position: -192px -128px; }
|
||||
.ui-icon-image { background-position: -208px -128px; }
|
||||
.ui-icon-video { background-position: -224px -128px; }
|
||||
.ui-icon-script { background-position: -240px -128px; }
|
||||
.ui-icon-alert { background-position: 0 -144px; }
|
||||
.ui-icon-info { background-position: -16px -144px; }
|
||||
.ui-icon-notice { background-position: -32px -144px; }
|
||||
.ui-icon-help { background-position: -48px -144px; }
|
||||
.ui-icon-check { background-position: -64px -144px; }
|
||||
.ui-icon-bullet { background-position: -80px -144px; }
|
||||
.ui-icon-radio-off { background-position: -96px -144px; }
|
||||
.ui-icon-radio-on { background-position: -112px -144px; }
|
||||
.ui-icon-pin-w { background-position: -128px -144px; }
|
||||
.ui-icon-pin-s { background-position: -144px -144px; }
|
||||
.ui-icon-play { background-position: 0 -160px; }
|
||||
.ui-icon-pause { background-position: -16px -160px; }
|
||||
.ui-icon-seek-next { background-position: -32px -160px; }
|
||||
.ui-icon-seek-prev { background-position: -48px -160px; }
|
||||
.ui-icon-seek-end { background-position: -64px -160px; }
|
||||
.ui-icon-seek-start { background-position: -80px -160px; }
|
||||
/* ui-icon-seek-first is deprecated, use ui-icon-seek-start instead */
|
||||
.ui-icon-seek-first { background-position: -80px -160px; }
|
||||
.ui-icon-stop { background-position: -96px -160px; }
|
||||
.ui-icon-eject { background-position: -112px -160px; }
|
||||
.ui-icon-volume-off { background-position: -128px -160px; }
|
||||
.ui-icon-volume-on { background-position: -144px -160px; }
|
||||
.ui-icon-power { background-position: 0 -176px; }
|
||||
.ui-icon-signal-diag { background-position: -16px -176px; }
|
||||
.ui-icon-signal { background-position: -32px -176px; }
|
||||
.ui-icon-battery-0 { background-position: -48px -176px; }
|
||||
.ui-icon-battery-1 { background-position: -64px -176px; }
|
||||
.ui-icon-battery-2 { background-position: -80px -176px; }
|
||||
.ui-icon-battery-3 { background-position: -96px -176px; }
|
||||
.ui-icon-circle-plus { background-position: 0 -192px; }
|
||||
.ui-icon-circle-minus { background-position: -16px -192px; }
|
||||
.ui-icon-circle-close { background-position: -32px -192px; }
|
||||
.ui-icon-circle-triangle-e { background-position: -48px -192px; }
|
||||
.ui-icon-circle-triangle-s { background-position: -64px -192px; }
|
||||
.ui-icon-circle-triangle-w { background-position: -80px -192px; }
|
||||
.ui-icon-circle-triangle-n { background-position: -96px -192px; }
|
||||
.ui-icon-circle-arrow-e { background-position: -112px -192px; }
|
||||
.ui-icon-circle-arrow-s { background-position: -128px -192px; }
|
||||
.ui-icon-circle-arrow-w { background-position: -144px -192px; }
|
||||
.ui-icon-circle-arrow-n { background-position: -160px -192px; }
|
||||
.ui-icon-circle-zoomin { background-position: -176px -192px; }
|
||||
.ui-icon-circle-zoomout { background-position: -192px -192px; }
|
||||
.ui-icon-circle-check { background-position: -208px -192px; }
|
||||
.ui-icon-circlesmall-plus { background-position: 0 -208px; }
|
||||
.ui-icon-circlesmall-minus { background-position: -16px -208px; }
|
||||
.ui-icon-circlesmall-close { background-position: -32px -208px; }
|
||||
.ui-icon-squaresmall-plus { background-position: -48px -208px; }
|
||||
.ui-icon-squaresmall-minus { background-position: -64px -208px; }
|
||||
.ui-icon-squaresmall-close { background-position: -80px -208px; }
|
||||
.ui-icon-grip-dotted-vertical { background-position: 0 -224px; }
|
||||
.ui-icon-grip-dotted-horizontal { background-position: -16px -224px; }
|
||||
.ui-icon-grip-solid-vertical { background-position: -32px -224px; }
|
||||
.ui-icon-grip-solid-horizontal { background-position: -48px -224px; }
|
||||
.ui-icon-gripsmall-diagonal-se { background-position: -64px -224px; }
|
||||
.ui-icon-grip-diagonal-se { background-position: -80px -224px; }
|
||||
|
||||
|
||||
/* Misc visuals
|
||||
----------------------------------*/
|
||||
|
||||
/* Corner radius */
|
||||
.ui-corner-tl { -moz-border-radius-topleft: 4px; -webkit-border-top-left-radius: 4px; border-top-left-radius: 4px; }
|
||||
.ui-corner-tr { -moz-border-radius-topright: 4px; -webkit-border-top-right-radius: 4px; border-top-right-radius: 4px; }
|
||||
.ui-corner-bl { -moz-border-radius-bottomleft: 4px; -webkit-border-bottom-left-radius: 4px; border-bottom-left-radius: 4px; }
|
||||
.ui-corner-br { -moz-border-radius-bottomright: 4px; -webkit-border-bottom-right-radius: 4px; border-bottom-right-radius: 4px; }
|
||||
.ui-corner-top { -moz-border-radius-topleft: 4px; -webkit-border-top-left-radius: 4px; border-top-left-radius: 4px; -moz-border-radius-topright: 4px; -webkit-border-top-right-radius: 4px; border-top-right-radius: 4px; }
|
||||
.ui-corner-bottom { -moz-border-radius-bottomleft: 4px; -webkit-border-bottom-left-radius: 4px; border-bottom-left-radius: 4px; -moz-border-radius-bottomright: 4px; -webkit-border-bottom-right-radius: 4px; border-bottom-right-radius: 4px; }
|
||||
.ui-corner-right { -moz-border-radius-topright: 4px; -webkit-border-top-right-radius: 4px; border-top-right-radius: 4px; -moz-border-radius-bottomright: 4px; -webkit-border-bottom-right-radius: 4px; border-bottom-right-radius: 4px; }
|
||||
.ui-corner-left { -moz-border-radius-topleft: 4px; -webkit-border-top-left-radius: 4px; border-top-left-radius: 4px; -moz-border-radius-bottomleft: 4px; -webkit-border-bottom-left-radius: 4px; border-bottom-left-radius: 4px; }
|
||||
.ui-corner-all { -moz-border-radius: 4px; -webkit-border-radius: 4px; border-radius: 4px; }
|
||||
|
||||
/* Overlays */
|
||||
.ui-widget-overlay { background: #aaaaaa url(images/ui-bg_flat_0_aaaaaa_40x100.png) 50% 50% repeat-x; opacity: .30;filter:Alpha(Opacity=30); }
|
||||
.ui-widget-shadow { margin: -8px 0 0 -8px; padding: 8px; background: #aaaaaa url(images/ui-bg_flat_0_aaaaaa_40x100.png) 50% 50% repeat-x; opacity: .30;filter:Alpha(Opacity=30); -moz-border-radius: 8px; -webkit-border-radius: 8px; border-radius: 8px; }/*
|
||||
* jQuery UI Resizable 1.8.13
|
||||
*
|
||||
* Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
|
||||
* Dual licensed under the MIT or GPL Version 2 licenses.
|
||||
* http://jquery.org/license
|
||||
*
|
||||
* http://docs.jquery.com/UI/Resizable#theming
|
||||
*/
|
||||
.ui-resizable { position: relative;}
|
||||
.ui-resizable-handle { position: absolute;font-size: 0.1px;z-index: 99999; display: block;
|
||||
/* http://bugs.jqueryui.com/ticket/7233
|
||||
- Resizable: resizable handles fail to work in IE if transparent and content overlaps
|
||||
*/
|
||||
background-image:url(data:image/gif;base64,R0lGODlhAQABAAD/ACwAAAAAAQABAAACADs=);
|
||||
}
|
||||
.ui-resizable-disabled .ui-resizable-handle, .ui-resizable-autohide .ui-resizable-handle { display: none; }
|
||||
.ui-resizable-n { cursor: n-resize; height: 7px; width: 100%; top: -5px; left: 0; }
|
||||
.ui-resizable-s { cursor: s-resize; height: 7px; width: 100%; bottom: -5px; left: 0; }
|
||||
.ui-resizable-e { cursor: e-resize; width: 7px; right: -5px; top: 0; height: 100%; }
|
||||
.ui-resizable-w { cursor: w-resize; width: 7px; left: -5px; top: 0; height: 100%; }
|
||||
.ui-resizable-se { cursor: se-resize; width: 12px; height: 12px; right: 1px; bottom: 1px; }
|
||||
.ui-resizable-sw { cursor: sw-resize; width: 9px; height: 9px; left: -5px; bottom: -5px; }
|
||||
.ui-resizable-nw { cursor: nw-resize; width: 9px; height: 9px; left: -5px; top: -5px; }
|
||||
.ui-resizable-ne { cursor: ne-resize; width: 9px; height: 9px; right: -5px; top: -5px;}/*
|
||||
* jQuery UI Selectable 1.8.13
|
||||
*
|
||||
* Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
|
||||
* Dual licensed under the MIT or GPL Version 2 licenses.
|
||||
* http://jquery.org/license
|
||||
*
|
||||
* http://docs.jquery.com/UI/Selectable#theming
|
||||
*/
|
||||
.ui-selectable-helper { position: absolute; z-index: 100; border:1px dotted black; }
|
||||
/*
|
||||
* jQuery UI Accordion 1.8.13
|
||||
*
|
||||
* Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
|
||||
* Dual licensed under the MIT or GPL Version 2 licenses.
|
||||
* http://jquery.org/license
|
||||
*
|
||||
* http://docs.jquery.com/UI/Accordion#theming
|
||||
*/
|
||||
/* IE/Win - Fix animation bug - #4615 */
|
||||
.ui-accordion { width: 100%; }
|
||||
.ui-accordion .ui-accordion-header { cursor: pointer; position: relative; margin-top: 1px; zoom: 1; }
|
||||
.ui-accordion .ui-accordion-li-fix { display: inline; }
|
||||
.ui-accordion .ui-accordion-header-active { border-bottom: 0 !important; }
|
||||
.ui-accordion .ui-accordion-header a { display: block; font-size: 1em; padding: .5em .5em .5em .7em; }
|
||||
.ui-accordion-icons .ui-accordion-header a { padding-left: 2.2em; }
|
||||
.ui-accordion .ui-accordion-header .ui-icon { position: absolute; left: .5em; top: 50%; margin-top: -8px; }
|
||||
.ui-accordion .ui-accordion-content { padding: 1em 2.2em; border-top: 0; margin-top: -2px; position: relative; top: 1px; margin-bottom: 2px; overflow: auto; display: none; zoom: 1; }
|
||||
.ui-accordion .ui-accordion-content-active { display: block; }
|
||||
/*
|
||||
* jQuery UI Autocomplete 1.8.13
|
||||
*
|
||||
* Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
|
||||
* Dual licensed under the MIT or GPL Version 2 licenses.
|
||||
* http://jquery.org/license
|
||||
*
|
||||
* http://docs.jquery.com/UI/Autocomplete#theming
|
||||
*/
|
||||
.ui-autocomplete { position: absolute; cursor: default; }
|
||||
|
||||
/* workarounds */
|
||||
* html .ui-autocomplete { width:1px; } /* without this, the menu expands to 100% in IE6 */
|
||||
|
||||
/*
|
||||
* jQuery UI Menu 1.8.13
|
||||
*
|
||||
* Copyright 2010, AUTHORS.txt (http://jqueryui.com/about)
|
||||
* Dual licensed under the MIT or GPL Version 2 licenses.
|
||||
* http://jquery.org/license
|
||||
*
|
||||
* http://docs.jquery.com/UI/Menu#theming
|
||||
*/
|
||||
.ui-menu {
|
||||
list-style:none;
|
||||
padding: 2px;
|
||||
margin: 0;
|
||||
display:block;
|
||||
float: left;
|
||||
}
|
||||
.ui-menu .ui-menu {
|
||||
margin-top: -3px;
|
||||
}
|
||||
.ui-menu .ui-menu-item {
|
||||
margin:0;
|
||||
padding: 0;
|
||||
zoom: 1;
|
||||
float: left;
|
||||
clear: left;
|
||||
width: 100%;
|
||||
}
|
||||
.ui-menu .ui-menu-item a {
|
||||
text-decoration:none;
|
||||
display:block;
|
||||
padding:.2em .4em;
|
||||
line-height:1.5;
|
||||
zoom:1;
|
||||
}
|
||||
.ui-menu .ui-menu-item a.ui-state-hover,
|
||||
.ui-menu .ui-menu-item a.ui-state-active {
|
||||
font-weight: normal;
|
||||
margin: -1px;
|
||||
}
|
||||
/*
|
||||
* jQuery UI Button 1.8.13
|
||||
*
|
||||
* Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
|
||||
* Dual licensed under the MIT or GPL Version 2 licenses.
|
||||
* http://jquery.org/license
|
||||
*
|
||||
* http://docs.jquery.com/UI/Button#theming
|
||||
*/
|
||||
.ui-button { display: inline-block; position: relative; padding: 0; margin-right: .1em; text-decoration: none !important; cursor: pointer; text-align: center; zoom: 1; overflow: visible; } /* the overflow property removes extra width in IE */
|
||||
.ui-button-icon-only { width: 2.2em; } /* to make room for the icon, a width needs to be set here */
|
||||
button.ui-button-icon-only { width: 2.4em; } /* button elements seem to need a little more width */
|
||||
.ui-button-icons-only { width: 3.4em; }
|
||||
button.ui-button-icons-only { width: 3.7em; }
|
||||
|
||||
/*button text element */
|
||||
.ui-button .ui-button-text { display: block; line-height: 1.4; }
|
||||
.ui-button-text-only .ui-button-text { padding: .4em 1em; }
|
||||
.ui-button-icon-only .ui-button-text, .ui-button-icons-only .ui-button-text { padding: .4em; text-indent: -9999999px; }
|
||||
.ui-button-text-icon-primary .ui-button-text, .ui-button-text-icons .ui-button-text { padding: .4em 1em .4em 2.1em; }
|
||||
.ui-button-text-icon-secondary .ui-button-text, .ui-button-text-icons .ui-button-text { padding: .4em 2.1em .4em 1em; }
|
||||
.ui-button-text-icons .ui-button-text { padding-left: 2.1em; padding-right: 2.1em; }
|
||||
/* no icon support for input elements, provide padding by default */
|
||||
input.ui-button { padding: .4em 1em; }
|
||||
|
||||
/*button icon element(s) */
|
||||
.ui-button-icon-only .ui-icon, .ui-button-text-icon-primary .ui-icon, .ui-button-text-icon-secondary .ui-icon, .ui-button-text-icons .ui-icon, .ui-button-icons-only .ui-icon { position: absolute; top: 50%; margin-top: -8px; }
|
||||
.ui-button-icon-only .ui-icon { left: 50%; margin-left: -8px; }
|
||||
.ui-button-text-icon-primary .ui-button-icon-primary, .ui-button-text-icons .ui-button-icon-primary, .ui-button-icons-only .ui-button-icon-primary { left: .5em; }
|
||||
.ui-button-text-icon-secondary .ui-button-icon-secondary, .ui-button-text-icons .ui-button-icon-secondary, .ui-button-icons-only .ui-button-icon-secondary { right: .5em; }
|
||||
.ui-button-text-icons .ui-button-icon-secondary, .ui-button-icons-only .ui-button-icon-secondary { right: .5em; }
|
||||
|
||||
/*button sets*/
|
||||
.ui-buttonset { margin-right: 7px; }
|
||||
.ui-buttonset .ui-button { margin-left: 0; margin-right: -.3em; }
|
||||
|
||||
/* workarounds */
|
||||
button.ui-button::-moz-focus-inner { border: 0; padding: 0; } /* reset extra padding in Firefox */
|
||||
/*
|
||||
* jQuery UI Dialog 1.8.13
|
||||
*
|
||||
* Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
|
||||
* Dual licensed under the MIT or GPL Version 2 licenses.
|
||||
* http://jquery.org/license
|
||||
*
|
||||
* http://docs.jquery.com/UI/Dialog#theming
|
||||
*/
|
||||
.ui-dialog { position: absolute; padding: .2em; width: 300px; overflow: hidden; }
|
||||
.ui-dialog .ui-dialog-titlebar { padding: .4em 1em; position: relative; }
|
||||
.ui-dialog .ui-dialog-title { float: left; margin: .1em 16px .1em 0; }
|
||||
.ui-dialog .ui-dialog-titlebar-close { position: absolute; right: .3em; top: 50%; width: 19px; margin: -10px 0 0 0; padding: 1px; height: 18px; }
|
||||
.ui-dialog .ui-dialog-titlebar-close span { display: block; margin: 1px; }
|
||||
.ui-dialog .ui-dialog-titlebar-close:hover, .ui-dialog .ui-dialog-titlebar-close:focus { padding: 0; }
|
||||
.ui-dialog .ui-dialog-content { position: relative; border: 0; padding: .5em 1em; background: none; overflow: auto; zoom: 1; }
|
||||
.ui-dialog .ui-dialog-buttonpane { text-align: left; border-width: 1px 0 0 0; background-image: none; margin: .5em 0 0 0; padding: .3em 1em .5em .4em; }
|
||||
.ui-dialog .ui-dialog-buttonpane .ui-dialog-buttonset { float: right; }
|
||||
.ui-dialog .ui-dialog-buttonpane button { margin: .5em .4em .5em 0; cursor: pointer; }
|
||||
.ui-dialog .ui-resizable-se { width: 14px; height: 14px; right: 3px; bottom: 3px; }
|
||||
.ui-draggable .ui-dialog-titlebar { cursor: move; }
|
||||
/*
|
||||
* jQuery UI Slider 1.8.13
|
||||
*
|
||||
* Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
|
||||
* Dual licensed under the MIT or GPL Version 2 licenses.
|
||||
* http://jquery.org/license
|
||||
*
|
||||
* http://docs.jquery.com/UI/Slider#theming
|
||||
*/
|
||||
.ui-slider { position: relative; text-align: left; }
|
||||
.ui-slider .ui-slider-handle { position: absolute; z-index: 2; width: 1.2em; height: 1.2em; cursor: default; }
|
||||
.ui-slider .ui-slider-range { position: absolute; z-index: 1; font-size: .7em; display: block; border: 0; background-position: 0 0; }
|
||||
|
||||
.ui-slider-horizontal { height: .8em; }
|
||||
.ui-slider-horizontal .ui-slider-handle { top: -.3em; margin-left: -.6em; }
|
||||
.ui-slider-horizontal .ui-slider-range { top: 0; height: 100%; }
|
||||
.ui-slider-horizontal .ui-slider-range-min { left: 0; }
|
||||
.ui-slider-horizontal .ui-slider-range-max { right: 0; }
|
||||
|
||||
.ui-slider-vertical { width: .8em; height: 100px; }
|
||||
.ui-slider-vertical .ui-slider-handle { left: -.3em; margin-left: 0; margin-bottom: -.6em; }
|
||||
.ui-slider-vertical .ui-slider-range { left: 0; width: 100%; }
|
||||
.ui-slider-vertical .ui-slider-range-min { bottom: 0; }
|
||||
.ui-slider-vertical .ui-slider-range-max { top: 0; }/*
|
||||
* jQuery UI Tabs 1.8.13
|
||||
*
|
||||
* Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
|
||||
* Dual licensed under the MIT or GPL Version 2 licenses.
|
||||
* http://jquery.org/license
|
||||
*
|
||||
* http://docs.jquery.com/UI/Tabs#theming
|
||||
*/
|
||||
.ui-tabs { position: relative; padding: .2em; zoom: 1; } /* position: relative prevents IE scroll bug (element with position: relative inside container with overflow: auto appear as "fixed") */
|
||||
.ui-tabs .ui-tabs-nav { margin: 0; padding: .2em .2em 0; }
|
||||
.ui-tabs .ui-tabs-nav li { list-style: none; float: left; position: relative; top: 1px; margin: 0 .2em 1px 0; border-bottom: 0 !important; padding: 0; white-space: nowrap; }
|
||||
.ui-tabs .ui-tabs-nav li a { float: left; padding: .5em 1em; text-decoration: none; }
|
||||
.ui-tabs .ui-tabs-nav li.ui-tabs-selected { margin-bottom: 0; padding-bottom: 1px; }
|
||||
.ui-tabs .ui-tabs-nav li.ui-tabs-selected a, .ui-tabs .ui-tabs-nav li.ui-state-disabled a, .ui-tabs .ui-tabs-nav li.ui-state-processing a { cursor: text; }
|
||||
.ui-tabs .ui-tabs-nav li a, .ui-tabs.ui-tabs-collapsible .ui-tabs-nav li.ui-tabs-selected a { cursor: pointer; } /* first selector in group seems obsolete, but required to overcome bug in Opera applying cursor: text overall if defined elsewhere... */
|
||||
.ui-tabs .ui-tabs-panel { display: block; border-width: 0; padding: 1em 1.4em; background: none; }
|
||||
.ui-tabs .ui-tabs-hide { display: none !important; }
|
||||
/*
|
||||
* jQuery UI Datepicker 1.8.13
|
||||
*
|
||||
* Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
|
||||
* Dual licensed under the MIT or GPL Version 2 licenses.
|
||||
* http://jquery.org/license
|
||||
*
|
||||
* http://docs.jquery.com/UI/Datepicker#theming
|
||||
*/
|
||||
.ui-datepicker { width: 17em; padding: .2em .2em 0; display: none; }
|
||||
.ui-datepicker .ui-datepicker-header { position:relative; padding:.2em 0; }
|
||||
.ui-datepicker .ui-datepicker-prev, .ui-datepicker .ui-datepicker-next { position:absolute; top: 2px; width: 1.8em; height: 1.8em; }
|
||||
.ui-datepicker .ui-datepicker-prev-hover, .ui-datepicker .ui-datepicker-next-hover { top: 1px; }
|
||||
.ui-datepicker .ui-datepicker-prev { left:2px; }
|
||||
.ui-datepicker .ui-datepicker-next { right:2px; }
|
||||
.ui-datepicker .ui-datepicker-prev-hover { left:1px; }
|
||||
.ui-datepicker .ui-datepicker-next-hover { right:1px; }
|
||||
.ui-datepicker .ui-datepicker-prev span, .ui-datepicker .ui-datepicker-next span { display: block; position: absolute; left: 50%; margin-left: -8px; top: 50%; margin-top: -8px; }
|
||||
.ui-datepicker .ui-datepicker-title { margin: 0 2.3em; line-height: 1.8em; text-align: center; }
|
||||
.ui-datepicker .ui-datepicker-title select { font-size:1em; margin:1px 0; }
|
||||
.ui-datepicker select.ui-datepicker-month-year {width: 100%;}
|
||||
.ui-datepicker select.ui-datepicker-month,
|
||||
.ui-datepicker select.ui-datepicker-year { width: 49%;}
|
||||
.ui-datepicker table {width: 100%; font-size: .9em; border-collapse: collapse; margin:0 0 .4em; }
|
||||
.ui-datepicker th { padding: .7em .3em; text-align: center; font-weight: bold; border: 0; }
|
||||
.ui-datepicker td { border: 0; padding: 1px; }
|
||||
.ui-datepicker td span, .ui-datepicker td a { display: block; padding: .2em; text-align: right; text-decoration: none; }
|
||||
.ui-datepicker .ui-datepicker-buttonpane { background-image: none; margin: .7em 0 0 0; padding:0 .2em; border-left: 0; border-right: 0; border-bottom: 0; }
|
||||
.ui-datepicker .ui-datepicker-buttonpane button { float: right; margin: .5em .2em .4em; cursor: pointer; padding: .2em .6em .3em .6em; width:auto; overflow:visible; }
|
||||
.ui-datepicker .ui-datepicker-buttonpane button.ui-datepicker-current { float:left; }
|
||||
|
||||
/* with multiple calendars */
|
||||
.ui-datepicker.ui-datepicker-multi { width:auto; }
|
||||
.ui-datepicker-multi .ui-datepicker-group { float:left; }
|
||||
.ui-datepicker-multi .ui-datepicker-group table { width:95%; margin:0 auto .4em; }
|
||||
.ui-datepicker-multi-2 .ui-datepicker-group { width:50%; }
|
||||
.ui-datepicker-multi-3 .ui-datepicker-group { width:33.3%; }
|
||||
.ui-datepicker-multi-4 .ui-datepicker-group { width:25%; }
|
||||
.ui-datepicker-multi .ui-datepicker-group-last .ui-datepicker-header { border-left-width:0; }
|
||||
.ui-datepicker-multi .ui-datepicker-group-middle .ui-datepicker-header { border-left-width:0; }
|
||||
.ui-datepicker-multi .ui-datepicker-buttonpane { clear:left; }
|
||||
.ui-datepicker-row-break { clear:both; width:100%; }
|
||||
|
||||
/* RTL support */
|
||||
.ui-datepicker-rtl { direction: rtl; }
|
||||
.ui-datepicker-rtl .ui-datepicker-prev { right: 2px; left: auto; }
|
||||
.ui-datepicker-rtl .ui-datepicker-next { left: 2px; right: auto; }
|
||||
.ui-datepicker-rtl .ui-datepicker-prev:hover { right: 1px; left: auto; }
|
||||
.ui-datepicker-rtl .ui-datepicker-next:hover { left: 1px; right: auto; }
|
||||
.ui-datepicker-rtl .ui-datepicker-buttonpane { clear:right; }
|
||||
.ui-datepicker-rtl .ui-datepicker-buttonpane button { float: left; }
|
||||
.ui-datepicker-rtl .ui-datepicker-buttonpane button.ui-datepicker-current { float:right; }
|
||||
.ui-datepicker-rtl .ui-datepicker-group { float:right; }
|
||||
.ui-datepicker-rtl .ui-datepicker-group-last .ui-datepicker-header { border-right-width:0; border-left-width:1px; }
|
||||
.ui-datepicker-rtl .ui-datepicker-group-middle .ui-datepicker-header { border-right-width:0; border-left-width:1px; }
|
||||
|
||||
/* IE6 IFRAME FIX (taken from datepicker 1.5.3 */
|
||||
.ui-datepicker-cover {
|
||||
display: none; /*sorry for IE5*/
|
||||
display/**/: block; /*sorry for IE5*/
|
||||
position: absolute; /*must have*/
|
||||
z-index: -1; /*must have*/
|
||||
filter: mask(); /*must have*/
|
||||
top: -4px; /*must have*/
|
||||
left: -4px; /*must have*/
|
||||
width: 200px; /*must have*/
|
||||
height: 200px; /*must have*/
|
||||
}/*
|
||||
* jQuery UI Progressbar 1.8.13
|
||||
*
|
||||
* Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
|
||||
* Dual licensed under the MIT or GPL Version 2 licenses.
|
||||
* http://jquery.org/license
|
||||
*
|
||||
* http://docs.jquery.com/UI/Progressbar#theming
|
||||
*/
|
||||
.ui-progressbar { height:2em; text-align: left; }
|
||||
.ui-progressbar .ui-progressbar-value {margin: -1px; height:100%; }
|
||||
5
assets/stylesheets/jquery-ui/jquery-ui-1.9.2.css
vendored
Normal file
@ -55,7 +55,7 @@ en:
|
||||
:title_locked_by_user: "Locked by %{user}"
|
||||
:title_locked_by_you: "Locked by you"
|
||||
:title_waiting_for_approval: "Waiting for Approval"
|
||||
:title_approved: "Approved"
|
||||
:title_approved: "Approved"
|
||||
:title_unlock_file: "Unlock to allow changes for other members"
|
||||
:title_lock_file: "Lock to prevent changes for other members"
|
||||
:submit_download: "Download"
|
||||
@ -92,12 +92,10 @@ en:
|
||||
:title_delete_revision: "Delete revision"
|
||||
:label_created: "Created"
|
||||
:label_changed: "Changed"
|
||||
:info_changed_by_user: "%{changed} by %{user}"
|
||||
:info_changed_by_user: "%{changed} by"
|
||||
:label_filename: "Filename"
|
||||
:label_version: "Version"
|
||||
:label_workflow: "Workflow"
|
||||
:option_workflow_waiting_for_approval: "Waiting for approval"
|
||||
:option_workflow_approved: "Approved"
|
||||
:label_workflow: "Workflow"
|
||||
:option_workflow_none: "None"
|
||||
:label_mime: "Mime"
|
||||
:label_size: "Size"
|
||||
@ -208,3 +206,36 @@ en:
|
||||
:select_option_webdav_readwrite: "Read/Write"
|
||||
:label_webdav_strategy: "Webdav strategy"
|
||||
:note_webdav_strategy: "Enables the administrator to decide if webdav is a read-only or read-write platform for end users."
|
||||
|
||||
error_unable_delete_dmsf_workflow: 'Unable to delete the workflow'
|
||||
error_empty_note: "The note can't be empty"
|
||||
error_workflow_assign: 'An error occured while assigning'
|
||||
label_dmsf_workflow_new: 'New approval workflow'
|
||||
label_dmsf_workflow: 'Approval workflow'
|
||||
label_dmsf_workflow_plural: 'Approval workflows'
|
||||
label_dmsf_workflow_step: Step
|
||||
label_dmsf_workflow_step_plural: Steps
|
||||
label_dmsf_workflow_approval: Approval
|
||||
label_dmsf_workflow_approval_plural: Approvals
|
||||
label_dmsf: DMSF
|
||||
label_dmsf_wokflow_action_approve: Approve
|
||||
label_dmsf_wokflow_action_reject: Reject
|
||||
label_dmsf_wokflow_action_delegate: 'Delegate to'
|
||||
label_dmsf_wokflow_action_assign: 'Assign an approval workflow'
|
||||
label_dmsf_wokflow_action_start: 'Start workflow'
|
||||
label_action: Action
|
||||
label_note: Note
|
||||
title_draft: Draft
|
||||
title_rejected: Rejected
|
||||
title_delegated: Delegated
|
||||
title_assigned: Assigned
|
||||
title_started: Started
|
||||
title_dmsf_workflow_log: 'Approval workflow log'
|
||||
dmsf_and: AND
|
||||
dmsf_or: OR
|
||||
dmsf_new_step: New step
|
||||
message_dmsf_wokflow_note: Your note...
|
||||
info_revision: "r%{rev}"
|
||||
link_workflow: Workflow
|
||||
|
||||
|
||||
@ -100,4 +100,21 @@ RedmineApp::Application.routes.draw do
|
||||
:resource_class => RedmineDmsf::Webdav::ResourceProxy,
|
||||
:controller_class => RedmineDmsf::Webdav::Controller
|
||||
), :at => "/dmsf/webdav"
|
||||
|
||||
# Approval workflow
|
||||
resources :dmsf_workflows do
|
||||
member do
|
||||
get 'autocomplete_for_user'
|
||||
get 'action'
|
||||
get 'assign'
|
||||
get 'log'
|
||||
post 'new_action'
|
||||
post 'start'
|
||||
post 'assignment'
|
||||
end
|
||||
end
|
||||
|
||||
match 'dmsf_workflows/:id/edit', :controller => 'dmsf_workflows', :action => 'add_step', :id => /\d+/, :via => :post
|
||||
match 'dmsf_workflows/:id/edit', :controller => 'dmsf_workflows', :action => 'remove_step', :id => /\d+/, :via => :delete
|
||||
match 'dmsf_workflows/:id/edit', :controller => 'dmsf_workflows', :action => 'reorder_steps', :id => /\d+/, :via => :put
|
||||
end
|
||||
|
||||
44
db/migrate/20120822100401_create_dmsf_workflows.rb
Normal file
@ -0,0 +1,44 @@
|
||||
# Redmine plugin for Document Management System "Features"
|
||||
#
|
||||
# Copyright (C) 2013 Karel Picman <karel.picman@kontron.com>
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU General Public License
|
||||
# as published by the Free Software Foundation; either version 2
|
||||
# of the License, or (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
|
||||
class CreateDmsfWorkflows < ActiveRecord::Migration
|
||||
def self.up
|
||||
create_table :dmsf_workflows do |t|
|
||||
t.string :name, :null => false
|
||||
t.references :project
|
||||
end
|
||||
add_index :dmsf_workflows, [:name], :unique => true
|
||||
|
||||
change_table :dmsf_file_revisions do |t|
|
||||
t.references :dmsf_workflow
|
||||
t.integer :dmsf_workflow_assigned_by
|
||||
t.datetime :dmsf_workflow_assigned_at
|
||||
t.integer :dmsf_workflow_started_by
|
||||
t.datetime :dmsf_workflow_started_at
|
||||
end
|
||||
end
|
||||
|
||||
def self.down
|
||||
remove_column :dmsf_file_revisions, :dmsf_workflow_id
|
||||
remove_column :dmsf_file_revisions, :dmsf_workflow_assigned_by
|
||||
remove_column :dmsf_file_revisions, :dmsf_workflow_assigned_at
|
||||
remove_column :dmsf_file_revisions, :dmsf_workflow_started_by
|
||||
remove_column :dmsf_file_revisions, :dmsf_workflow_started_at
|
||||
drop_table :dmsf_workflows
|
||||
end
|
||||
end
|
||||
33
db/migrate/20120822100402_create_dmsf_workflow_steps.rb
Normal file
@ -0,0 +1,33 @@
|
||||
# Redmine plugin for Document Management System "Features"
|
||||
#
|
||||
# Copyright (C) 2013 Karel Picman <karel.picman@kontron.com>
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU General Public License
|
||||
# as published by the Free Software Foundation; either version 2
|
||||
# of the License, or (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
|
||||
class CreateDmsfWorkflowSteps < ActiveRecord::Migration
|
||||
def self.up
|
||||
create_table :dmsf_workflow_steps do |t|
|
||||
t.references :dmsf_workflow, :null => false
|
||||
t.integer :step, :null => false
|
||||
t.references :user, :null => false
|
||||
t.integer :operator, :null => false
|
||||
end
|
||||
add_index :dmsf_workflow_steps, :dmsf_workflow_id
|
||||
end
|
||||
|
||||
def self.down
|
||||
drop_table :dmsf_workflow_steps
|
||||
end
|
||||
end
|
||||
@ -0,0 +1,35 @@
|
||||
# Redmine plugin for Document Management System "Features"
|
||||
#
|
||||
# Copyright (C) 2013 Karel Picman <karel.picman@kontron.com>
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU General Public License
|
||||
# as published by the Free Software Foundation; either version 2
|
||||
# of the License, or (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
|
||||
class CreateDmsfWorkflowStepAssignments < ActiveRecord::Migration
|
||||
def self.up
|
||||
create_table :dmsf_workflow_step_assignments do |t|
|
||||
t.references :dmsf_workflow_step, :null => false
|
||||
t.references :user, :null => false
|
||||
t.references :dmsf_file_revision, :null => false
|
||||
end
|
||||
add_index :dmsf_workflow_step_assignments,
|
||||
[:dmsf_workflow_step_id, :dmsf_file_revision_id],
|
||||
# The default index name exceeds the index name limit
|
||||
{:name => 'index_dmsf_wrkfl_step_assigns_on_wrkfl_step_id_and_frev_id'}
|
||||
end
|
||||
|
||||
def self.down
|
||||
drop_table :dmsf_workflow_step_assignments
|
||||
end
|
||||
end
|
||||
@ -0,0 +1,36 @@
|
||||
# Redmine plugin for Document Management System "Features"
|
||||
#
|
||||
# Copyright (C) 2013 Karel Picman <karel.picman@kontron.com>
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU General Public License
|
||||
# as published by the Free Software Foundation; either version 2
|
||||
# of the License, or (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
|
||||
class CreateDmsfWorkflowStepActions < ActiveRecord::Migration
|
||||
def self.up
|
||||
create_table :dmsf_workflow_step_actions do |t|
|
||||
t.references :dmsf_workflow_step_assignment, :null => false
|
||||
t.integer :action, :null => false
|
||||
t.text :note
|
||||
t.timestamp :created_at
|
||||
t.integer :author_id, :null => false
|
||||
end
|
||||
add_index :dmsf_workflow_step_actions,
|
||||
:dmsf_workflow_step_assignment_id,
|
||||
# The default index name exceeds the index name limit
|
||||
{:name => 'index_dmsf_workflow_step_actions_on_workflow_step_assignment_id'}
|
||||
end
|
||||
def self.down
|
||||
drop_table :dmsf_workflow_step_actions
|
||||
end
|
||||
end
|
||||
21
init.rb
@ -51,13 +51,26 @@ Redmine::Plugin.register :redmine_dmsf do
|
||||
permission :view_dmsf_folders, {:dmsf => [:show], :dmsf_folders_copy => [:new, :copy_to, :move_to]}
|
||||
permission :user_preferences, {:dmsf_state => [:user_pref_save]}
|
||||
permission :view_dmsf_files, {:dmsf => [:entries_operation, :entries_email],
|
||||
:dmsf_files => [:show], :dmsf_files_copy => [:new, :create, :move]}
|
||||
:dmsf_files => [:show], :dmsf_files_copy => [:new, :create, :move]}
|
||||
permission :folder_manipulation, {:dmsf => [:new, :create, :delete, :edit, :save, :edit_root, :save_root, :lock, :unlock]}
|
||||
permission :file_manipulation, {:dmsf_files => [:create_revision, :delete, :lock, :unlock],
|
||||
:dmsf_upload => [:upload_files, :upload_file, :commit_files]}
|
||||
:dmsf_upload => [:upload_files, :upload_file, :commit_files]}
|
||||
permission :file_approval, {:dmsf_files => [:delete_revision, :notify_activate, :notify_deactivate],
|
||||
:dmsf => [:notify_activate, :notify_deactivate]}
|
||||
permission :force_file_unlock, {}
|
||||
:dmsf => [:notify_activate, :notify_deactivate],
|
||||
:dmsf_workflows => [:new, :create, :destroy, :edit, :add_step, :remove_step, :reorder_steps, :update, :start, :assign, :assignment, :action, :new_action, :log]}
|
||||
permission :force_file_unlock, {}
|
||||
end
|
||||
|
||||
# Administration menu extension
|
||||
Redmine::MenuManager.map :admin_menu do |menu|
|
||||
menu.push :approvalworkflows, {:controller => 'dmsf_workflows', :action => 'index'}, :caption => :label_dmsf_workflow_plural
|
||||
end
|
||||
|
||||
# Adds stylesheet tag
|
||||
class DmsfViewListener < Redmine::Hook::ViewListener
|
||||
def view_layouts_base_html_head(context)
|
||||
stylesheet_link_tag('dmsf', :plugin => :redmine_dmsf)
|
||||
end
|
||||
end
|
||||
|
||||
Redmine::WikiFormatting::Macros.register do
|
||||
|
||||
@ -33,7 +33,7 @@ module RedmineDmsf
|
||||
has_many :dmsf_files, :class_name => "DmsfFile", :foreign_key => "project_id", :conditions => { :dmsf_folder_id => nil }
|
||||
#Fix: should only be root folders not, all folders
|
||||
has_many :dmsf_folders, :class_name => "DmsfFolder", :foreign_key => "project_id", :conditions => {:dmsf_folder_id => nil}, :dependent => :destroy
|
||||
|
||||
has_many :dmsf_workflows, :dependent => :destroy
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
@ -39,8 +39,9 @@ module RedmineDmsf
|
||||
|
||||
def project_settings_tabs_with_dmsf
|
||||
tabs = project_settings_tabs_without_dmsf
|
||||
if @project.module_enabled?("dmsf")
|
||||
tabs.push({:name => 'dmsf', :controller => :dmsf_state, :action => :user_pref_save, :partial => 'dmsf_state/user_pref', :label => :dmsf})
|
||||
if @project.module_enabled? 'dmsf'
|
||||
#tabs.push({:name => 'dmsf', :controller => :dmsf_state, :action => :user_pref_save, :partial => 'dmsf_state/user_pref', :label => :dmsf})
|
||||
tabs << {:name => 'dmsf', :controller => 'dmsf_workflows', :action => 'index', :partial => 'dmsf_workflows/main', :label => 'label_dmsf'}
|
||||
end
|
||||
return tabs
|
||||
end
|
||||
|
||||
22
test/fixtures/dmsf_workflow_step_actions.yml
vendored
Normal file
@ -0,0 +1,22 @@
|
||||
|
||||
---
|
||||
wfsac1:
|
||||
id: 1
|
||||
dmsf_workflow_step_assignment_id: 1
|
||||
action: 1
|
||||
note: 'Approval'
|
||||
created_at: '2013-05-03 10:45:35'
|
||||
|
||||
wfsac2:
|
||||
id: 2
|
||||
dmsf_workflow_step_assignment_id: 1
|
||||
action: 2
|
||||
note: 'Rejection'
|
||||
created_at: '2013-05-03 10:45:36'
|
||||
|
||||
wfsac3:
|
||||
id: 3
|
||||
dmsf_workflow_step_assignment_id: 1
|
||||
action: 3
|
||||
note: 'Delegation'
|
||||
created_at: '2013-05-03 10:45:37'
|
||||
6
test/fixtures/dmsf_workflow_step_assignments.yml
vendored
Normal file
@ -0,0 +1,6 @@
|
||||
---
|
||||
wfsa1:
|
||||
id: 1
|
||||
dmsf_workflow_step_id: 1
|
||||
user_id: 1
|
||||
dmsf_file_revision_id: 2
|
||||
21
test/fixtures/dmsf_workflow_steps.yml
vendored
Normal file
@ -0,0 +1,21 @@
|
||||
---
|
||||
wfs1:
|
||||
id: 1
|
||||
dmsf_workflow_id: 1
|
||||
step: 1
|
||||
user_id: 1
|
||||
operator: 1
|
||||
|
||||
wfs2:
|
||||
id: 2
|
||||
dmsf_workflow_id: 1
|
||||
step: 2
|
||||
user_id: 2
|
||||
operator: 1
|
||||
|
||||
wfs3:
|
||||
id: 3
|
||||
dmsf_workflow_id: 1
|
||||
step: 3
|
||||
user_id: 1
|
||||
operator: 1
|
||||
8
test/fixtures/dmsf_workflows.yml
vendored
Normal file
@ -0,0 +1,8 @@
|
||||
---
|
||||
wf1:
|
||||
id: 1
|
||||
name: wf1
|
||||
|
||||
wf2:
|
||||
id: 2
|
||||
name: wf2
|
||||
171
test/functional/dmsf_workflow_controller_test.rb
Normal file
@ -0,0 +1,171 @@
|
||||
require File.expand_path('../../test_helper', __FILE__)
|
||||
|
||||
class DmsfWorkflowsControllerTest < RedmineDmsf::Test::TestCase
|
||||
fixtures :users, :dmsf_workflows, :dmsf_workflow_steps, :projects, :roles,
|
||||
:members, :member_roles
|
||||
|
||||
def setup
|
||||
User.current = nil
|
||||
|
||||
@manager_role = Role.find_by_name('Manager')
|
||||
@project = Project.find(5)
|
||||
end
|
||||
|
||||
def test_index_admin
|
||||
@request.session[:user_id] = 1 # admin
|
||||
get :index
|
||||
assert_response :success
|
||||
assert_template 'index'
|
||||
end
|
||||
|
||||
def test_index_user
|
||||
@request.session[:user_id] = 2 # non admin
|
||||
get :index
|
||||
assert_response :forbidden
|
||||
end
|
||||
|
||||
def test_index_member
|
||||
old_controller = @controller
|
||||
@controller = ProjectsController.new
|
||||
|
||||
@request.session[:user_id] = 2
|
||||
get :settings, :id => @project.id
|
||||
assert_response :success
|
||||
assert_template 'settings'
|
||||
|
||||
@controller = old_controller
|
||||
end
|
||||
|
||||
def test_new_admin
|
||||
@request.session[:user_id] = 1 # admin
|
||||
get :new
|
||||
assert_response :success
|
||||
assert_template 'new'
|
||||
end
|
||||
|
||||
def test_new_member_no_permission
|
||||
@project.enable_module!(:dmsf)
|
||||
@manager_role.remove_permission! :approval_workflows
|
||||
@request.session[:user_id] = 2
|
||||
get :new, {:project_id => @project.id}
|
||||
assert_response :forbidden
|
||||
end
|
||||
|
||||
def test_new_member_no_module
|
||||
@project.disable_module!(:dmsf)
|
||||
@manager_role.add_permission! :approval_workflows
|
||||
@request.session[:user_id] = 2
|
||||
get :new, {:project_id => @project.id}
|
||||
assert_response :forbidden
|
||||
end
|
||||
|
||||
def test_new_member
|
||||
@manager_role.add_permission! :approval_workflows
|
||||
@request.session[:user_id] = 2
|
||||
@project.enable_module!(:dmsf)
|
||||
get :new, {:project_id => @project.id}
|
||||
assert_response :success
|
||||
assert_template 'new'
|
||||
end
|
||||
|
||||
def test_new_no_member
|
||||
@manager_role.add_permission! :approval_workflows
|
||||
@request.session[:user_id] = 3
|
||||
@project.enable_module!(:dmsf)
|
||||
get :new, {:project_id => @project.id}
|
||||
assert_response :forbidden
|
||||
end
|
||||
|
||||
def test_edit
|
||||
@request.session[:user_id] = 1 # admin
|
||||
get :edit, :id => 1
|
||||
assert_response :success
|
||||
assert_template 'edit'
|
||||
end
|
||||
|
||||
def test_create
|
||||
@request.session[:user_id] = 1 # admin
|
||||
assert_difference 'DmsfWorkflow.count', +1 do
|
||||
post :create, :dmsf_workflow => {:name => 'wf3'}
|
||||
end
|
||||
workflow = DmsfWorkflow.first(:order => 'id DESC')
|
||||
assert_redirected_to dmsf_workflows_path
|
||||
assert_equal 'wf3', workflow.name
|
||||
end
|
||||
|
||||
def test_update
|
||||
@request.session[:user_id] = 1 # admin
|
||||
put :update, :id => 1, :dmsf_workflow => {:name => 'wf1a'}
|
||||
workflow = DmsfWorkflow.find(1)
|
||||
assert_equal 'wf1a', workflow.name
|
||||
end
|
||||
|
||||
def test_destroy
|
||||
@request.session[:user_id] = 1 # admin
|
||||
assert_difference 'DmsfWorkflow.count', -1 do
|
||||
delete :destroy, :id => 1
|
||||
end
|
||||
assert_redirected_to dmsf_workflows_path
|
||||
assert_nil DmsfWorkflow.find_by_id(1)
|
||||
end
|
||||
|
||||
def test_add_step
|
||||
@request.session[:user_id] = 1 # admin
|
||||
assert_difference 'DmsfWorkflowStep.count', +1 do
|
||||
post :add_step, :commit => 'OR', :step => 1, :id => 1, :user_ids =>[3]
|
||||
end
|
||||
assert_response :success
|
||||
ws = DmsfWorkflowStep.first(:order => 'id DESC')
|
||||
assert_equal 1, ws.dmsf_workflow_id
|
||||
assert_equal 1, ws.step
|
||||
assert_equal 3, ws.user_id
|
||||
assert_equal 0, ws.operator
|
||||
end
|
||||
|
||||
def test_remove_step
|
||||
@request.session[:user_id] = 1 # admin
|
||||
n = DmsfWorkflowStep.where(:dmsf_workflow_id => 1, :step => 1).count
|
||||
assert_difference 'DmsfWorkflowStep.count', -n do
|
||||
delete :remove_step, :step => 1, :id => 1
|
||||
end
|
||||
assert_response :success
|
||||
ws = DmsfWorkflowStep.where(:dmsf_workflow_id => 1).first(:order => 'id ASC')
|
||||
assert_equal 1, ws.step
|
||||
end
|
||||
|
||||
def test_reorder_steps_to_lower
|
||||
@request.session[:user_id] = 1 # admin
|
||||
put :reorder_steps, :step => 1, :id => 1, :workflow_step => {:move_to => 'lower'}
|
||||
assert_response :success
|
||||
assert_equal 2, DmsfWorkflowStep.find(1).step
|
||||
assert_equal 1, DmsfWorkflowStep.find(2).step
|
||||
assert_equal 3, DmsfWorkflowStep.find(3).step
|
||||
end
|
||||
|
||||
def test_reorder_steps_to_lowest
|
||||
@request.session[:user_id] = 1 # admin
|
||||
put :reorder_steps, :step => 1, :id => 1, :workflow_step => {:move_to => 'lowest'}
|
||||
assert_response :success
|
||||
assert_equal 3, DmsfWorkflowStep.find(1).step
|
||||
assert_equal 1, DmsfWorkflowStep.find(2).step
|
||||
assert_equal 2, DmsfWorkflowStep.find(3).step
|
||||
end
|
||||
|
||||
def test_reorder_steps_to_higher
|
||||
@request.session[:user_id] = 1 # admin
|
||||
put :reorder_steps, :step => 2, :id => 1, :workflow_step => {:move_to => 'higher'}
|
||||
assert_response :success
|
||||
assert_equal 2, DmsfWorkflowStep.find(1).step
|
||||
assert_equal 1, DmsfWorkflowStep.find(2).step
|
||||
assert_equal 3, DmsfWorkflowStep.find(3).step
|
||||
end
|
||||
|
||||
def test_reorder_steps_to_highest
|
||||
@request.session[:user_id] = 1 # admin
|
||||
put :reorder_steps, :step => 3, :id => 1, :workflow_step => {:move_to => 'highest'}
|
||||
assert_response :success
|
||||
assert_equal 2, DmsfWorkflowStep.find(1).step
|
||||
assert_equal 3, DmsfWorkflowStep.find(2).step
|
||||
assert_equal 1, DmsfWorkflowStep.find(3).step
|
||||
end
|
||||
end
|
||||
60
test/unit/dmsf_workflow_step_action_test.rb
Normal file
@ -0,0 +1,60 @@
|
||||
require File.expand_path('../../test_helper', __FILE__)
|
||||
|
||||
class DmsfWorkflowStepActionTest < RedmineDmsf::Test::UnitTest
|
||||
|
||||
|
||||
fixtures :dmsf_workflow_steps
|
||||
fixtures :dmsf_workflow_step_actions
|
||||
|
||||
def setup
|
||||
@wfsac1 = DmsfWorkflowStepAction.find(1)
|
||||
@wfsac2 = DmsfWorkflowStepAction.find(2)
|
||||
@wfsac3 = DmsfWorkflowStepAction.find(3)
|
||||
end
|
||||
|
||||
def test_truth
|
||||
assert_kind_of DmsfWorkflowStepAction, @wfsac1
|
||||
assert_kind_of DmsfWorkflowStepAction, @wfsac2
|
||||
assert_kind_of DmsfWorkflowStepAction, @wfsac3
|
||||
end
|
||||
|
||||
def test_create
|
||||
wfsac = DmsfWorkflowStepAction.new(
|
||||
:dmsf_workflow_step_assignment_id => 1,
|
||||
:action => 1,
|
||||
:note => 'Approvement')
|
||||
assert wfsac.save
|
||||
wfsac.reload
|
||||
assert wfsac.created_at
|
||||
end
|
||||
|
||||
def test_update
|
||||
@wfsac1.dmsf_workflow_step_assignment_id = 2
|
||||
@wfsac1.action = 2
|
||||
@wfsac1.note = 'Rejection'
|
||||
|
||||
assert @wfsac1.save
|
||||
@wfsac1.reload
|
||||
|
||||
assert_equal 2, @wfsac1.dmsf_workflow_step_assignment_id
|
||||
assert_equal 2, @wfsac1.action
|
||||
assert_equal 'Rejection', @wfsac1.note
|
||||
end
|
||||
|
||||
def test_validate_workflow_step_assignment_id_presence
|
||||
@wfsac1.dmsf_workflow_step_assignment_id = nil
|
||||
assert !@wfsac1.save
|
||||
assert_equal 1, @wfsac1.errors.count
|
||||
end
|
||||
|
||||
def test_validate_action_presence
|
||||
@wfsac1.action = nil
|
||||
assert !@wfsac1.save
|
||||
assert_equal 1, @wfsac1.errors.count
|
||||
end
|
||||
|
||||
def test_destroy
|
||||
@wfsac1.destroy
|
||||
assert_nil DmsfWorkflowStepAction.find_by_id(1)
|
||||
end
|
||||
end
|
||||
53
test/unit/dmsf_workflow_step_assignment_test.rb
Normal file
@ -0,0 +1,53 @@
|
||||
require File.expand_path('../../test_helper', __FILE__)
|
||||
|
||||
class WorkflowStepAssignmentTest < RedmineDmsf::Test::UnitTest
|
||||
|
||||
fixtures :users, :dmsf_file_revisions, :dmsf_workflow_steps, :dmsf_workflow_step_assignments
|
||||
|
||||
def setup
|
||||
@wfsa1 = DmsfWorkflowStepAssignment.find(1)
|
||||
end
|
||||
|
||||
def test_truth
|
||||
assert_kind_of DmsfWorkflowStepAssignment, @wfsa1
|
||||
end
|
||||
|
||||
def test_create
|
||||
wfsa = DmsfWorkflowStepAssignment.new(
|
||||
:dmsf_workflow_step_id => 2,
|
||||
:user_id => 2,
|
||||
:dmsf_file_revision_id => 2)
|
||||
assert wfsa.save
|
||||
end
|
||||
|
||||
def test_update
|
||||
@wfsa1.dmsf_workflow_step_id = 2
|
||||
@wfsa1.user_id = 2
|
||||
@wfsa1.dmsf_file_revision_id = 2
|
||||
|
||||
assert @wfsa1.save
|
||||
@wfsa1.reload
|
||||
|
||||
assert_equal 2, @wfsa1.dmsf_workflow_step_id
|
||||
assert_equal 2, @wfsa1.user_id
|
||||
assert_equal 2, @wfsa1.dmsf_file_revision_id
|
||||
end
|
||||
|
||||
def test_validate_workflow_step_id_presence
|
||||
@wfsa1.dmsf_workflow_step_id = nil
|
||||
assert !@wfsa1.save
|
||||
assert_equal 1, @wfsa1.errors.count
|
||||
end
|
||||
|
||||
def test_validate_workflow_entity_id_presence
|
||||
@wfsa1.dmsf_file_revision_id = nil
|
||||
assert !@wfsa1.save
|
||||
assert_equal 1, @wfsa1.errors.count
|
||||
end
|
||||
|
||||
def test_destroy
|
||||
@wfsa1.destroy
|
||||
assert_nil DmsfWorkflowStepAssignment.find_by_id(1)
|
||||
assert_nil DmsfWorkflowStepAction.find_by_id(1)
|
||||
end
|
||||
end
|
||||
76
test/unit/dmsf_workflow_step_test.rb
Normal file
@ -0,0 +1,76 @@
|
||||
require File.expand_path('../../test_helper', __FILE__)
|
||||
|
||||
class DmsfWorkflowStepTest < RedmineDmsf::Test::UnitTest
|
||||
|
||||
fixtures :users, :dmsf_workflows, :dmsf_workflow_steps
|
||||
|
||||
def setup
|
||||
@wfs1 = DmsfWorkflowStep.find(1)
|
||||
@wfs2 = DmsfWorkflowStep.find(2)
|
||||
end
|
||||
|
||||
def test_truth
|
||||
assert_kind_of DmsfWorkflowStep, @wfs1
|
||||
end
|
||||
|
||||
def test_create
|
||||
wfs = DmsfWorkflowStep.new(
|
||||
:dmsf_workflow_id => 1,
|
||||
:step => 2,
|
||||
:user_id => 1,
|
||||
:operator => 1)
|
||||
assert wfs.save
|
||||
end
|
||||
|
||||
def test_update
|
||||
@wfs1.dmsf_workflow_id = 2
|
||||
@wfs1.step = 2
|
||||
@wfs1.user_id = 2
|
||||
@wfs1.operator = 2
|
||||
|
||||
assert @wfs1.save
|
||||
@wfs1.reload
|
||||
|
||||
assert_equal 2, @wfs1.dmsf_workflow_id
|
||||
assert_equal 2, @wfs1.step
|
||||
assert_equal 2, @wfs1.user_id
|
||||
assert_equal 2, @wfs1.operator
|
||||
end
|
||||
|
||||
def test_validate_workflow_id_presence
|
||||
@wfs1.dmsf_workflow_id = nil
|
||||
assert !@wfs1.save
|
||||
assert_equal 1, @wfs1.errors.count
|
||||
end
|
||||
|
||||
def test_validate_step_presence
|
||||
@wfs1.step = nil
|
||||
assert !@wfs1.save
|
||||
assert_equal 1, @wfs1.errors.count
|
||||
end
|
||||
|
||||
def test_validate_user_id_presence
|
||||
@wfs1.user_id = nil
|
||||
assert !@wfs1.save
|
||||
assert_equal 1, @wfs1.errors.count
|
||||
end
|
||||
|
||||
def test_validate_operator_presence
|
||||
@wfs1.operator = nil
|
||||
assert !@wfs1.save
|
||||
assert_equal 1, @wfs1.errors.count
|
||||
end
|
||||
|
||||
def test_validate_user_id_uniqueness
|
||||
@wfs2.user_id = @wfs1.user_id
|
||||
@wfs2.dmsf_workflow_id = @wfs1.dmsf_workflow_id
|
||||
@wfs2.step = @wfs1.step
|
||||
assert !@wfs2.save
|
||||
assert_equal 1, @wfs2.errors.count
|
||||
end
|
||||
|
||||
def test_destroy
|
||||
@wfs2.destroy
|
||||
assert_nil DmsfWorkflowStep.find_by_id(2)
|
||||
end
|
||||
end
|
||||
54
test/unit/dmsf_workflow_test.rb
Normal file
@ -0,0 +1,54 @@
|
||||
require File.expand_path('../../test_helper', __FILE__)
|
||||
|
||||
class DmsfWorkflowTest < RedmineDmsf::Test::UnitTest
|
||||
|
||||
fixtures :projects, :dmsf_workflows, :dmsf_workflow_steps
|
||||
|
||||
def setup
|
||||
@wf1 = DmsfWorkflow.find(1)
|
||||
@wf2 = DmsfWorkflow.find(2)
|
||||
@wfs1 = DmsfWorkflowStep.find(1)
|
||||
end
|
||||
|
||||
def test_truth
|
||||
assert_kind_of DmsfWorkflow, @wf1
|
||||
end
|
||||
|
||||
def test_create
|
||||
workflow = DmsfWorkflow.new(:name => 'wf')
|
||||
assert workflow.save
|
||||
end
|
||||
|
||||
def test_update
|
||||
@wf1.name = 'wf1a'
|
||||
@wf1.project_id = 5
|
||||
assert @wf1.save
|
||||
@wf1.reload
|
||||
assert_equal 'wf1a', @wf1.name
|
||||
assert_equal 5, @wf1.project_id
|
||||
end
|
||||
|
||||
def test_validate_name_length
|
||||
@wf1.name = 'a' * 256
|
||||
assert !@wf1.save
|
||||
assert_equal 1, @wf1.errors.count
|
||||
end
|
||||
|
||||
def test_validate_name_presence
|
||||
@wf1.name = ''
|
||||
assert !@wf1.save
|
||||
assert_equal 1, @wf1.errors.count
|
||||
end
|
||||
|
||||
def test_validate_name_uniqueness
|
||||
@wf2.name = @wf1.name
|
||||
assert !@wf2.save
|
||||
assert_equal 1, @wf2.errors.count
|
||||
end
|
||||
|
||||
def test_destroy
|
||||
@wf1.destroy
|
||||
assert_nil DmsfWorkflow.find_by_id(1)
|
||||
assert_nil DmsfWorkflowStep.find_by_id(@wfs1.id)
|
||||
end
|
||||
end
|
||||