Initial Redmine tooling and local plugin forks

This commit is contained in:
Jason Thistlethwaite
2026-04-24 22:01:18 +00:00
commit 9f682af0eb
683 changed files with 56878 additions and 0 deletions
@@ -0,0 +1,74 @@
<div id="attributes" class="attributes">
<div class="contextual">
<%- if ContactsSetting.vcard? -%>
<%= link_to 'vCard', contact_path(@contact, :format => :vcf) %>
<%- end -%>
</div>
<h3><%= if !@contact.is_company then l(:label_contact) else l(:label_crm_company) end %></h3>
<table class="contact sidebar attributes vcard">
<%= call_hook(:view_contacts_sidebar_attributes_top) %>
<tr>
<th class = "name"><%= l(:field_contact_name) %>:</th><td class="name fn <%= "org" if @contact.is_company %>"><%= h @contact.name(:firstname_middlename_lastname) %></td>
</tr>
<% if !@contact.job_title.blank? %>
<tr> <th class = "job_title"><%= !@contact.is_company ? l(:field_contact_job_title) : l(:field_company_field) %>:</th><td class="job_title title"><%= h @contact.job_title %></td></tr>
<% end %>
<% if !@contact.is_company %>
<tr><th class = "company"><%=l(:field_contact_company)%>:</th><td class="company org"><%= h @contact.company %></td></tr>
<% end %>
<tr>
<th class = "address"><%= l(:field_contact_address) %>:</th>
<% unless @contact.address.blank? %>
<td class="address adr">
<%= @contact.post_address.gsub("\n", "<br/>").html_safe %>
<br>
<%= link_to l(:label_crm_show_on_map), "http://maps.google.com/maps?f=q&q=#{@contact.address}+(#{@contact.name})&ie=UTF8&om=1"%>
</td>
<% end %>
</tr>
<tr class = "tel">
<th class = "phone"><%= l(:field_contact_phone) %>:</th>
<td class = "phones">
<% @contact.phones.each do |phone| %>
<span class="value"><%= h phone %> <br></span>
<% end %>
</td>
</tr>
<tr class = "emails">
<th><%= l(:field_contact_email) %>:</th>
<td>
<% @contact.emails.each do |email| %>
<span class="email"><%= mail_to email %> <br></span>
<% end %>
</td>
</tr>
<tr>
<th class = "website"><%= l(:field_contact_website) %>:</th>
<td class="website url"><%= link_to @contact.website, @contact.website_address, :class => 'external' %></td>
</tr>
<% if !@contact.skype_name.blank? %>
<tr>
<th class = "skype"><%= l(:field_contact_skype) %>:</th>
<td class="skype"><%= skype_to @contact.skype_name %></td>
</tr>
<% end %>
<% if !@contact.birthday.blank? %>
<tr> <th class = "birthday"><%= l(:field_birthday) %>:</th><td class="birthday bday" title=<%= "#{format_date(@contact.birthday)}" %>><%= "#{@contact.birthday.day} #{t('date.month_names')[@contact.birthday.month]}"%></td> </tr>
<tr> <th class = "age"><%= l(:field_age) %>:</th><td class="ega"><%= @contact.age %></td> </tr>
<% end %>
<% @contact.custom_field_values.compact.each do |custom_value| %>
<% if !custom_value.value.blank? %>
<tr> <th class = "custom_field"><%= custom_value.custom_field.name%>:</th><td> <%= simple_format_without_paragraph(h(show_value(custom_value))) %></td> </tr>
<% end %>
<% end %>
<% if @contact.assigned_to %>
<tr><th class="author"><%=l(:label_crm_assigned_to)%>:</th><td class="author"><%= avatar(@contact.assigned_to, :size => "14") %><%= link_to_user(@contact.assigned_to) %></td></tr>
<% end %>
<%= call_hook(:view_contacts_sidebar_attributes_bottom) %>
</table>
</div>
@@ -0,0 +1,13 @@
<% @company_contacts = @contact.company_contacts.visible.uniq %>
<% if @contact.is_company %>
<div id="company_contacts">
<div class="contextual">
<%= link_to_if_authorized l(:label_crm_add_contact), {:controller => 'contacts', :action => 'new', :project_id => @project, :contact => {:company => @contact.name}} %>
</div>
<h3><%= l(:label_contact_plural) %></h3>
<%= render :partial => 'common/contact_data', :collection => @company_contacts %>
<div style="clear:both;"> </div>
</div>
<% end %>
@@ -0,0 +1,36 @@
<div class="contact card">
<table class="subject_header">
<tr>
<td class="avatar"><%= contact_tag(contact_card, :type => "avatar", :size => 64) %></td>
<td class="name" style="vertical-align: top;">
<h2><%= contact_tag(contact_card, :type => "plain") %> </h2>
<p>
<%= h contact_card.job_title %>
<% if !contact_card.is_company %>
<%= " #{l(:label_crm_at_company)} " unless (contact_card.job_title.blank? or contact_card.company.blank?) %>
<% if contact_card.contact_company %>
<%= link_to contact_card.contact_company.name, {:controller => 'contacts', :action => 'show', :project_id => contact_card.contact_company.project(@project), :id => contact_card.contact_company.id } %>
<% else %>
<%= h contact_card.company %>
<% end %>
<% end %>
</p>
</td>
</tr>
<tr>
<td colspan="2" style="padding-left: 10px;">
<% if contact_card.phones.any? %>
<p class="phone icon icon-phone"><%= contact_card.phones.first %></p>
<% end %>
<% if contact_card.emails.any? %>
<p class="email icon icon-email"><%= mail_to contact_card.emails.first %></p>
<% end %>
<%= tag_links(contact_card.tag_list) %>
</td>
</tr>
</table>
</div>
@@ -0,0 +1,4 @@
<p><%= form.check_box :is_filter %></p>
<% if (@custom_field.respond_to?(:format) && @custom_field.format.searchable_supported) || !@custom_field.respond_to?(:format) %>
<p><%= form.check_box :searchable %></p>
<% end %>
+105
View File
@@ -0,0 +1,105 @@
<%= back_url_hidden_field_tag %>
<%= error_messages_for 'contact' %>
<div class = "box tabular" id="contact_data">
<script type="text/javascript" charset="utf-8">
function togglePerson(element) {
if (element.checked) {
$('#person_data').hide();
$('#job_title label').get(0).innerHTML ='<%= l(:field_company_field) %>';
$('#first_name label').get(0).innerHTML='<%= l(:field_company_name) %>' + '<span class="required"> *</span>';
} else {
$('#person_data').show();
$('#job_title label').get(0).innerHTML ='<%= l(:field_contact_job_title) %>';
$('#first_name label').get(0).innerHTML='<%= l(:field_contact_first_name) %>' + '<span class="required"> *</span>';
}
}
</script>
<p class="avatar extended" id="watchers">
<%= avatar_to(@contact, :size => "64", :style => "vertical-align: middle;") %>
<%= link_to image_tag('delete.png'), {:controller => 'attachments', :action => 'destroy', :id => @contact.avatar},
:data => {:confirm => l(:text_are_you_sure)},
:method => :delete,
:class => 'delete',
:style => "vertical-align: middle;",
:title => l(:button_delete) unless @contact.avatar.blank? %>
</p>
<p class="extended">
<%= label_tag l(:field_contact_avatar) %>
<span id="attachments_fields"></span>
<span class="add_attachment">
<%= file_field_tag 'dummy_file',
:size => 30,
:id => nil,
:class => 'file_selector',
:multiple => true,
:onchange => 'uploadAvatar(this);',
:data => {
:max_file_size => Setting.attachment_max_size.to_i.kilobytes,
:max_file_size_message => l(:error_attachment_too_big, :max_size => number_to_human_size(Setting.attachment_max_size.to_i.kilobytes)),
:max_concurrent_uploads => Redmine::Configuration['max_concurrent_ajax_uploads'].to_i,
:upload_path => uploads_path(:format => 'js'),
:description_placeholder => l(:label_optional_description)
} %>
</span>
</p>
<p><%= f.check_box(:is_company, :label => l(:field_contact_is_company), :onclick => "togglePerson(this)" ) %></p>
<p id="first_name"><%= f.text_field :first_name, :label => !@contact.is_company ? l(:field_contact_first_name) : l(:field_company_name), :required => true, :style => "width:90%;" %></p>
<div id="person_data" style="<%= 'display: none;' if @contact.is_company %>">
<p><%= f.text_field :middle_name, :label=>l(:field_contact_middle_name) %></p>
<p><%= f.text_field :last_name, :label=>l(:field_contact_last_name), :id => 'contact_last_name' %></p>
<p><%= f.text_field :company, :label=>l(:field_contact_company) -%></p>
<%= javascript_tag "observeAutocompleteField('contact_company', '#{escape_javascript auto_complete_companies_path}')" %>
<p class="extended"><%= f.text_field :birthday, :size => 12 %><%= calendar_for('contact_birthday') %> </p>
</div>
<p id="job_title"><%= f.text_field :job_title, :label => !@contact.is_company ? l(:field_contact_job_title) : l(:field_company_field) %></p>
<% @contact.build_address if @contact.address.blank? %>
<%= f.fields_for(:address) do |a| %>
<span class="extended">
<%= render :partial => 'common/address_form', :locals => {:f => a} %>
</span>
<% end %>
<div id="phones_fields">
<p>
<%= f.text_field :phone, :label=>l(:field_contact_phone), :style => "width:90%;" -%>
<br>
<em class="info"><%= l(:text_comma_separated) %></em>
</p>
</div>
<p>
<%= f.text_field 'email', :label=>l(:field_contact_email), :style => "width:90%;" -%>
<br>
<em class="info"><%= l(:text_comma_separated) %></em>
</p>
<p class="extended"><%= f.text_field 'website', :label=>l(:field_contact_website) -%></p>
<p class="extended"><%= f.text_field 'skype_name', :label=>l(:field_contact_skype) -%></p>
<% @contact.custom_field_values.each do |value| %>
<p class="<%= "extended" unless value.custom_field.is_required? %>">
<%= custom_field_tag_with_label :contact, value %>
</p>
<% end -%>
<p class="extended notes"><%= f.text_area :background , :cols => 80, :rows => 8, :class => 'wiki-edit', :label=>l(:field_contact_background) %></p>
<%= wikitoolbar_for 'contact_background' %>
<p class="extended">
<%= label_tag l(:label_crm_tags_plural) %>
<%= render :partial => "contacts_tags/tags_form" %>
</p>
<% if @project %>
<p class="extended"><%= f.select :assigned_to_id, (@project.assignable_users.collect {|m| [m.name, m.id]}), :include_blank => true, :label => l(:label_crm_assigned_to) %></p>
<% end %>
<p class="extended"><%= f.select :visibility, collection_for_visibility_select, :include_blank => false, :label => l(:label_crm_contacts_visibility) %></p>
<p id="show_details_link" style="display: none;"><%= link_to l(:label_crm_show_details), "javascript:void(0);", :onclick => "$('#contact_data .extended').show();" %></p>
</div>
@@ -0,0 +1,24 @@
<div id="tags_data">
<%= tag_links(@contact.tag_list) %>
<% if authorize_for('contacts', 'update') %>
<span class="contextual">
<%= link_to l(:label_crm_edit_tags), {}, :onclick => "$('#edit_tags_form').show(); $('#tags_data').hide(); return false;", :id => 'edit_tags_link' %>
</span>
<% end %>
</div>
<div id="edit_tags_form" style="display:none;">
<%= form_tag( {:controller => 'contacts',
:action => 'update',
:project_id => @project,
:id => @contact },
:method => :put,
:multipart => true ) do %>
<%= render :partial => "contacts_tags/tags_form" %>
<%= submit_tag l(:button_save), :class => "button-small" %>
<%= link_to l(:button_cancel), {}, :onclick => "$('#edit_tags_form').hide(); $('#tags_data').show(); return false;" %>
<% end %>
</div>
@@ -0,0 +1,44 @@
<%= form_tag({}, :data => {:cm_url => context_menu_contacts_path}) do %>
<%= hidden_field_tag 'back_url', url_for(params.respond_to?(:to_unsafe_hash) ? params.to_unsafe_hash : params) %>
<%= hidden_field_tag 'project_id', @project.id if @project %>
<div class="autoscroll">
<table class="list contacts">
<thead>
<tr>
<th class="checkbox hide-when-print">
<%= link_to image_tag('toggle_check.png'), {}, :onclick => 'toggleCRMIssuesSelection(this); return false;',
:title => "#{l(:button_check_all)}/#{l(:button_uncheck_all)}" %>
</th>
<% @query.columns.each do |column| %>
<%= Redmine::VERSION.to_s >= '3.4' || RedmineContacts.unstable_branch? ? column_header(@query, column) : column_header(column) %>
<% end %>
</tr>
</thead>
<% previous_group = false %>
<tbody>
<% @contacts.each do |contact| -%>
<% if @query.grouped? && (group = @query.group_by_column.value(contact)) != previous_group %>
<% reset_cycle %>
<tr class="group open">
<td colspan="<%= @query.columns.size + 2 %>">
<span class="expander" onclick="toggleRowGroup(this);">&nbsp;</span>
<%= group.blank? ? l(:label_none) : column_content(@query.group_by_column, contact) %> <span class="count">(<%= @contact_count_by_group[group] %>)</span>
<%= link_to_function("#{l(:button_collapse_all)}/#{l(:button_expand_all)}", "toggleAllRowGroups(this)", :class => 'toggle-all') %>
</td>
</tr>
<% previous_group = group %>
<% end %>
<tr id="contact-<%= h(contact.id) %>" class="contact <%= 'company' if contact.is_company %> hascontextmenu <%= cycle('odd', 'even') %>">
<td class="checkbox hide-when-print"><%= check_box_tag("selected_contacts[]", contact.id, false, :id => nil) %></td>
<% @query.columns.each do |column| %><%= content_tag 'td', column_content(column, contact), :class => column.css_classes %><% end %>
</tr>
<% end %>
</tbody>
</table>
</div>
<% end %>
@@ -0,0 +1,51 @@
<%= form_tag({}, :data => {:cm_url => context_menu_contacts_path}) do %>
<%= hidden_field_tag 'back_url', url_for(params.respond_to?(:to_unsafe_hash) ? params.to_unsafe_hash : params) %>
<%= hidden_field_tag 'project_id', @project.id if @project %>
<div class="splitcontentleft">
<% i = 0 %>
<% split_on = (@contacts.size / 2.0).ceil - 1 %>
<% @contacts.each do |contact| %>
<% @contact = contact %>
<div class="contact card">
<table class="subject_header">
<tr>
<td class="avatar"><%= contact_tag(contact, :type => "avatar", :size => 64) %></td>
<td class="name" style="vertical-align: top;">
<h2><%= contact_tag(contact, :type => "plain") %> </h2>
<p>
<%= h contact.job_title %>
<% if !contact.is_company %>
<%= " #{l(:label_crm_at_company)} " unless (contact.job_title.blank? or contact.company.blank?) %>
<% if contact.contact_company %>
<%= link_to contact.contact_company.name, {:controller => 'contacts', :action => 'show', :project_id => contact.contact_company.project(@project), :id => contact.contact_company.id } %>
<% else %>
<%= h contact.company %>
<% end %>
<% end %>
</p>
<% if contact.phones.any? %>
<p class="phone icon icon-phone"><%= contact.phones.first %></p>
<% end %>
<% if contact.emails.any? %>
<p class="email icon icon-email"><%= mail_to contact.emails.first %></p>
<% end %>
<%= tag_links(contact.tag_list) %>
</td>
</tr>
</table>
</div>
<% if i == split_on -%>
</div><div class="splitcontentright">
<% end -%>
<% i += 1 -%>
<% end -%>
</div>
<div style="clear:both;"> </div>
<% end %>
@@ -0,0 +1,54 @@
<%= form_tag({}, :data => {:cm_url => context_menu_contacts_path}) do %>
<%= hidden_field_tag 'back_url', url_for(params.respond_to?(:to_unsafe_hash) ? params.to_unsafe_hash : params) %>
<%= hidden_field_tag 'project_id', @project.id if @project %>
<div class="autoscroll">
<table class="contacts index">
<tbody>
<% previous_group = false %>
<% @contacts.each do |contact| %>
<% if @query.grouped? && (group = @query.group_by_column.value(contact)) != previous_group %>
<% reset_cycle %>
<tr class="group open">
<td colspan="<%= @query.columns.size + 2 %>">
<span class="expander" onclick="toggleRowGroup(this);">&nbsp;</span>
<%= group.blank? ? 'None' : column_content(@query.group_by_column, contact) %> <span class="count">(<%= @contact_count_by_group[group] %>)</span>
<%= link_to_function("#{l(:button_collapse_all)}/#{l(:button_expand_all)}", "toggleAllRowGroups(this)", :class => 'toggle-all') %>
</td>
</tr>
<% previous_group = group %>
<% end %>
<tr class="hascontextmenu <%= cycle('odd', 'even') %> ">
<td class="checkbox">
<%= check_box_tag "selected_contacts[]", contact.id, false, :onclick => "toggleContact(event, this);" %>
</td>
<td class="avatar">
<%= link_to avatar_to(contact, :size => "32"), contact_path(contact, :project_id => @project), :id => "avatar" %>
</td>
<td class="name">
<h1><%= link_to contact.name, contact_path(contact, :project_id => @project) %></h1>
<p>
<%= link_to contact.website, contact.website_address, :class => 'external', :only_path => true unless !contact.is_company %>
<%= mail_to contact.emails.first unless contact.is_company%>
<div><%= contact.phones.first %></div>
</p>
</td>
<td class="info">
<div class="title_and_company" >
<%= contact.job_title %>
<% if !contact.is_company %>
<%= " #{l(:label_crm_at_company)} " unless (contact.job_title.blank? or contact.company.blank?) %>
<%= contact.company %>
<% end %>
</div>
<div class="tags">
<%= tag_links(contact.tag_list) %>
<%# tag_links(RedmineCrm::TagList.from(contact.cached_tag_list)) %>
</div>
</td>
</tr>
<% end %>
</tbody>
</table>
</div>
<% end %>
@@ -0,0 +1,37 @@
<script type="text/javascript">
jQuery(function($) {
// when the #search field changes
var duplicates = function() {
var form = $("#contact_form"); // grab the form wrapping the search bar.
var url = '<%= escape_javascript(url_for({:controller => "contacts_duplicates", :action => "duplicates", :project_id => @project, :contact_id => @contact})) %>';
var formData = form.serialize();
$.get(url, formData, function(data) { // perform an AJAX get, the trailing function is what happens on successful get.
$("#duplicates").html(data); // replace the "results" div with the result of action taken
});
}
$("#contact_first_name").observe_field(2, duplicates);
$("#contact_middle_name").observe_field(2, duplicates);
$("#contact_last_name").observe_field(2, duplicates);
});
</script>
<%# observe_field("contact_first_name",
:frequency => 1,
:update => 'duplicates',
:url => {:controller => 'contacts_duplicates', :action => 'duplicates', :project_id => @project, :contact_id => @contact},
:with => "$('contact_form').serialize()") %>
<%# observe_field("contact_middle_name",
:frequency => 1,
:update => 'duplicates',
:url => {:controller => 'contacts_duplicates', :action => 'duplicates', :project_id => @project, :contact_id => @contact},
:with => "$('contact_form').serialize()") %>
<%# observe_field("contact_last_name",
:frequency => 1,
:update => 'duplicates',
:url => {:controller => 'contacts_duplicates', :action => 'duplicates', :project_id => @project, :contact_id => @contact},
:with => "$('contact_form').serialize()") %>
@@ -0,0 +1,15 @@
<h3 class="title"><%=l(:label_crm_contact_new)%></h3>
<%= labelled_form_for @contact, :url => project_contacts_path(@project), :remote => true do |f| %>
<%= hidden_field_tag :contact_field_name, params[:contact_field_name] %>
<%= hidden_field_tag :contacts_is_company, params[:contacts_is_company] %>
<%= render :partial => 'contacts/form', :locals => { :f => f } %>
<p class="buttons">
<%= submit_tag l(:button_create), :name => nil %>
<%= submit_tag l(:button_cancel), :name => nil, :onclick => "hideModal(this);", :type => 'button' %>
</p>
<% end %>
<% content_for :header_tags do %>
<%= javascript_include_tag :contacts, :plugin => 'redmine_contacts' %>
<% end %>
@@ -0,0 +1,29 @@
<%
extend Redmine::Pagination
source_id_cond = @contact.is_company ? Contact.visible.where(:company => @contact.first_name).map(&:id) << @contact.id : @contact.id
@note = Note.new(:created_on => Time.now)
scope = Note.where({:source_id => source_id_cond, :source_type => 'Contact'}).includes(:attachments).order("#{Note.table_name}.created_on DESC")
@notes_pages = Redmine::Pagination::Paginator.new(scope.count, 20, params['page'])
@notes = scope.limit(20).offset(@notes_pages.offset)
%>
<% if authorize_for(:notes, :create) %>
<div class="add-note hide-when-print">
<%= render :partial => 'notes/add', :locals => {:note_source => @contact} %>
</div>
<% end %>
<% if @contact.is_public? || authorize_for(:notes, :show) %>
<div id="comments">
<div id="notes">
<%= render :partial => 'notes/note_item', :collection => @notes, :locals => {:show_info => @contact.is_company, :note_source => @contact} %>
<span class="pagination"> <%= pagination_links_full @notes_pages %> </span>
</div>
</div>
<% other_formats_links do |f| %>
<% filtered_params = params.respond_to?(:to_unsafe_hash) ? params.to_unsafe_hash : params %>
<%= f.link_to 'Atom', :url => filtered_params.merge(:key => User.current.rss_key) %>
<% end %>
<% end %>
@@ -0,0 +1,10 @@
<div id="tags_data">
<span class="tags">
<%= render :partial => 'contacts/tags_item', :collection => tag_list, :locals => {:is_note => false} %>
</span>
<% if editable && authorize_for('contacts', 'update') %>
<span class="contextual">
<%= link_to l(:label_crm_edit_tags), {}, :onclick => "$('#edit_tags_form').show(); $('#tags_data').hide(); return false;", :id => 'edit_tags_link' %>
</span>
<% end %>
</div>
@@ -0,0 +1,7 @@
<div id="tags">
<span id="single_tags">
<h3><%= l(:label_crm_tags_plural) %></h3>
<span class="tag_list"><%= safe_join(tags_cloud.map{|tag| tag_link(tag.name, :count => tag.count)}, ContactsSetting.monochrome_tags? ? ', ' : ' ').html_safe %></span>
</span>
</div>
@@ -0,0 +1,19 @@
<%
html_options = {:id => "tag_#{tags_item.id}",
:style => "background-color: #{tags_item.color_name}"}
taggable_type ||= 'contacts'
tag_url = {:controller => taggable_type,
:action => 'index',
:set_filter => 1,
:fields => [:tags],
:values => {:tags => [tags_item.name]},
:operators => {:tags => '='}}
%>
<span class="tag" >
<%- if !is_note -%>
<%= link_to tags_item.name + "#{"(" + tags_item.count.to_s + ")" if tags_item.count > 0}", {:project_id => @project}.merge!(tag_url), html_options %>
<%- else -%>
<%= link_to tags_item.name, {:controller => "contacts", :action => "contacts_notes", :project_id => @project, :tag => tags_item.name}, html_options %>
<%- end -%>
</span>
@@ -0,0 +1,130 @@
<h2><%= l(:label_crm_bulk_edit_selected_contacts) %></h2>
<div class="box" id="duplicates">
<ul>
<% @contacts.each do |contact| %>
<li>
<%= avatar_to contact, :size => "16" %>
<%= link_to_source contact %>,
<%= h contact.job_title %>
<%= " #{l(:label_crm_at_company)} " unless (contact.job_title.blank? or contact.company.blank?) %>
<% if contact.contact_company %>
<%= link_to contact.contact_company.name, {:controller => 'contacts', :action => 'show', :id => contact.contact_company.id } %>
<% else %>
<%= h contact.company %>
<% end %>
<%= "(#{l(:field_contact_tag_names)}: #{contact.tag_list})" if contact.tags.any? %>
</li>
<% end %>
</ul>
</div>
<%= form_tag(:action => 'bulk_update', :project_id => @project) do %>
<%= @contacts.collect {|i| hidden_field_tag('ids[]', i.id)}.join.html_safe %>
<div class="box tabular">
<fieldset class="attributes">
<legend><%= l(:label_change_properties) %></legend>
<div class="splitcontentleft">
<p>
<label><%= l(:field_company) %></label>
<%= text_field_tag('contact[company]', '') %>
<%= javascript_tag "observeAutocompleteField('contact_company', '#{escape_javascript auto_complete_companies_path(:project_id => @project)}')" %>
</p>
<% @custom_fields.each do |custom_field| %>
<p><label><%= h(custom_field.name) %></label> <%= custom_field_tag_for_bulk_edit('contact', custom_field, @projects) %></p>
<% end %>
<p>
<label><%= l(:label_crm_assigned_to) %></label>
<%= select_tag('contact[assigned_to_id]', content_tag('option', l(:label_no_change_option), :value => '') +
content_tag('option', l(:label_nobody), :value => 'none') +
options_from_collection_for_select(@assignables, :id, :name)) %>
</p>
<p>
<label><%= l(:label_crm_contacts_visibility) %></label>
<%= select_tag 'contact[visibility]', options_for_select(collection_for_visibility_select) %>
</p>
</div>
<div class="splitcontentright">
<p>
<label><%= l(:field_contact_job_title) %>/<%= l(:field_company_field) %></label>
<%= text_field_tag('contact[job_title]', '') %>
</p>
<p class="address city">
<label><%= l(:label_crm_city) %></label>
<%= text_field_tag 'contact[address_attributes][city]' -%>
</p>
<p class="address region">
<label><%= l(:label_crm_region) %></label>
<%= text_field_tag 'contact[address_attributes][region]' -%>
</p>
<p class="address country">
<label><%= l(:label_crm_country) %></label>
<%= select_tag 'contact[address_attributes][country_code]', options_for_select(l(:label_crm_countries).map{|k, v| [v, k]}), :include_blank => true -%>
</p>
</div>
</fieldset>
<fieldset class="attributes">
<legend><%= l(:label_crm_tags_plural) %></legend>
<div class="splitcontentleft">
<p id="add_tags" class="contacts-tags-edit">
<label><%= l(:field_add_tags) %></label>
<%= text_field_tag 'add_tag_list', '', :size => 10, :class => "hol" %><%= tagsedit_with_source_for("#add_tag_list", auto_complete_contact_tags_path(:project_id => @project)) %>
</p>
</div>
<div class="splitcontentright">
<p id="delete_tags" class="contacts-tags-edit">
<label><%= l(:field_delete_tags) %></label>
<%= text_field_tag 'delete_tag_list', '', :label => :field_contact_tag_names, :size => 10, :class => "hol" %><%= tagsedit_with_source_for("#delete_tag_list", auto_complete_contact_tags_path(:project_id => @project)) %>
</p>
</div>
</fieldset>
<% if @add_projects.any? %>
<fieldset class="attributes">
<legend><%= l(:label_project_plural) %></legend>
<div class="splitcontentleft">
<p>
<label><%= l(:label_crm_add_into) %></label>
<%= select_tag 'add_projects_list[]', content_tag('option', l(:label_no_change_option), :value => '', :selected => 'selected') + project_tree_options_for_select(@add_projects), :multiple => false %>
</p>
</div>
<div class="splitcontentright">
<p>
<label><%= l(:label_crm_delete_from) %></label>
<%= select_tag 'delete_projects_list[]', content_tag('option', l(:label_no_change_option), :value => '', :selected => 'selected') + project_tree_options_for_select(@add_projects), :multiple => false %>
</p>
</div>
</fieldset>
<% end %>
<fieldset><legend><%= l(:field_notes) %></legend>
<%= text_area_tag 'note[content]', '', :cols => 60, :rows => 10, :class => 'wiki-edit' %>
<%= wikitoolbar_for 'note_content' %>
</fieldset>
</div>
<p><%= submit_tag l(:button_submit) %></p>
<% end %>
@@ -0,0 +1,64 @@
<% filtered_params = params.respond_to?(:to_unsafe_hash) ? params.to_unsafe_hash : params %>
<div class="filters">
<% if !@tag %>
<%= form_tag(filtered_params, :id => "query_form", :method => :get) do %>
<%= hidden_field_tag('project_id', @project.to_param) if @project %>
<h2>
<span class="scope_title">
<%= l(:label_crm_contact_all_note_plural) %>
</span>
<span class="live_search">
<%= text_field_tag(:search_note, params[:search_note], :autocomplete => "off", :class => "live_search_field", :placeholder => l(:label_crm_contact_search) ) %>
<script type="text/javascript">
jQuery(function($) {
// when the #search field changes
$("#search_note").observe_field(2, function() {
var form = $("#query_form"); // grab the form wrapping the search bar.
var url = form.attr("action");
var formData = form.serialize();
$.get(url, formData, function(data) { // perform an AJAX get, the trailing function is what happens on successful get.
$("#contacts_notes").html(data); // replace the "results" div with the result of action taken
});
});
});
</script>
</span>
</h2>
<% end %>
<% else %>
<h2 class="scope_title"><%= "#{l(:label_crm_contact_tag)}(#{@notes_pages.item_count}): #{tag_links(@tag)}".html_safe %> </h2>
<% end %>
</div>
<div id="contacts_notes">
<%= render :partial => 'notes/notes_list' %>
</div>
<% other_formats_links do |f| %>
<%= f.link_to 'Atom', :url => filtered_params.merge(:key => User.current.rss_key) %>
<%= f.link_to 'CSV', :url => filtered_params %>
<% end %>
<% content_for :sidebar do %>
<%= render :partial => 'common/sidebar' %>
<h3><%= l(:label_crm_note_plural) %></h3>
<div id="note_types">
<% collection_for_note_types_select.each do |note_type| %>
<%= radio_button_tag "note_type", note_type[1], filtered_params[:type_id].to_s == note_type[1].to_s, {:onchange => "document.location='#{url_for(filtered_params.merge(:type_id => note_type[1]))}';", :id => "note_type_#{note_type[1]}" }%>
<%= label_tag "note_type_#{note_type[1]}", note_type[0] %>
<br>
<% end %>
</div>
<h3><%= l(:label_crm_tags_plural) %></h3>
<div id="tags">
<span class="tag_list"><%= @tags.map{|tag| content_tag(:span, link_to(tag.name, {:controller => "contacts", :action => "contacts_notes", :project_id => @project, :tag => tag.name}), {}.merge(ContactsSetting.monochrome_tags? ? {:class => "tag-label"} : {:class => "tag-label-color", :style => "background-color: #{tag_color(tag.name)}"}))}.join(' ').html_safe %></span>
</div>
<%= render :partial => 'common/recently_viewed' %>
<% end %>
<% content_for(:header_tags) do %>
<%= javascript_include_tag :contacts, :plugin => 'redmine_contacts' %>
<%= stylesheet_link_tag :contacts_sidebar, :plugin => 'redmine_contacts' %>
<% end %>
@@ -0,0 +1,35 @@
<ul>
<%= call_hook(:view_contacts_context_menu_start, {:contacts => @contacts, :can => @can, :back => @back }) %>
<% unless @contact.nil? %>
<li><%= context_menu_link l(:button_edit), {:controller => 'contacts', :action => 'edit', :id => @contact, :project_id => @project}, :class => 'icon-edit', :disabled => !@can[:edit] %></li>
<% if User.current.logged? %>
<li><%= watcher_link(@contact, User.current) %></li>
<% end %>
<% if !@project.nil? %>
<li><%= context_menu_link l(:label_crm_deal_new), {:controller => 'deals', :action => 'new', :project_id => @project, :contact_id => @contact},
:class => 'icon-add-deal', :disabled => !@can[:create_deal] %></li>
<% if @contact.is_company? %>
<li><%= context_menu_link l(:label_crm_add_contact), {:controller => 'contacts', :action => 'new', :project_id => @project, :contact => {:company => @contact.name}},
:class => 'icon-company-contact', :disabled => !@can[:create] %></li>
<% end %>
<% end %>
<% else %>
<li><%= context_menu_link l(:button_edit), {:controller => 'contacts', :action => 'bulk_edit', :ids => @contacts.collect(&:id)},
:class => 'icon-edit', :disabled => !@can[:edit] %></li>
<% end %>
<li><%= context_menu_link l(:label_crm_send_mail), {:controller => 'contacts', :action => 'edit_mails', :ids => @contacts.collect(&:id), :project_id => @project}, :class => 'icon-email', :disabled => !@can[:send_mails] %></li>
<%= call_hook(:view_contacts_context_menu_before_delete, {:contacts => @contacts, :can => @can, :back => @back }) %>
<li><%= context_menu_link l(:button_delete), {:controller => 'contacts', :action => 'bulk_destroy', :ids => @contacts.collect(&:id), :project_id => @project},
:method => :delete, :data => {:confirm => l(:text_are_you_sure)}, :class => 'icon-del', :disabled => !@can[:delete] %></li>
<% if !@contact && Redmine::VERSION.to_s >= '3.3' %>
<li>
<%= context_menu_link l(:button_filter), _project_contacts_path(@project, :set_filter => 1, :ids => @contacts.map(&:id).join(',')),
:class => 'icon-list' %>
</li>
<% end %>
<%= call_hook(:view_contacts_context_menu_end, {:contacts => @contacts, :can => @can, :back => @back }) %>
</ul>
@@ -0,0 +1,13 @@
hideModal();
<% field_id = params[:contact_field_name].to_s.gsub("[", "_").gsub("]", "") -%>
$('select#<%= field_id %>')
.append($("<option></option>")
.attr("value",'<%= @contact.id %>')
.attr("selected",'selected')
.text('<%= @contact.name %>'));
$('input#<%= field_id %>').val('<%= @contact.id %>');
$('#<%= field_id %>_selected_contact').text('<%= @contact.name %>');
$('#<%= field_id %>_selected_contact').show();
$('#<%= field_id %>_selected_contact').scrollTop( 0 );
$('input#<%= field_id %>').hide();
$('#<%= field_id %>_edit_link').show();
+28
View File
@@ -0,0 +1,28 @@
<div class="contextual">
<%= link_to_if_authorized l(:label_crm_merge_duplicate_plural), {:controller => 'contacts_duplicates', :action => 'index', :project_id => @project, :contact_id => @contact}, :class => 'icon icon-merge' unless @contact.new_record? %>
</div>
<h2><%= l(:label_crm_contact_edit_information) %></h2>
<%= labelled_form_for :contact, @contact,
:url => {:action => 'update', :project_id => @project, :id => @contact},
:html => { :multipart => true, :method => :put, :id => "contact_form" } do |f| %>
<%= render :partial => 'form', :locals => {:f => f} %>
<%= render :partial => 'name_observer' %>
<%= submit_tag l(:button_save) -%>
<% end -%>
<% content_for :sidebar do %>
<%= render :partial => 'common/sidebar' %>
<%= render :partial => 'contacts_duplicates/duplicates' %>
<div id="contact_projects">
<%= render :partial => 'contacts_projects/related' %>
</div>
<% end %>
<% content_for :header_tags do %>
<%= javascript_include_tag 'attachments' %>
<%= javascript_include_tag :contacts, :plugin => 'redmine_contacts' %>
<%= stylesheet_link_tag :contacts_sidebar, :plugin => 'redmine_contacts' %>
<%= robot_exclusion_tag %>
<% end %>
@@ -0,0 +1,64 @@
<h2><%= l(:label_crm_bulk_send_mail_selected_contacts) %></h2>
<div class="box" id="duplicates">
<ul>
<% @contacts.each do |contact| %>
<li>
<%= avatar_to contact, :size => "16" %>
<%= link_to_source contact %>
<%= "(#{contact.job_title}) " unless contact.job_title.blank? %>
- <%= contact.emails.first %>
</li>
<% end %>
</ul>
</div>
<%= form_for(:email_message, :url => {:action => 'send_mails', :project_id => @project}, :html => {:multipart => true, :id => 'message-form'}) do %>
<%= @contacts.collect {|i| hidden_field_tag('ids[]', i.id)}.join.html_safe %>
<div class="box tabular">
<p>
<label><%= l(:field_mail_from) %></label>
<%= text_field_tag('from', "#{User.current.name} <#{User.current.mail}>", :style => "width: 98%;") %>
<%= link_to "#{l(:label_crm_contacts_cc)}/#{l(:label_crm_contacts_bcc)}", '#' , :onclick => "$('#mail_cc').show();$(this).hide();" %>
</p>
<span id="mail_cc" style="display:none;">
<p>
<label><%= l(:label_crm_contacts_cc) %></label>
<%= text_field_tag('cc', '', :style => "width: 98%;") %>
</p>
<p>
<label><%= l(:label_crm_contacts_bcc) %></label>
<%= text_field_tag('bcc', '', :style => "width: 98%;") %>
</p>
</span>
<p>
<label><%= l(:field_subject) %></label>
<%= text_field_tag('subject', '', :id => "subject", :style => "width: 98%;") %>
</p>
<p>
<label><%= l(:field_message) %></label>
<%= text_area_tag 'message-content', '', :cols => 60, :rows => 10, :class => 'wiki-edit' %>
<em class="info"><%= l(:text_email_macros, :macro => "%%NAME%%, %%LAST_NAME%%, %%MIDDLE_NAME%%, %%FULL_NAME%%, %%COMPANY%%, %%DATE%%, %%[Custom field]%%") %></em>
</p>
<%= wikitoolbar_for 'message-content' %>
<p id="attachments_form"><%= label_tag('attachments[1][file]', l(:label_attachment_plural))%><%= render :partial => 'attachments/form' %></p>
</div>
<p>
<%= submit_tag l(:button_submit) %>
<%= preview_link({ :controller => 'contacts', :action => 'preview_email' }, 'message-form') %>
</p>
<% end %>
<div id="preview" class="wiki"></div>
<% content_for :header_tags do %>
<%= javascript_include_tag :contacts, :plugin => 'redmine_contacts' %>
<% end %>
@@ -0,0 +1,53 @@
api.array :contacts, api_meta(:total_count => @contacts_count, :offset => @offset, :limit => @limit) do
@contacts.each do |contact|
api.contact do
api.id contact.id
api.avatar(:attachment_id => contact.avatar.id) if contact.avatar
api.is_company contact.is_company
api.first_name contact.first_name
api.last_name contact.last_name
api.middle_name contact.middle_name
api.company contact.company
api.website contact.website
api.skype_name contact.skype_name
api.birthday contact.birthday
api.job_title contact.job_title
api.background contact.background
api.author(:id => contact.author_id, :name => contact.author.name) unless contact.author.nil?
api.assigned_to(:id => contact.assigned_to_id, :name => contact.assigned_to.name) unless contact.assigned_to.nil?
api.address do
api.full_address contact.address
api.street contact.street1
api.city contact.city
api.region contact.region
api.country contact.country
api.country_code contact.address.country_code unless contact.address.blank?
api.postcode contact.postcode
end
api.array :phones do
contact.phones.each do |phone|
api.phone do
api.number phone
end
end
end if contact.phones.any?
api.array :emails do
contact.emails.each do |email|
api.email do
api.address email
end
end
end if contact.emails.any?
api.tag_list contact.tag_list
render_api_custom_values contact.custom_field_values, api
api.created_on contact.created_on
api.updated_on contact.updated_on
end
end
end
+203
View File
@@ -0,0 +1,203 @@
<% filtered_params = params.respond_to?(:to_unsafe_hash) ? params.to_unsafe_hash : params %>
<div class="contextual">
<% if !@query.new_record? && @query.editable_by?(User.current) %>
<%= link_to l(:button_contacts_edit_query), edit_crm_query_path(@query, :object_type => "contact"), :class => 'icon icon-edit' %>
<%= link_to l(:button_contacts_delete_query), crm_query_path(@query, :object_type => "contact"), :data => {:confirm => l(:text_are_you_sure)}, :method => :delete, :class => 'icon icon-del' %>
<% end %>
<%= link_to_if_authorized l(:label_crm_contact_new), {:controller => 'contacts', :action => 'new', :project_id => @project}, :class => 'icon icon-add' %>
<%= link_to_if_authorized l(:label_crm_import), {:controller => 'contact_imports', :action => 'new', :project_id => @project}, :class => 'icon icon-import', :id => 'import_from_csv' %>
<%= call_hook(:view_contacts_action_menu) %>
</div>
<% html_title(@query.new_record? ? l(:label_contact_plural) : @query.name) %>
<%= form_tag({ :controller => 'contacts', :action => 'index', :project_id => @project }, :method => :get, :id => 'query_form') do %>
<script type="text/javascript">
jQuery(function($) {
// when the #search field changes
$("#search").observe_field(2, function() {
var form = $("#query_form"); // grab the form wrapping the search bar.
var url = form.attr("action");
form.find('[name="c[]"] option').each(function(i, elem){
$(elem).attr('selected', true)
})
var formData = form.serialize();
form.find('[name="c[]"] option').each(function(i, elem){
$(elem).attr('selected', false)
})
$.get(url, formData, function(data) { // perform an AJAX get, the trailing function is what happens on successful get.
$("#contact_list").html(data); // replace the "results" div with the result of action taken
});
});
});
</script>
<h2 class="contacts_header">
<span id='scope_header' class="scope_title">
<%= @query.new_record? ? l(:label_contact_plural) : h(@query.name) %>
</span>
<span class="live_search">
<%= text_field_tag(:search, params[:search], :autocomplete => "off", :class => "live_search_field", :placeholder => l(:label_crm_contact_search) ) %>
</span>
<span class="tags">
<%= tag_links(@filter_tags) %>
</span>
</h2>
<%= hidden_field_tag 'set_filter', '1' %>
<%= hidden_field_tag 'object_type', 'contact' %>
<div id="query_form_content" class="hide-when-print">
<fieldset id="filters" class="collapsible <%= @query.new_record? ? "" : "collapsed" %>">
<legend onclick="toggleFieldset(this);"><%= l(:label_filter_plural) %></legend>
<div style="<%= @query.new_record? ? "" : "display: none;" %>">
<%= render :partial => 'queries/filters', :locals => {:query => @query} %>
</div>
</fieldset>
<fieldset class="collapsible collapsed">
<legend onclick="toggleFieldset(this);"><%= l(:label_options) %></legend>
<div style="display: none;">
<table>
<tr style="<%= 'display: none;' if contacts_list_style != 'list' %>">
<td><%= l(:field_column_names) %></td>
<td><%= render_query_columns_selection(@query) %></td>
</tr>
<tr>
<% if contacts_list_style != 'list_cards' %>
<td><label for='group_by'><%= l(:field_group_by) %></label></td>
<td><%= select_tag('group_by', options_for_select([[]] + @query.groupable_columns.collect {|c| [c.caption, c.name.to_s]}, @query.group_by)) %></td>
<% end -%>
<% if contacts_list_style != 'list' %>
<td><label for='sort'><%= l(:label_sort) %></label></td>
<td><%= select_tag('sort',
options_for_select(
[[]] +
[[l(:field_contact_job_title), "job_title"],
[l(:field_contact_company), "company"],
[l(:field_created_on), "created_on:desc"],
[l(:field_updated_on), "updated_on:desc"]],
params[:sort])
) %></td>
<% end %>
</tr>
<tr>
<td><label for='contacts_list_style'><%= l(:label_crm_list_partial_style) %></label></td>
<td><%= select_tag('contacts_list_style', options_for_select(contact_list_styles_for_select, contacts_list_style)) %></td>
</tr>
</table>
</div>
</fieldset>
</div>
<p class="buttons hide-when-print">
<%= link_to_function l(:button_apply), 'submit_query_form("query_form")', :class => 'icon icon-checked' %>
<%= link_to l(:button_clear), { :set_filter => 1, :project_id => @project }, :class => 'icon icon-reload' %>
<% if @query.new_record? && User.current.allowed_to?(:save_contacts_queries, @project, :global => true) %>
<%= link_to_function l(:button_save),
"$('#query_form').attr('action', '#{ @project ? new_project_crm_query_path(@project) : new_crm_query_path }'); submit_query_form('query_form')",
:class => 'icon icon-save' %>
<% end %>
</p>
<% end %>
<%= error_messages_for 'query' %>
<% if @query.valid? %>
<div id="contact_list">
<% if @contacts.empty? %>
<p class="nodata"><%= l(:label_no_data) %></p>
<% else %>
<%= render :partial => contacts_list_style %>
<span class="pagination"><%= pagination_links_full @contacts_pages, @contacts_count %></span>
<% end %>
</div>
<% if User.current.allowed_to?(:export_contacts, @project, :global => true) %>
<% other_formats_links do |f| %>
<%= f.link_to 'Atom', :url => filtered_params.merge(:key => User.current.rss_key) %>
<% if contacts_list_style == 'list' %>
<%= f.link_to 'CSV', :url => filtered_params, :onclick => "showModal('csv-export-options', '350px'); return false;" %>
<% else %>
<%= f.link_to 'CSV', :url => filtered_params %>
<% end %>
<%- if ContactsSetting.vcard? -%>
<%= f.link_to 'VCF', :url => filtered_params %>
<%- end -%>
<%- if ContactsSetting.spreadsheet? -%>
<%= f.link_to 'XLS', :url => filtered_params %>
<%- end -%>
<% end %>
<div id="csv-export-options" style="display:none;">
<h3 class="title">
<%= l(:label_export_options, :export_format => 'CSV') %>
</h3>
<%= form_tag({:controller => 'contacts',
:action => 'index',
:project_id => @project,
:format => 'csv'},
:method => :get,
:id => 'csv-export-form') do %>
<% columns_name = 'c[]' %>
<% if Redmine::VERSION::STRING > '3.2.1' %>
<%= query_as_hidden_field_tags(@query) %>
<% if Redmine::VERSION::STRING < '3.4' %>
<%= hidden_field_tag 'sort', @sort_criteria.to_param, :id => nil %>
<% columns_name = 'csv[columns]' %>
<% end %>
<% elsif Redmine::VERSION::STRING < '3.2' %>
<% columns_name = 'columns' %>
<% end %>
<p>
<label>
<%= radio_button_tag columns_name, '', true %>
<%= l(:description_selected_columns) %>
</label>
<br />
<label>
<%= radio_button_tag columns_name, 'all_inline' %>
<%= l(:description_all_columns) %>
</label>
</p>
<p class="buttons">
<%= submit_tag l(:button_export),
:name => nil,
:onclick => "hideModal(this);" %>
<%= submit_tag l(:button_cancel),
:name => nil,
:onclick => "hideModal(this);",
:type => 'button' %>
</p>
<% end %>
</div>
<% end %>
<% end %>
<% content_for :sidebar do %>
<%= render :partial => 'common/sidebar' %>
<%= render :partial => 'tags_cloud', :object => @tags %>
<%= render_sidebar_crm_queries('contact') %>
<%= render :partial => 'notes/last_notes', :object => @last_notes %>
<%= render :partial => 'common/recently_viewed' %>
<%= call_hook(:view_contacts_sidebar_contacts_list_bottom) %>
<% end %>
<% content_for(:header_tags) do %>
<%= javascript_include_tag :contacts, :plugin => 'redmine_contacts' %>
<%= stylesheet_link_tag :contacts_sidebar, :plugin => 'redmine_contacts' %>
<%= auto_discovery_link_tag(:atom, {:format => 'atom', :key => User.current.rss_key}, :title => l(:label_contact_plural)) %>
<% end %>
<% if Redmine::VERSION.to_s >= '3.4' || RedmineContacts.unstable_branch? %>
<%= context_menu %>
<% else %>
<%= context_menu url_for( {:controller => "contacts", :action => "context_menu"} ) %>
<% end %>
@@ -0,0 +1,5 @@
<%
@tab = params[:tab_name]
@partial = params[:partial]
%>
$('#tab-placeholder-<%= @tab %>').html("<%= j(render :partial => @partial) %>")
+23
View File
@@ -0,0 +1,23 @@
<h2><%= l(:label_crm_contact_new) %></h2>
<%= labelled_form_for :contact, @contact, :url => {:action => 'create', :project_id => @project}, :html => { :multipart => true, :id => 'contact_form'} do |f| %>
<%= render :partial => 'form', :locals => {:f => f} %>
<%= render :partial => 'name_observer' %>
<%= submit_tag l(:button_save) -%>
<%= submit_tag l(:button_create_and_continue), :name => 'continue' %>
<% end -%>
<% content_for :sidebar do %>
<%= render :partial => 'common/sidebar' %>
<%= render :partial => 'contacts_duplicates/duplicates' %>
<%= render :partial => 'contacts_vcf/load' %>
<% end %>
<% content_for :header_tags do %>
<%= javascript_include_tag 'attachments' %>
<%= javascript_include_tag :contacts, :plugin => 'redmine_contacts' %>
<%= stylesheet_link_tag :contacts_sidebar, :plugin => 'redmine_contacts' %>
<%= robot_exclusion_tag %>
<% end %>
@@ -0,0 +1,9 @@
$('#ajax-modal').html('<%= escape_javascript(render :partial => 'contacts/new_modal') %>');
$('#ajax-modal #contact_data .extended').hide();
$('#ajax-modal #contact_data #show_details_link').show();
showModal('ajax-modal', '800px');
$('#new_contact').submit( function(event) {
$('.file_selector').val('');
event.preventDefault();
});
@@ -0,0 +1,110 @@
api.contact do
api.id @contact.id
api.avatar(:attachment_id => @contact.avatar.id) if @contact.avatar
api.is_company @contact.is_company
api.first_name @contact.first_name
api.last_name @contact.last_name
api.middle_name @contact.middle_name
api.company @contact.company
api.website @contact.website
api.skype_name @contact.skype_name
api.birthday @contact.birthday
api.job_title @contact.job_title
api.background @contact.background
api.author(:id => @contact.author_id, :name => @contact.author.name) unless @contact.author.nil?
api.assigned_to(:id => @contact.assigned_to_id, :name => @contact.assigned_to.name) unless @contact.assigned_to.nil?
api.address do
api.full_address @contact.address
api.street @contact.street1
api.city @contact.city
api.region @contact.region
api.country @contact.country
api.country_code @contact.address.country_code unless @contact.address.blank?
api.postcode @contact.postcode
end
api.array :phones do
@contact.phones.each do |phone|
api.phone do
api.number phone
end
end
end if @contact.phones.any?
api.array :emails do
@contact.emails.each do |email|
api.email do
api.address email
end
end
end if @contact.emails.any?
api.tag_list @contact.tag_list
render_api_custom_values @contact.custom_field_values, api
api.created_on @contact.created_on
api.updated_on @contact.updated_on
api.array :projects do
@contact.projects.each do |project|
api.project(:id => project.id, :name => project.name)
end
end if @contact.projects.present?
if authorize_for(:notes, :show)
api.array :notes do
@contact.notes.each do |note|
api.note do
api.id note.id
api.content note.content
api.type_id note.type_id
api.author(:id => note.author_id, :name => note.author.name) unless note.author.nil?
api.created_on note.created_on
api.updated_on note.updated_on
end
end
end if include_in_api_response?('notes') && @contact.notes.present? && User.current.allowed_to?(:view_contacts, @project)
end
api.array :contacts do
@contact.company_contacts.each do |contact|
api.contact(:id => contact.id, :name => contact.name )
end
end if include_in_api_response?('contacts') && @contact.company_contacts.present?
api.array :deals do
(@contact.related_deals + @contact.deals).each do |deal|
api.deal do
api.id deal.id
api.price deal.price
api.currency deal.currency
api.price_type deal.price_type
api.name deal.name
api.project(:id => deal.project.id, :name => deal.project.name)
api.status(:id => deal.status.id, :name => deal.status.name)
api.background deal.background
api.created_on deal.created_on
api.updated_on deal.updated_on
end
end
end if include_in_api_response?('deals') && (@contact.related_deals + @contact.deals).present? && User.current.allowed_to?(:view_deals, @project)
if authorize_for(:issues, :show)
api.array :issues do
@contact.issues.each do |issue|
api.issue do
api.id issue.id
api.subject issue.subject
api.status(:id => issue.status_id, :name => issue.status.name) unless issue.status.nil?
api.due_date issue.due_date
api.created_on issue.created_on
api.updated_on issue.updated_on
end
end
end if include_in_api_response?('issues') && @contact.issues.present? && User.current.allowed_to?(:view_issues, @project)
end
call_hook(:api_contacts_show)
end
+86
View File
@@ -0,0 +1,86 @@
<%= error_messages_for 'contact', 'note' %>
<% html_title "#{l(:label_contact)} ##{@contact.id}: #{@contact.name}" %>
<div class="contextual">
<%= call_hook(:view_contacts_before_actions, :contact => @contact, :project => @project) %>
<%= link_to l(:label_profile), user_path(@contact.redmine_user), :class => 'icon icon-user' unless @contact.redmine_user.blank? %>
<%= link_to(l(:button_create), {:controller => 'users', :action => 'new_from_contact', :contact_id => @contact.id, :id => 'current'}, :class => 'icon icon-user') if (User.current.admin? && @contact.redmine_user.blank? && !@contact.email.blank?) %>
<%= link_to_if_authorized l(:label_crm_send_mail), {:controller => 'contacts', :action => 'edit_mails', :ids => [@contact.id], :project_id => @project}, :class => 'icon icon-email' unless @contact.primary_email.blank? %>
<%= watcher_link(@contact, User.current) %>
<%= link_to l(:button_edit), {:controller => 'contacts', :action => 'edit', :project_id => @project, :id => @contact}, :class => 'icon icon-edit' if @contact.editable? %>
<%= link_to l(:button_delete), {:controller => 'contacts', :action => 'destroy', :project_id => @project, :id => @contact}, :data => {:confirm => l(:text_are_you_sure)}, :method => :delete, :class => 'icon icon-del' if @contact.deletable? %>
<%= call_hook(:view_contacts_after_actions, :contact => @contact, :project => @project) %>
</div>
<h2><%= !@contact.is_company ? l(:label_contact) : l(:label_crm_company) %> #<%= @contact.id %></h2>
<div class="contact details<%= ' private' if @contact.is_private? %>">
<table class="subject_header">
<tr>
<td class="avatar"><%= avatar_to(@contact, :size => "64", :full_size => true) %></td>
<td class="name" style="vertical-align: top;">
<h1><%= h @contact.name %></h1>
<% if !@contact.is_company %>
<p>
<%= h @contact.job_title %>
<%= " #{l(:label_crm_at_company)} " unless (@contact.job_title.blank? or @contact.company.blank?) %>
<% if @contact.contact_company %>
<%= link_to @contact.contact_company.name, {:controller => 'contacts', :action => 'show', :project_id => @contact.contact_company.project(@project), :id => @contact.contact_company.id } %>
<% else %>
<%= h @contact.company %>
<% end %>
</p>
<% end %>
<%= render :partial => 'form_tags', :object => @contact.tags, :locals => {:editable => true} %>
</td>
<% if @contact.phones.any? || @contact.emails.any? %>
<td class="subject_info">
<ul>
<% if @contact.phones.any? %>
<li class="phone icon icon-phone"><%= @contact.phones.first %></li>
<% end %>
<% if @contact.emails.any? %>
<li class="email icon icon-email"><%= mail_to @contact.emails.first %></li>
<% end %>
</ul>
</td>
<% end %>
</tr>
</table>
<%= call_hook(:view_contacts_show_details_bottom, :contact => @contact) %>
</div>
<%= render_contact_tabs contact_tabs(@contact) %>
<% content_for :sidebar do %>
<%= render :partial => 'common/sidebar' %>
<%= render :partial => 'attributes' %>
<%= call_hook(:view_contacts_sidebar_after_attributes, :contact => @contact) %>
<%= render :partial => 'contacts_issues/issues', :locals => {:contact => @contact, :issues => @contact_issues} %>
<%= call_hook(:view_contacts_sidebar_after_tasks, :contact => @contact) %>
<%= render :partial => 'common/notes_attachments', :object => @contact.notes_attachments %>
<%= call_hook(:view_contacts_sidebar_after_notes_attachments, :contact => @contact) %>
<% if !@contact.background.blank? %>
<h3><%= l(:label_crm_background_info) %></h3>
<div class="wiki"><%= textilizable(@contact, :background) %></div>
<% end %>
<div id="contact_projects">
<%= render :partial => 'contacts_projects/related' %>
</div>
<%= render :partial => 'common/recently_viewed' %>
<% end %>
<% content_for :header_tags do %>
<%= javascript_include_tag :contacts, :plugin => 'redmine_contacts' %>
<%= stylesheet_link_tag :contacts_sidebar, :plugin => 'redmine_contacts' %>
<%= auto_discovery_link_tag(:atom, {:format => 'atom', :key => User.current.rss_key}, :title => "#{@contact.name} - ##{@contact.id}") %>
<% end %>