Initial commit: Add logistics and order_detail message types
Some checks failed
Lock Threads / action (push) Has been cancelled
Mark stale issues and pull requests / stale (push) Has been cancelled
Publish Chatwoot EE docker images / build (linux/amd64, ubuntu-latest) (push) Has been cancelled
Publish Chatwoot EE docker images / build (linux/arm64, ubuntu-22.04-arm) (push) Has been cancelled
Publish Chatwoot EE docker images / merge (push) Has been cancelled
Publish Chatwoot CE docker images / build (linux/amd64, ubuntu-latest) (push) Has been cancelled
Publish Chatwoot CE docker images / build (linux/arm64, ubuntu-22.04-arm) (push) Has been cancelled
Publish Chatwoot CE docker images / merge (push) Has been cancelled
Run Chatwoot CE spec / lint-backend (push) Has been cancelled
Run Chatwoot CE spec / lint-frontend (push) Has been cancelled
Run Chatwoot CE spec / frontend-tests (push) Has been cancelled
Run Chatwoot CE spec / backend-tests (0, 16) (push) Has been cancelled
Run Chatwoot CE spec / backend-tests (1, 16) (push) Has been cancelled
Run Chatwoot CE spec / backend-tests (10, 16) (push) Has been cancelled
Run Chatwoot CE spec / backend-tests (11, 16) (push) Has been cancelled
Run Chatwoot CE spec / backend-tests (12, 16) (push) Has been cancelled
Run Chatwoot CE spec / backend-tests (13, 16) (push) Has been cancelled
Run Chatwoot CE spec / backend-tests (14, 16) (push) Has been cancelled
Run Chatwoot CE spec / backend-tests (15, 16) (push) Has been cancelled
Run Chatwoot CE spec / backend-tests (2, 16) (push) Has been cancelled
Run Chatwoot CE spec / backend-tests (3, 16) (push) Has been cancelled
Run Chatwoot CE spec / backend-tests (4, 16) (push) Has been cancelled
Run Chatwoot CE spec / backend-tests (5, 16) (push) Has been cancelled
Run Chatwoot CE spec / backend-tests (6, 16) (push) Has been cancelled
Run Chatwoot CE spec / backend-tests (7, 16) (push) Has been cancelled
Run Chatwoot CE spec / backend-tests (8, 16) (push) Has been cancelled
Run Chatwoot CE spec / backend-tests (9, 16) (push) Has been cancelled
Run Linux nightly installer / nightly (push) Has been cancelled

- Add Logistics component with progress tracking
- Add OrderDetail component for order information
- Support data-driven steps and actions
- Add blue color scale to widget SCSS
- Fix node overflow and progress bar rendering issues
- Add English translations for dashboard components

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
Liang XJ
2026-01-26 11:16:56 +08:00
commit 092fb2e083
7646 changed files with 975643 additions and 0 deletions

View File

@@ -0,0 +1,126 @@
require 'rails_helper'
RSpec.describe Integrations::App do
let(:apps) { described_class }
let(:app) { apps.find(id: app_name) }
let(:account) { create(:account) }
describe '#name' do
let(:app_name) { 'slack' }
it 'returns the name' do
expect(app.name).to eq('Slack')
end
end
describe '#logo' do
let(:app_name) { 'slack' }
it 'returns the logo' do
expect(app.logo).to eq('slack.png')
end
end
describe '#action' do
let(:app_name) { 'slack' }
before do
allow(Current).to receive(:account).and_return(account)
end
context 'when the app is slack' do
it 'returns the action URL with client_id and redirect_uri' do
with_modified_env SLACK_CLIENT_ID: 'dummy_client_id' do
expect(app.action).to include('client_id=dummy_client_id')
expect(app.action).to include(
"/app/accounts/#{account.id}/settings/integrations/slack"
)
end
end
end
end
describe '#active?' do
let(:app_name) { 'slack' }
context 'when the app is slack' do
it 'returns true if SLACK_CLIENT_SECRET is present' do
with_modified_env SLACK_CLIENT_SECRET: 'random_secret' do
expect(app.active?(account)).to be true
end
end
end
context 'when the app is shopify' do
let(:app_name) { 'shopify' }
it 'returns true if the shopify integration feature is enabled' do
account.enable_features('shopify_integration')
allow(GlobalConfigService).to receive(:load).with('SHOPIFY_CLIENT_ID', nil).and_return('client_id')
expect(app.active?(account)).to be true
end
it 'returns false if the shopify integration feature is disabled' do
allow(GlobalConfigService).to receive(:load).with('SHOPIFY_CLIENT_ID', nil).and_return('client_id')
expect(app.active?(account)).to be false
end
it 'returns false if SHOPIFY_CLIENT_ID is not present, even if feature is enabled' do
account.enable_features('shopify_integration')
allow(GlobalConfigService).to receive(:load).with('SHOPIFY_CLIENT_ID', nil).and_return(nil)
expect(app.active?(account)).to be false
end
end
context 'when the app is linear' do
let(:app_name) { 'linear' }
it 'returns false if the linear integration feature is disabled' do
expect(app.active?(account)).to be false
end
it 'returns true if the linear integration feature is enabled' do
account.enable_features('linear_integration')
account.save!
allow(GlobalConfigService).to receive(:load).with('LINEAR_CLIENT_ID', nil).and_return('client_id')
expect(app.active?(account)).to be true
end
end
context 'when other apps are queried' do
let(:app_name) { 'webhook' }
it 'returns true' do
expect(app.active?(account)).to be true
end
end
end
describe '#enabled?' do
context 'when the app is webhook' do
let(:app_name) { 'webhook' }
it 'returns false if the account does not have any webhooks' do
expect(app.enabled?(account)).to be false
end
it 'returns true if the account has webhooks' do
create(:webhook, account: account)
expect(app.enabled?(account)).to be true
end
end
context 'when the app is anything other than webhook' do
let(:app_name) { 'openai' }
it 'returns false if the account does not have any hooks for the app' do
expect(app.enabled?(account)).to be false
end
it 'returns true if the account has hooks for the app' do
create(:integrations_hook, :openai, account: account)
expect(app.enabled?(account)).to be true
end
end
end
end

View File

@@ -0,0 +1,135 @@
require 'rails_helper'
require Rails.root.join 'spec/models/concerns/reauthorizable_shared.rb'
RSpec.describe Integrations::Hook do
it_behaves_like 'reauthorizable'
context 'with validations' do
it { is_expected.to validate_presence_of(:app_id) }
it { is_expected.to validate_presence_of(:account_id) }
end
describe 'associations' do
it { is_expected.to belong_to(:account) }
end
describe 'when trying to create multiple hooks for an app' do
let(:account) { create(:account) }
context 'when app allows multiple hooks' do
it 'allows to create succesfully' do
create(:integrations_hook, account: account, app_id: 'webhook')
expect(build(:integrations_hook, account: account, app_id: 'webhook').valid?).to be true
end
end
context 'when app doesnot allow multiple hooks' do
it 'throws invalid error' do
create(:integrations_hook, account: account, app_id: 'slack')
expect(build(:integrations_hook, account: account, app_id: 'slack').valid?).to be false
end
end
end
describe 'process_event' do
let(:account) { create(:account) }
let(:params) { { event: 'rephrase', payload: { test: 'test' } } }
it 'returns no processor found for hooks with out processor defined' do
hook = create(:integrations_hook, account: account)
expect(hook.process_event(params)).to eq({ :error => 'No processor found' })
end
it 'returns results from procesor for openai hook' do
hook = create(:integrations_hook, :openai, account: account)
openai_double = double
allow(Integrations::Openai::ProcessorService).to receive(:new).and_return(openai_double)
allow(openai_double).to receive(:perform).and_return('test')
expect(hook.process_event(params)).to eq('test')
expect(Integrations::Openai::ProcessorService).to have_received(:new).with(event: params, hook: hook)
expect(openai_double).to have_received(:perform)
end
end
describe 'scopes' do
let(:account) { create(:account) }
let(:inbox) { create(:inbox, account: account) }
let!(:account_hook) { create(:integrations_hook, account: account, app_id: 'webhook') }
let!(:inbox_hook) do
create(:integrations_hook,
account: account,
app_id: 'dialogflow',
inbox: inbox,
settings: {
project_id: 'test-project',
credentials: { type: 'service_account' }
})
end
it 'returns account hooks' do
expect(described_class.account_hooks.pluck(:id)).to include(account_hook.id)
expect(described_class.account_hooks.pluck(:id)).not_to include(inbox_hook.id)
end
it 'returns inbox hooks' do
expect(described_class.inbox_hooks.pluck(:id)).to include(inbox_hook.id)
expect(described_class.inbox_hooks.pluck(:id)).not_to include(account_hook.id)
end
end
describe '#crm_integration?' do
let(:account) { create(:account) }
before do
account.enable_features('crm_integration')
end
it 'returns true for leadsquared integration' do
hook = create(:integrations_hook,
account: account,
app_id: 'leadsquared',
settings: {
access_key: 'test',
secret_key: 'test',
endpoint_url: 'https://api.leadsquared.com'
})
expect(hook.send(:crm_integration?)).to be true
end
it 'returns false for non-crm integrations' do
hook = create(:integrations_hook, account: account, app_id: 'slack')
expect(hook.send(:crm_integration?)).to be false
end
end
describe '#trigger_setup_if_crm' do
let(:account) { create(:account) }
before do
account.enable_features('crm_integration')
allow(Crm::SetupJob).to receive(:perform_later)
end
context 'when integration is a CRM' do
it 'enqueues setup job' do
create(:integrations_hook,
account: account,
app_id: 'leadsquared',
settings: {
access_key: 'test',
secret_key: 'test',
endpoint_url: 'https://api.leadsquared.com'
})
expect(Crm::SetupJob).to have_received(:perform_later)
end
end
context 'when integration is not a CRM' do
it 'does not enqueue setup job' do
create(:integrations_hook, account: account, app_id: 'slack')
expect(Crm::SetupJob).not_to have_received(:perform_later)
end
end
end
end