diff --git a/app/javascript/dashboard/components-next/icon/FileIcon.vue b/app/javascript/dashboard/components-next/icon/FileIcon.vue
index 8dd9e7ce1..66a971bc6 100644
--- a/app/javascript/dashboard/components-next/icon/FileIcon.vue
+++ b/app/javascript/dashboard/components-next/icon/FileIcon.vue
@@ -18,6 +18,7 @@ const fileTypeIcon = computed(() => {
json: 'i-woot-file-txt',
odt: 'i-woot-file-doc',
pdf: 'i-woot-file-pdf',
+ pfx: 'i-woot-file-pfx',
ppt: 'i-woot-file-ppt',
pptx: 'i-woot-file-ppt',
rar: 'i-woot-file-zip',
@@ -26,6 +27,7 @@ const fileTypeIcon = computed(() => {
txt: 'i-woot-file-txt',
xls: 'i-woot-file-xls',
xlsx: 'i-woot-file-xls',
+ xml: 'i-woot-file-txt',
zip: 'i-woot-file-zip',
};
diff --git a/app/javascript/dashboard/components/widgets/WootWriter/ReplyBottomPanel.vue b/app/javascript/dashboard/components/widgets/WootWriter/ReplyBottomPanel.vue
index ff569d763..2e5a9aab2 100644
--- a/app/javascript/dashboard/components/widgets/WootWriter/ReplyBottomPanel.vue
+++ b/app/javascript/dashboard/components/widgets/WootWriter/ReplyBottomPanel.vue
@@ -7,7 +7,6 @@ import * as ActiveStorage from 'activestorage';
import inboxMixin from 'shared/mixins/inboxMixin';
import { FEATURE_FLAGS } from 'dashboard/featureFlags';
import { getAllowedFileTypesByChannel } from '@chatwoot/utils';
-import { ALLOWED_FILE_TYPES } from 'shared/constants/messages';
import VideoCallButton from '../VideoCallButton.vue';
import { INBOX_TYPES } from 'dashboard/helper/inbox';
import { mapGetters } from 'vuex';
@@ -166,11 +165,6 @@ export default {
uploadRef,
};
},
- data() {
- return {
- ALLOWED_FILE_TYPES,
- };
- },
computed: {
...mapGetters({
accountId: 'getCurrentAccountId',
@@ -212,13 +206,11 @@ export default {
return this.conversationType === 'instagram_direct_message';
},
allowedFileTypes() {
- // Use default file types for private notes
if (this.isOnPrivateNote) {
- return this.ALLOWED_FILE_TYPES;
+ return getAllowedFileTypesByChannel();
}
let channelType = this.channelType || this.inbox?.channel_type;
-
if (this.isAnInstagramChannel || this.isInstagramDM) {
channelType = INBOX_TYPES.INSTAGRAM;
}
diff --git a/app/javascript/shared/constants/messages.js b/app/javascript/shared/constants/messages.js
index 989aa12ca..18bc380ec 100644
--- a/app/javascript/shared/constants/messages.js
+++ b/app/javascript/shared/constants/messages.js
@@ -39,12 +39,14 @@ export const ALLOWED_FILE_TYPES =
'audio/*,' +
'video/*,' +
'.3gpp,' +
+ '.xls, .xlsx, .xml, .pfx,' +
'text/csv, text/plain, application/json, application/pdf, text/rtf,' +
'application/xml, text/xml,' +
'application/zip, application/x-7z-compressed application/vnd.rar application/x-tar,' +
'application/msword, application/vnd.ms-excel, application/vnd.ms-powerpoint, application/vnd.oasis.opendocument.text,' +
'application/vnd.openxmlformats-officedocument.presentationml.presentation, application/vnd.openxmlformats-officedocument.spreadsheetml.sheet,' +
- 'application/vnd.openxmlformats-officedocument.wordprocessingml.document,';
+ 'application/vnd.openxmlformats-officedocument.wordprocessingml.document,' +
+ 'application/x-pkcs12, application/pkcs12,';
export const CSAT_RATINGS = [
{
diff --git a/app/javascript/shared/helpers/FileHelper.js b/app/javascript/shared/helpers/FileHelper.js
index 2616c868a..93c8a7156 100644
--- a/app/javascript/shared/helpers/FileHelper.js
+++ b/app/javascript/shared/helpers/FileHelper.js
@@ -1,6 +1,5 @@
import { getAllowedFileTypesByChannel } from '@chatwoot/utils';
import { INBOX_TYPES } from 'dashboard/helper/inbox';
-import { ALLOWED_FILE_TYPES } from 'shared/constants/messages';
export const DEFAULT_MAXIMUM_FILE_UPLOAD_SIZE = 40;
@@ -58,9 +57,8 @@ export const isFileTypeAllowedForChannel = (file, options = {}) => {
isOnPrivateNote,
} = options;
- // Use broader file types for private notes (matches file picker behavior)
const allowedFileTypes = isOnPrivateNote
- ? ALLOWED_FILE_TYPES
+ ? getAllowedFileTypesByChannel()
: getAllowedFileTypesByChannel({
channelType:
isInstagramChannel || conversationType === 'instagram_direct_message'
diff --git a/app/models/attachment.rb b/app/models/attachment.rb
index 2d46f3b7e..79a8021b3 100644
--- a/app/models/attachment.rb
+++ b/app/models/attachment.rb
@@ -25,15 +25,19 @@ class Attachment < ApplicationRecord
include Rails.application.routes.url_helpers
ACCEPTABLE_FILE_TYPES = %w[
- text/csv text/plain text/rtf
+ text/csv text/plain text/rtf text/xml
application/json application/pdf
+ application/xml
application/zip application/x-7z-compressed application/vnd.rar application/x-tar
application/msword application/vnd.ms-excel application/vnd.ms-powerpoint application/rtf
application/vnd.oasis.opendocument.text
application/vnd.openxmlformats-officedocument.presentationml.presentation
application/vnd.openxmlformats-officedocument.spreadsheetml.sheet
application/vnd.openxmlformats-officedocument.wordprocessingml.document
+ application/x-pkcs12 application/pkcs12
].freeze
+ ACCEPTABLE_FILE_EXTENSIONS = %w[pfx xml].freeze
+ GENERIC_FILE_CONTENT_TYPES = %w[application/octet-stream].freeze
belongs_to :account
belongs_to :message
has_one_attached :file
@@ -195,7 +199,10 @@ class Attachment < ApplicationRecord
end
def validate_file_content_type(file_content_type)
- errors.add(:file, 'type not supported') unless media_file?(file_content_type) || ACCEPTABLE_FILE_TYPES.include?(file_content_type)
+ return if media_file?(file_content_type) || ACCEPTABLE_FILE_TYPES.include?(file_content_type)
+ return if generic_file_content_type?(file_content_type) && ACCEPTABLE_FILE_EXTENSIONS.include?(file_extension)
+
+ errors.add(:file, 'type not supported')
end
def validate_file_size(byte_size)
@@ -206,7 +213,15 @@ class Attachment < ApplicationRecord
end
def media_file?(file_content_type)
- file_content_type.start_with?('image/', 'video/', 'audio/')
+ file_content_type.to_s.start_with?('image/', 'video/', 'audio/')
+ end
+
+ def generic_file_content_type?(file_content_type)
+ file_content_type.blank? || GENERIC_FILE_CONTENT_TYPES.include?(file_content_type)
+ end
+
+ def file_extension
+ File.extname(file.filename.to_s).delete_prefix('.').downcase
end
end
diff --git a/package.json b/package.json
index ed8bbf00f..1e506d6c5 100644
--- a/package.json
+++ b/package.json
@@ -35,7 +35,7 @@
"@breezystack/lamejs": "^1.2.7",
"@chatwoot/ninja-keys": "1.2.3",
"@chatwoot/prosemirror-schema": "1.3.13",
- "@chatwoot/utils": "^0.0.52",
+ "@chatwoot/utils": "^0.0.55",
"@formkit/core": "^1.7.2",
"@formkit/vue": "^1.7.2",
"@hcaptcha/vue3-hcaptcha": "^1.3.0",
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index 3f1e9e2cf..3a9efa7eb 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -29,8 +29,8 @@ importers:
specifier: 1.3.13
version: 1.3.13
'@chatwoot/utils':
- specifier: ^0.0.52
- version: 0.0.52
+ specifier: ^0.0.55
+ version: 0.0.55
'@formkit/core':
specifier: ^1.7.2
version: 1.7.2
@@ -462,8 +462,8 @@ packages:
'@chatwoot/prosemirror-schema@1.3.13':
resolution: {integrity: sha512-T6FBUinMJbwDCD7975g8M/Tsn2+G3O2pTGIXdcLkMRpbAAC6mVdl4ZcZektlt5y/PVmPVqNHPsfee1XB/C3vAw==}
- '@chatwoot/utils@0.0.52':
- resolution: {integrity: sha512-e57uVqyVW4tj1gql4YJPNMykqMJPkETn5Y9AmHdhc6Y7oxDXfRXBq27fZrrDadLkZdn5RYVCZjfIhXOumyYv2Q==}
+ '@chatwoot/utils@0.0.55':
+ resolution: {integrity: sha512-8G6HYQe1ZEYfJEsSYfDVvE+uhf98JDRjtGlpB+bzMko+yltbrk4yACSo/ImC3jSaJ6K8yPTSjJToSRmsQbL2iQ==}
engines: {node: '>=10'}
'@codemirror/commands@6.7.0':
@@ -5011,7 +5011,7 @@ snapshots:
prosemirror-utils: 1.2.2(prosemirror-model@1.22.3)(prosemirror-state@1.4.3)
prosemirror-view: 1.34.1
- '@chatwoot/utils@0.0.52':
+ '@chatwoot/utils@0.0.55':
dependencies:
date-fns: 2.30.0
diff --git a/swagger/definitions/request/agent/create_payload.yml b/swagger/definitions/request/agent/create_payload.yml
index 1daeae83a..77180d282 100644
--- a/swagger/definitions/request/agent/create_payload.yml
+++ b/swagger/definitions/request/agent/create_payload.yml
@@ -17,12 +17,12 @@ properties:
enum: ['agent', 'administrator']
description: Whether its administrator or agent
example: 'agent'
- availability_status:
+ availability:
type: string
- enum: ['available', 'busy', 'offline']
- description: The availability setting of the agent.
- example: 'available'
+ enum: ['online', 'busy', 'offline']
+ description: The configured availability of the agent.
+ example: 'online'
auto_offline:
type: boolean
- description: Whether the availability status of agent is configured to go offline automatically when away.
+ description: Whether the agent is automatically marked offline when they are away.
example: true
diff --git a/swagger/definitions/request/agent/update_payload.yml b/swagger/definitions/request/agent/update_payload.yml
index fc8d1457d..168d46f49 100644
--- a/swagger/definitions/request/agent/update_payload.yml
+++ b/swagger/definitions/request/agent/update_payload.yml
@@ -7,12 +7,12 @@ properties:
enum: ['agent', 'administrator']
description: Whether its administrator or agent
example: 'agent'
- availability_status:
+ availability:
type: string
- enum: ['available', 'busy', 'offline']
- description: The availability status of the agent.
- example: 'available'
+ enum: ['online', 'busy', 'offline']
+ description: The configured availability of the agent.
+ example: 'online'
auto_offline:
type: boolean
- description: Whether the availability status of agent is configured to go offline automatically when away.
+ description: Whether the agent is automatically marked offline when they are away.
example: true
diff --git a/swagger/definitions/resource/agent.yml b/swagger/definitions/resource/agent.yml
index 1d7b2b4c3..cabd1ee27 100644
--- a/swagger/definitions/resource/agent.yml
+++ b/swagger/definitions/resource/agent.yml
@@ -6,11 +6,15 @@ properties:
type: integer
availability_status:
type: string
- enum: ['available', 'busy', 'offline']
- description: The availability status of the agent computed by Chatwoot.
+ enum: ['online', 'busy', 'offline']
+ readOnly: true
+ description: >-
+ The effective availability status of the agent, derived from the configured availability,
+ auto-offline setting, and current presence. To update an agent's configured availability,
+ use the availability field in create or update requests.
auto_offline:
type: boolean
- description: Whether the availability status of agent is configured to go offline automatically when away.
+ description: Whether the agent is automatically marked offline when they are away.
confirmed:
type: boolean
description: Whether the agent has confirmed their email address.
diff --git a/swagger/swagger.json b/swagger/swagger.json
index 94d1f04d3..b8b64b009 100644
--- a/swagger/swagger.json
+++ b/swagger/swagger.json
@@ -9892,15 +9892,16 @@
"availability_status": {
"type": "string",
"enum": [
- "available",
+ "online",
"busy",
"offline"
],
- "description": "The availability status of the agent computed by Chatwoot."
+ "readOnly": true,
+ "description": "The effective availability status of the agent, derived from the configured availability, auto-offline setting, and current presence. To update an agent's configured availability, use the availability field in create or update requests."
},
"auto_offline": {
"type": "boolean",
- "description": "Whether the availability status of agent is configured to go offline automatically when away."
+ "description": "Whether the agent is automatically marked offline when they are away."
},
"confirmed": {
"type": "boolean",
@@ -11595,19 +11596,19 @@
"description": "Whether its administrator or agent",
"example": "agent"
},
- "availability_status": {
+ "availability": {
"type": "string",
"enum": [
- "available",
+ "online",
"busy",
"offline"
],
- "description": "The availability setting of the agent.",
- "example": "available"
+ "description": "The configured availability of the agent.",
+ "example": "online"
},
"auto_offline": {
"type": "boolean",
- "description": "Whether the availability status of agent is configured to go offline automatically when away.",
+ "description": "Whether the agent is automatically marked offline when they are away.",
"example": true
}
}
@@ -11627,19 +11628,19 @@
"description": "Whether its administrator or agent",
"example": "agent"
},
- "availability_status": {
+ "availability": {
"type": "string",
"enum": [
- "available",
+ "online",
"busy",
"offline"
],
- "description": "The availability status of the agent.",
- "example": "available"
+ "description": "The configured availability of the agent.",
+ "example": "online"
},
"auto_offline": {
"type": "boolean",
- "description": "Whether the availability status of agent is configured to go offline automatically when away.",
+ "description": "Whether the agent is automatically marked offline when they are away.",
"example": true
}
}
diff --git a/swagger/tag_groups/application_swagger.json b/swagger/tag_groups/application_swagger.json
index a013b3694..17e015139 100644
--- a/swagger/tag_groups/application_swagger.json
+++ b/swagger/tag_groups/application_swagger.json
@@ -8399,15 +8399,16 @@
"availability_status": {
"type": "string",
"enum": [
- "available",
+ "online",
"busy",
"offline"
],
- "description": "The availability status of the agent computed by Chatwoot."
+ "readOnly": true,
+ "description": "The effective availability status of the agent, derived from the configured availability, auto-offline setting, and current presence. To update an agent's configured availability, use the availability field in create or update requests."
},
"auto_offline": {
"type": "boolean",
- "description": "Whether the availability status of agent is configured to go offline automatically when away."
+ "description": "Whether the agent is automatically marked offline when they are away."
},
"confirmed": {
"type": "boolean",
@@ -10102,19 +10103,19 @@
"description": "Whether its administrator or agent",
"example": "agent"
},
- "availability_status": {
+ "availability": {
"type": "string",
"enum": [
- "available",
+ "online",
"busy",
"offline"
],
- "description": "The availability setting of the agent.",
- "example": "available"
+ "description": "The configured availability of the agent.",
+ "example": "online"
},
"auto_offline": {
"type": "boolean",
- "description": "Whether the availability status of agent is configured to go offline automatically when away.",
+ "description": "Whether the agent is automatically marked offline when they are away.",
"example": true
}
}
@@ -10134,19 +10135,19 @@
"description": "Whether its administrator or agent",
"example": "agent"
},
- "availability_status": {
+ "availability": {
"type": "string",
"enum": [
- "available",
+ "online",
"busy",
"offline"
],
- "description": "The availability status of the agent.",
- "example": "available"
+ "description": "The configured availability of the agent.",
+ "example": "online"
},
"auto_offline": {
"type": "boolean",
- "description": "Whether the availability status of agent is configured to go offline automatically when away.",
+ "description": "Whether the agent is automatically marked offline when they are away.",
"example": true
}
}
diff --git a/swagger/tag_groups/client_swagger.json b/swagger/tag_groups/client_swagger.json
index 763e090b1..7bc7227fb 100644
--- a/swagger/tag_groups/client_swagger.json
+++ b/swagger/tag_groups/client_swagger.json
@@ -1664,15 +1664,16 @@
"availability_status": {
"type": "string",
"enum": [
- "available",
+ "online",
"busy",
"offline"
],
- "description": "The availability status of the agent computed by Chatwoot."
+ "readOnly": true,
+ "description": "The effective availability status of the agent, derived from the configured availability, auto-offline setting, and current presence. To update an agent's configured availability, use the availability field in create or update requests."
},
"auto_offline": {
"type": "boolean",
- "description": "Whether the availability status of agent is configured to go offline automatically when away."
+ "description": "Whether the agent is automatically marked offline when they are away."
},
"confirmed": {
"type": "boolean",
@@ -3367,19 +3368,19 @@
"description": "Whether its administrator or agent",
"example": "agent"
},
- "availability_status": {
+ "availability": {
"type": "string",
"enum": [
- "available",
+ "online",
"busy",
"offline"
],
- "description": "The availability setting of the agent.",
- "example": "available"
+ "description": "The configured availability of the agent.",
+ "example": "online"
},
"auto_offline": {
"type": "boolean",
- "description": "Whether the availability status of agent is configured to go offline automatically when away.",
+ "description": "Whether the agent is automatically marked offline when they are away.",
"example": true
}
}
@@ -3399,19 +3400,19 @@
"description": "Whether its administrator or agent",
"example": "agent"
},
- "availability_status": {
+ "availability": {
"type": "string",
"enum": [
- "available",
+ "online",
"busy",
"offline"
],
- "description": "The availability status of the agent.",
- "example": "available"
+ "description": "The configured availability of the agent.",
+ "example": "online"
},
"auto_offline": {
"type": "boolean",
- "description": "Whether the availability status of agent is configured to go offline automatically when away.",
+ "description": "Whether the agent is automatically marked offline when they are away.",
"example": true
}
}
diff --git a/swagger/tag_groups/other_swagger.json b/swagger/tag_groups/other_swagger.json
index 50bf2212b..6dbfbdd8e 100644
--- a/swagger/tag_groups/other_swagger.json
+++ b/swagger/tag_groups/other_swagger.json
@@ -1079,15 +1079,16 @@
"availability_status": {
"type": "string",
"enum": [
- "available",
+ "online",
"busy",
"offline"
],
- "description": "The availability status of the agent computed by Chatwoot."
+ "readOnly": true,
+ "description": "The effective availability status of the agent, derived from the configured availability, auto-offline setting, and current presence. To update an agent's configured availability, use the availability field in create or update requests."
},
"auto_offline": {
"type": "boolean",
- "description": "Whether the availability status of agent is configured to go offline automatically when away."
+ "description": "Whether the agent is automatically marked offline when they are away."
},
"confirmed": {
"type": "boolean",
@@ -2782,19 +2783,19 @@
"description": "Whether its administrator or agent",
"example": "agent"
},
- "availability_status": {
+ "availability": {
"type": "string",
"enum": [
- "available",
+ "online",
"busy",
"offline"
],
- "description": "The availability setting of the agent.",
- "example": "available"
+ "description": "The configured availability of the agent.",
+ "example": "online"
},
"auto_offline": {
"type": "boolean",
- "description": "Whether the availability status of agent is configured to go offline automatically when away.",
+ "description": "Whether the agent is automatically marked offline when they are away.",
"example": true
}
}
@@ -2814,19 +2815,19 @@
"description": "Whether its administrator or agent",
"example": "agent"
},
- "availability_status": {
+ "availability": {
"type": "string",
"enum": [
- "available",
+ "online",
"busy",
"offline"
],
- "description": "The availability status of the agent.",
- "example": "available"
+ "description": "The configured availability of the agent.",
+ "example": "online"
},
"auto_offline": {
"type": "boolean",
- "description": "Whether the availability status of agent is configured to go offline automatically when away.",
+ "description": "Whether the agent is automatically marked offline when they are away.",
"example": true
}
}
diff --git a/swagger/tag_groups/platform_swagger.json b/swagger/tag_groups/platform_swagger.json
index f1e471e79..952813f62 100644
--- a/swagger/tag_groups/platform_swagger.json
+++ b/swagger/tag_groups/platform_swagger.json
@@ -1840,15 +1840,16 @@
"availability_status": {
"type": "string",
"enum": [
- "available",
+ "online",
"busy",
"offline"
],
- "description": "The availability status of the agent computed by Chatwoot."
+ "readOnly": true,
+ "description": "The effective availability status of the agent, derived from the configured availability, auto-offline setting, and current presence. To update an agent's configured availability, use the availability field in create or update requests."
},
"auto_offline": {
"type": "boolean",
- "description": "Whether the availability status of agent is configured to go offline automatically when away."
+ "description": "Whether the agent is automatically marked offline when they are away."
},
"confirmed": {
"type": "boolean",
@@ -3543,19 +3544,19 @@
"description": "Whether its administrator or agent",
"example": "agent"
},
- "availability_status": {
+ "availability": {
"type": "string",
"enum": [
- "available",
+ "online",
"busy",
"offline"
],
- "description": "The availability setting of the agent.",
- "example": "available"
+ "description": "The configured availability of the agent.",
+ "example": "online"
},
"auto_offline": {
"type": "boolean",
- "description": "Whether the availability status of agent is configured to go offline automatically when away.",
+ "description": "Whether the agent is automatically marked offline when they are away.",
"example": true
}
}
@@ -3575,19 +3576,19 @@
"description": "Whether its administrator or agent",
"example": "agent"
},
- "availability_status": {
+ "availability": {
"type": "string",
"enum": [
- "available",
+ "online",
"busy",
"offline"
],
- "description": "The availability status of the agent.",
- "example": "available"
+ "description": "The configured availability of the agent.",
+ "example": "online"
},
"auto_offline": {
"type": "boolean",
- "description": "Whether the availability status of agent is configured to go offline automatically when away.",
+ "description": "Whether the agent is automatically marked offline when they are away.",
"example": true
}
}
diff --git a/theme/icons.js b/theme/icons.js
index 266c7ddfa..281e21c23 100644
--- a/theme/icons.js
+++ b/theme/icons.js
@@ -113,6 +113,23 @@ export const icons = {
width: 16,
height: 20,
},
+ 'file-pfx': {
+ body: `
+
+
+
+
+
+
+
+
+
+
+
+ `,
+ width: 16,
+ height: 20,
+ },
bin: {
body: ``,
width: 16,