mirror of
https://github.com/rickbarrette/redmine_qbo_vehicles.git
synced 2026-04-02 15:11:58 -04:00
Compare commits
6 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| a709fecd0c | |||
| 6db87dd551 | |||
| a73b6cd438 | |||
| f163f6518b | |||
| a89f9881a6 | |||
| ed38584ab2 |
@@ -50,9 +50,10 @@ class Vehicle < ActiveRecord::Base
|
|||||||
write_attribute(:vin, val)
|
write_attribute(:vin, val)
|
||||||
end
|
end
|
||||||
|
|
||||||
# search for a vin
|
# search for a vehicle by vin, make, model, or year
|
||||||
def self.search(search)
|
def self.search(query)
|
||||||
where("vin LIKE ?", "%#{search}%")
|
q = sanitize_sql_like(query)
|
||||||
|
where("vin LIKE ? OR make LIKE ? OR model LIKE ? OR year LIKE ?", "%#{q}%", "%#{q}%", "%#{q}%", "%#{q}%")
|
||||||
end
|
end
|
||||||
|
|
||||||
# decodes a vin and updates self
|
# decodes a vin and updates self
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
<h4><%=t(:field_vehicles)%>:</h4>
|
<h4><%=t(:field_vehicles)%>:</h4>
|
||||||
<%= render partial: 'vehicles/list', locals: { vehicles: customer.vehicles.paginate(page: params[:page]) } %>
|
<%= render partial: 'vehicles/list', locals: { vehicles: customer.vehicles.paginate(page: params[:page]), show_customer: false, show_checkbox: false } %>
|
||||||
<div style="float: right;">
|
<div style="float: right;">
|
||||||
<%= button_to t(:button_new_vehicle), new_customer_vehicle_path(customer), method: :get %>
|
<%= button_to t(:button_new_vehicle), new_customer_vehicle_path(customer), method: :get %>
|
||||||
</div>
|
</div>
|
||||||
@@ -6,7 +6,7 @@
|
|||||||
<div class="vehicle_vin attribute">
|
<div class="vehicle_vin attribute">
|
||||||
<div class="label"><%=t(:field_vin)%>:</div>
|
<div class="label"><%=t(:field_vin)%>:</div>
|
||||||
<div class="value" id="vin">
|
<div class="value" id="vin">
|
||||||
<a href="#" id="copyLink" onclick="handleCopy(event)"><%=split_vin[0] if split_vin%><b><%=split_vin[1] if split_vin%></b></a>
|
<div id="copyLink" onclick="handleCopy(event)"><%=split_vin[0] if split_vin%><b><%=split_vin[1] if split_vin%></b></div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -18,8 +18,8 @@
|
|||||||
|
|
||||||
<tr>
|
<tr>
|
||||||
<th><%= t(:field_vin) %></th>
|
<th><%= t(:field_vin) %></th>
|
||||||
<td id="vin">
|
<td>
|
||||||
<a href="#" onclick="handleCopy(event)"><%= @vin[0] if @vin %><b><%=@vin[1] if @vin%></b></a>
|
<div onclick="handleCopy(event)"><%= @vin[0] if @vin %><b><%=@vin[1] if @vin%></b></div>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
|
||||||
|
|||||||
@@ -5,14 +5,23 @@
|
|||||||
|
|
||||||
<div class="container">
|
<div class="container">
|
||||||
|
|
||||||
<%= check_box_tag "vehicle_ids[]", vehicle.id, false, onchange: "updateLink()", data: { url: vehicle_path(vehicle).html_safe, text: vehicle.to_s }, class: "appointment checkbox" %>
|
<% if show_checkbox %>
|
||||||
|
<%= check_box_tag "vehicle_ids[]", vehicle.id, false, onchange: "updateLink()", data: { url: vehicle_path(vehicle).html_safe, text: vehicle.to_s }, class: "appointment checkbox" %>
|
||||||
|
<% else %>
|
||||||
|
<div class='checkbox'>
|
||||||
|
</div>
|
||||||
|
<% end %>
|
||||||
|
|
||||||
<div class='label-main'>
|
<div class='label-main'>
|
||||||
<%= link_to vehicle.to_s, vehicle_path(vehicle) %>
|
<%= link_to vehicle.to_s, vehicle_path(vehicle) %>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="label-sub">
|
<div class="label-sub">
|
||||||
<%= vehicle.vin.scan(/.{1,9}/)[0] if vehicle.vin %><b><%=vehicle.vin.scan(/.{1,9}/)[1] if vehicle.vin%></b>
|
<div onclick="handleCopy(event)"><%= vehicle.vin.scan(/.{1,9}/)[0] if vehicle.vin %><b><%=vehicle.vin.scan(/.{1,9}/)[1] if vehicle.vin%></b></div>
|
||||||
|
<% if show_customer %>
|
||||||
|
<br/>
|
||||||
|
<%= vehicle.customer %>
|
||||||
|
<% end %>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
<%= form_tag(vehicles_path, method: "get", id: "search-form") do %>
|
<%= form_tag(vehicles_path, method: "get", id: "search-form") do %>
|
||||||
<%= text_field_tag :search, params[:search], placeholder: t(:label_search_vin), autocomplete: "off" %>
|
<%= text_field_tag :search, params[:search], placeholder: t(:label_search), autocomplete: "off" %>
|
||||||
<%= submit_tag t(:label_search) %>
|
<%= submit_tag t(:label_search) %>
|
||||||
<% end %>
|
<% end %>
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
<h2><%=t(:label_customer_vehicles)%> <span style="float:right"> <%= render partial: 'vehicles/search' %> </span> </h2>
|
<h2><%=t(:label_customer_vehicles)%> <span style="float:right"> <%= render partial: 'vehicles/search' %> </span> </h2>
|
||||||
<br/>
|
<br/>
|
||||||
|
|
||||||
<%= render partial: 'vehicles/list', locals: {vehicles: @vehicles} %>
|
<%= render partial: 'vehicles/list', locals: {vehicles: @vehicles, show_customer: true, show_checkbox: false} %>
|
||||||
|
|||||||
@@ -1,22 +1,27 @@
|
|||||||
async function handleCopy(event) {
|
async function handleCopy(event) {
|
||||||
console.log("Copy link clicked");
|
console.log("Copy link clicked");
|
||||||
// 1. Prevent the link from actually navigating
|
|
||||||
event.preventDefault();
|
let text;
|
||||||
|
let link;
|
||||||
// 2. Grab the text from our span
|
// Grab the text from our clicked link
|
||||||
const text = document.getElementById('vin').innerText;
|
if(event.target.tagName.toLowerCase() === 'b'){
|
||||||
|
text = event.target.parentElement.innerText;
|
||||||
|
link = event.target.parentElement;
|
||||||
|
} else {
|
||||||
|
text = event.target.innerText;
|
||||||
|
link = event.target;
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// 3. Write to clipboard
|
// Write to clipboard
|
||||||
await navigator.clipboard.writeText(text);
|
await navigator.clipboard.writeText(text);
|
||||||
|
|
||||||
// 4. Update the UI to show it worked
|
// Update the UI to show it worked
|
||||||
const link = event.target;
|
|
||||||
const originalText = link.innerText;
|
const originalText = link.innerText;
|
||||||
link.innerHTML = "<b>Copied!</b>";
|
link.innerHTML = "<b>Copied!</b>";
|
||||||
link.style.color = "#4CAF50"; // Turn green
|
link.style.color = "#4CAF50"; // Turn green
|
||||||
|
|
||||||
// 5. Reset after 2 seconds
|
// Reset after 2 seconds
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
// Check if the text is long enough to prevent errors
|
// Check if the text is long enough to prevent errors
|
||||||
if (originalText.length >= 8) {
|
if (originalText.length >= 8) {
|
||||||
|
|||||||
@@ -28,7 +28,7 @@ en:
|
|||||||
label_model: "Model"
|
label_model: "Model"
|
||||||
label_new_vehicle: "New Customer Vehicle"
|
label_new_vehicle: "New Customer Vehicle"
|
||||||
label_no_vehicles: "There are no vehicles containing the term(s)"
|
label_no_vehicles: "There are no vehicles containing the term(s)"
|
||||||
label_search_vin: "Search Vehicles by VIN"
|
label_search: "Search Vehicles"
|
||||||
label_year: "Year"
|
label_year: "Year"
|
||||||
no_customer: "Customer no longer exists"
|
no_customer: "Customer no longer exists"
|
||||||
notice_vehicle_created: "Vehicle was successfully created."
|
notice_vehicle_created: "Vehicle was successfully created."
|
||||||
|
|||||||
2
init.rb
2
init.rb
@@ -14,7 +14,7 @@ Redmine::Plugin.register :redmine_qbo_vehicles do
|
|||||||
name 'Redmine QBO Vehicles plugin'
|
name 'Redmine QBO Vehicles plugin'
|
||||||
author 'Rick Barrette'
|
author 'Rick Barrette'
|
||||||
description 'This is a plugin for Redmine to intergrate with the redmine_qbo plugin to provide vehicle data tracking'
|
description 'This is a plugin for Redmine to intergrate with the redmine_qbo plugin to provide vehicle data tracking'
|
||||||
version '2026.2.3'
|
version '2026.2.5'
|
||||||
url 'https://github.com/rickbarrette/redmine_qbo_vehicles'
|
url 'https://github.com/rickbarrette/redmine_qbo_vehicles'
|
||||||
author_url 'https://barrettefabrication.com'
|
author_url 'https://barrettefabrication.com'
|
||||||
requires_redmine version_or_higher: '6.1.0'
|
requires_redmine version_or_higher: '6.1.0'
|
||||||
|
|||||||
Reference in New Issue
Block a user