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,232 @@
import conversationAPI from '../../inbox/conversation';
import ApiClient from '../../ApiClient';
describe('#ConversationAPI', () => {
it('creates correct instance', () => {
expect(conversationAPI).toBeInstanceOf(ApiClient);
expect(conversationAPI).toHaveProperty('get');
expect(conversationAPI).toHaveProperty('show');
expect(conversationAPI).toHaveProperty('create');
expect(conversationAPI).toHaveProperty('update');
expect(conversationAPI).toHaveProperty('delete');
expect(conversationAPI).toHaveProperty('toggleStatus');
expect(conversationAPI).toHaveProperty('assignAgent');
expect(conversationAPI).toHaveProperty('assignTeam');
expect(conversationAPI).toHaveProperty('markMessageRead');
expect(conversationAPI).toHaveProperty('toggleTyping');
expect(conversationAPI).toHaveProperty('mute');
expect(conversationAPI).toHaveProperty('unmute');
expect(conversationAPI).toHaveProperty('meta');
expect(conversationAPI).toHaveProperty('sendEmailTranscript');
expect(conversationAPI).toHaveProperty('filter');
});
describe('API calls', () => {
const originalAxios = window.axios;
const axiosMock = {
post: vi.fn(() => Promise.resolve()),
get: vi.fn(() => Promise.resolve()),
patch: vi.fn(() => Promise.resolve()),
delete: vi.fn(() => Promise.resolve()),
};
beforeEach(() => {
window.axios = axiosMock;
});
afterEach(() => {
window.axios = originalAxios;
});
it('#get conversations', () => {
conversationAPI.get({
inboxId: 1,
status: 'open',
assigneeType: 'me',
page: 1,
labels: [],
teamId: 1,
updatedWithin: 20,
});
expect(axiosMock.get).toHaveBeenCalledWith('/api/v1/conversations', {
params: {
inbox_id: 1,
team_id: 1,
status: 'open',
assignee_type: 'me',
page: 1,
labels: [],
updated_within: 20,
},
});
});
it('#search', () => {
conversationAPI.search({
q: 'leads',
page: 1,
});
expect(axiosMock.get).toHaveBeenCalledWith(
'/api/v1/conversations/search',
{
params: {
q: 'leads',
page: 1,
},
}
);
});
it('#toggleStatus', () => {
conversationAPI.toggleStatus({ conversationId: 12, status: 'online' });
expect(axiosMock.post).toHaveBeenCalledWith(
`/api/v1/conversations/12/toggle_status`,
{
status: 'online',
snoozed_until: null,
}
);
});
it('#assignAgent', () => {
conversationAPI.assignAgent({ conversationId: 12, agentId: 34 });
expect(axiosMock.post).toHaveBeenCalledWith(
`/api/v1/conversations/12/assignments`,
{
assignee_id: 34,
}
);
});
it('#assignTeam', () => {
conversationAPI.assignTeam({ conversationId: 12, teamId: 1 });
expect(axiosMock.post).toHaveBeenCalledWith(
`/api/v1/conversations/12/assignments`,
{
team_id: 1,
}
);
});
it('#markMessageRead', () => {
conversationAPI.markMessageRead({ id: 12 });
expect(axiosMock.post).toHaveBeenCalledWith(
`/api/v1/conversations/12/update_last_seen`
);
});
it('#toggleTyping', () => {
conversationAPI.toggleTyping({
conversationId: 12,
status: 'typing_on',
});
expect(axiosMock.post).toHaveBeenCalledWith(
`/api/v1/conversations/12/toggle_typing_status`,
{
typing_status: 'typing_on',
}
);
});
it('#mute', () => {
conversationAPI.mute(45);
expect(axiosMock.post).toHaveBeenCalledWith(
'/api/v1/conversations/45/mute'
);
});
it('#unmute', () => {
conversationAPI.unmute(45);
expect(axiosMock.post).toHaveBeenCalledWith(
'/api/v1/conversations/45/unmute'
);
});
it('#meta', () => {
conversationAPI.meta({
inboxId: 1,
status: 'open',
assigneeType: 'me',
labels: [],
teamId: 1,
});
expect(axiosMock.get).toHaveBeenCalledWith('/api/v1/conversations/meta', {
params: {
inbox_id: 1,
team_id: 1,
status: 'open',
assignee_type: 'me',
labels: [],
},
});
});
it('#sendEmailTranscript', () => {
conversationAPI.sendEmailTranscript({
conversationId: 45,
email: 'john@acme.inc',
});
expect(axiosMock.post).toHaveBeenCalledWith(
'/api/v1/conversations/45/transcript',
{
email: 'john@acme.inc',
}
);
});
it('#updateCustomAttributes', () => {
conversationAPI.updateCustomAttributes({
conversationId: 45,
customAttributes: { order_d: '1001' },
});
expect(axiosMock.post).toHaveBeenCalledWith(
'/api/v1/conversations/45/custom_attributes',
{
custom_attributes: { order_d: '1001' },
}
);
});
it('#filter', () => {
const payload = {
page: 1,
queryData: {
payload: [
{
attribute_key: 'status',
filter_operator: 'equal_to',
values: ['pending', 'resolved'],
query_operator: 'and',
},
{
attribute_key: 'assignee',
filter_operator: 'equal_to',
values: [3],
query_operator: 'and',
},
{
attribute_key: 'id',
filter_operator: 'equal_to',
values: ['This is a test'],
query_operator: null,
},
],
},
};
conversationAPI.filter(payload);
expect(axiosMock.post).toHaveBeenCalledWith(
'/api/v1/conversations/filter',
payload.queryData,
{ params: { page: payload.page } }
);
});
it('#getAllAttachments', () => {
conversationAPI.getAllAttachments(1);
expect(axiosMock.get).toHaveBeenCalledWith(
'/api/v1/conversations/1/attachments'
);
});
});
});

View File

@@ -0,0 +1,87 @@
import messageAPI, { buildCreatePayload } from '../../inbox/message';
import ApiClient from '../../ApiClient';
describe('#ConversationAPI', () => {
it('creates correct instance', () => {
expect(messageAPI).toBeInstanceOf(ApiClient);
expect(messageAPI).toHaveProperty('get');
expect(messageAPI).toHaveProperty('show');
expect(messageAPI).toHaveProperty('create');
expect(messageAPI).toHaveProperty('update');
expect(messageAPI).toHaveProperty('delete');
expect(messageAPI).toHaveProperty('getPreviousMessages');
});
describe('API calls', () => {
const originalAxios = window.axios;
const axiosMock = {
post: vi.fn(() => Promise.resolve()),
get: vi.fn(() => Promise.resolve()),
patch: vi.fn(() => Promise.resolve()),
delete: vi.fn(() => Promise.resolve()),
};
beforeEach(() => {
window.axios = axiosMock;
});
afterEach(() => {
window.axios = originalAxios;
});
it('#getPreviousMessages', () => {
messageAPI.getPreviousMessages({
conversationId: 12,
before: 4573,
});
expect(axiosMock.get).toHaveBeenCalledWith(
`/api/v1/conversations/12/messages`,
{
params: {
before: 4573,
},
}
);
});
});
describe('#buildCreatePayload', () => {
it('builds form payload if file is available', () => {
const formPayload = buildCreatePayload({
message: 'test content',
echoId: 12,
isPrivate: true,
contentAttributes: { in_reply_to: 12 },
files: [new Blob(['test-content'], { type: 'application/pdf' })],
});
expect(formPayload).toBeInstanceOf(FormData);
expect(formPayload.get('content')).toEqual('test content');
expect(formPayload.get('echo_id')).toEqual('12');
expect(formPayload.get('private')).toEqual('true');
expect(formPayload.get('cc_emails')).toEqual('');
expect(formPayload.get('bcc_emails')).toEqual('');
expect(formPayload.get('content_attributes')).toEqual(
'{"in_reply_to":12}'
);
});
it('builds object payload if file is not available', () => {
expect(
buildCreatePayload({
message: 'test content',
isPrivate: false,
echoId: 12,
contentAttributes: { in_reply_to: 12 },
})
).toEqual({
content: 'test content',
private: false,
echo_id: 12,
content_attributes: { in_reply_to: 12 },
cc_emails: '',
bcc_emails: '',
to_emails: '',
template_params: undefined,
});
});
});
});