Merge branch 'release/3.1.1'

This commit is contained in:
Sojan 2023-09-22 19:54:43 -07:00
commit 3eefa4daee
313 changed files with 2395 additions and 949 deletions

View File

@ -76,6 +76,7 @@ gem 'pundit'
# super admin # super admin
gem 'administrate', '>= 0.19.0' gem 'administrate', '>= 0.19.0'
gem 'administrate-field-active_storage' gem 'administrate-field-active_storage'
gem 'administrate-field-belongs_to_search'
##--- gems for pubsub service ---## ##--- gems for pubsub service ---##
# https://karolgalanciak.com/blog/2019/11/30/from-activerecord-callbacks-to-publish-slash-subscribe-pattern-and-event-driven-design/ # https://karolgalanciak.com/blog/2019/11/30/from-activerecord-callbacks-to-publish-slash-subscribe-pattern-and-event-driven-design/

View File

@ -116,6 +116,11 @@ GEM
administrate-field-active_storage (0.4.2) administrate-field-active_storage (0.4.2)
administrate (>= 0.2.2) administrate (>= 0.2.2)
rails (>= 7.0) rails (>= 7.0)
administrate-field-belongs_to_search (0.8.0)
administrate (>= 0.3, < 1.0)
jbuilder (~> 2)
rails (>= 4.2, < 7.1)
selectize-rails (~> 0.6)
annotate (3.2.0) annotate (3.2.0)
activerecord (>= 3.2, < 8.0) activerecord (>= 3.2, < 8.0)
rake (>= 10.4, < 14.0) rake (>= 10.4, < 14.0)
@ -831,6 +836,7 @@ DEPENDENCIES
acts-as-taggable-on acts-as-taggable-on
administrate (>= 0.19.0) administrate (>= 0.19.0)
administrate-field-active_storage administrate-field-active_storage
administrate-field-belongs_to_search
annotate annotate
attr_extras attr_extras
audited (~> 5.3) audited (~> 5.3)

View File

@ -1 +1 @@
2.17.0 3.1.0

View File

@ -1 +1 @@
2.3.0 2.4.0

View File

@ -78,11 +78,6 @@ $conv-header-height: 4rem;
$inbox-thumb-size: 4.8rem; $inbox-thumb-size: 4.8rem;
// Spinner
$spinkit-spinner-color: $color-white !default;
$spinkit-spinner-margin: 0 0 0 1.6rem !default;
$spinkit-size: 1.6rem !default;
// Snackbar default // Snackbar default
$woot-snackbar-bg: #323232; $woot-snackbar-bg: #323232;
$woot-snackbar-button: #ffeb3b; $woot-snackbar-button: #ffeb3b;

View File

@ -25,7 +25,8 @@ class Api::V1::Accounts::ContactsController < Api::V1::Accounts::BaseController
render json: { error: 'Specify search string with parameter q' }, status: :unprocessable_entity if params[:q].blank? && return render json: { error: 'Specify search string with parameter q' }, status: :unprocessable_entity if params[:q].blank? && return
contacts = resolved_contacts.where( contacts = resolved_contacts.where(
'name ILIKE :search OR email ILIKE :search OR phone_number ILIKE :search OR contacts.identifier LIKE :search', 'name ILIKE :search OR email ILIKE :search OR phone_number ILIKE :search OR contacts.identifier LIKE :search
OR contacts.additional_attributes->>\'company_name\' ILIKE :search',
search: "%#{params[:q].strip}%" search: "%#{params[:q].strip}%"
) )
@contacts_count = contacts.count @contacts_count = contacts.count

View File

@ -1,4 +1,4 @@
class Api::V1::UploadController < Api::BaseController class Api::V1::Accounts::UploadController < Api::V1::Accounts::BaseController
def create def create
file_blob = ActiveStorage::Blob.create_and_upload!( file_blob = ActiveStorage::Blob.create_and_upload!(
key: nil, key: nil,

View File

@ -44,7 +44,7 @@ class Public::Api::V1::Portals::ArticlesController < Public::Api::V1::Portals::B
end end
def list_params def list_params
params.permit(:query, :locale, :sort) params.permit(:query, :locale, :sort, :status)
end end
def permitted_params def permitted_params

View File

@ -6,6 +6,7 @@ class SuperAdmin::InstanceStatusesController < SuperAdmin::ApplicationController
postgres_status postgres_status
redis_metrics redis_metrics
chatwoot_edition chatwoot_edition
instance_meta
end end
def chatwoot_edition def chatwoot_edition
@ -18,6 +19,10 @@ class SuperAdmin::InstanceStatusesController < SuperAdmin::ApplicationController
end end
end end
def instance_meta
@metrics['Database Migrations'] = ActiveRecord::Base.connection.migration_context.needs_migration? ? 'pending' : 'completed'
end
def chatwoot_version def chatwoot_version
@metrics['Chatwoot version'] = Chatwoot.config[:version] @metrics['Chatwoot version'] = Chatwoot.config[:version]
end end

View File

@ -18,8 +18,8 @@ class AccountDashboard < Administrate::BaseDashboard
end end
ATTRIBUTE_TYPES = { ATTRIBUTE_TYPES = {
id: Field::Number, id: Field::Number.with_options(searchable: true),
name: Field::String, name: Field::String.with_options(searchable: true),
created_at: Field::DateTime, created_at: Field::DateTime,
updated_at: Field::DateTime, updated_at: Field::DateTime,
users: CountField, users: CountField,

View File

@ -8,9 +8,9 @@ class AccountUserDashboard < Administrate::BaseDashboard
# which determines how the attribute is displayed # which determines how the attribute is displayed
# on pages throughout the dashboard. # on pages throughout the dashboard.
ATTRIBUTE_TYPES = { ATTRIBUTE_TYPES = {
account: Field::BelongsTo.with_options(searchable: true, searchable_field: 'name', order: 'id DESC'), account: Field::BelongsToSearch.with_options(class_name: 'Account', searchable: true, searchable_field: [:name, :id], order: 'id DESC'),
user: Field::BelongsTo.with_options(searchable: true, searchable_field: 'name', order: 'id DESC'), user: Field::BelongsToSearch.with_options(class_name: 'User', searchable: true, searchable_field: [:name, :email, :id], order: 'id DESC'),
inviter: Field::BelongsTo.with_options(class_name: 'User', searchable: true, searchable_field: 'name'), inviter: Field::BelongsToSearch.with_options(class_name: 'User', searchable: true, searchable_field: [:name, :email, :id], order: 'id DESC'),
id: Field::Number, id: Field::Number,
role: Field::Select.with_options(collection: AccountUser.roles.keys), role: Field::Select.with_options(collection: AccountUser.roles.keys),
created_at: Field::DateTime, created_at: Field::DateTime,

View File

@ -9,7 +9,7 @@ class UserDashboard < Administrate::BaseDashboard
# on pages throughout the dashboard. # on pages throughout the dashboard.
ATTRIBUTE_TYPES = { ATTRIBUTE_TYPES = {
account_users: Field::HasMany, account_users: Field::HasMany,
id: Field::Number, id: Field::Number.with_options(searchable: true),
avatar_url: AvatarField, avatar_url: AvatarField,
avatar: Field::ActiveStorage.with_options( avatar: Field::ActiveStorage.with_options(
destroy_url: proc do |_namespace, _resource, attachment| destroy_url: proc do |_namespace, _resource, attachment|
@ -28,9 +28,9 @@ class UserDashboard < Administrate::BaseDashboard
confirmed_at: Field::DateTime, confirmed_at: Field::DateTime,
confirmation_sent_at: Field::DateTime, confirmation_sent_at: Field::DateTime,
unconfirmed_email: Field::String, unconfirmed_email: Field::String,
name: Field::String, name: Field::String.with_options(searchable: true),
display_name: Field::String, display_name: Field::String,
email: Field::String, email: Field::String.with_options(searchable: true),
tokens: Field::String.with_options(searchable: false), tokens: Field::String.with_options(searchable: false),
created_at: Field::DateTime, created_at: Field::DateTime,
updated_at: Field::DateTime, updated_at: Field::DateTime,

View File

@ -26,14 +26,14 @@
<script> <script>
import { mapGetters } from 'vuex'; import { mapGetters } from 'vuex';
import AddAccountModal from '../dashboard/components/layout/sidebarComponents/AddAccountModal'; import AddAccountModal from '../dashboard/components/layout/sidebarComponents/AddAccountModal.vue';
import LoadingState from './components/widgets/LoadingState.vue'; import LoadingState from './components/widgets/LoadingState.vue';
import NetworkNotification from './components/NetworkNotification'; import NetworkNotification from './components/NetworkNotification.vue';
import UpdateBanner from './components/app/UpdateBanner.vue'; import UpdateBanner from './components/app/UpdateBanner.vue';
import UpgradeBanner from './components/app/UpgradeBanner.vue'; import UpgradeBanner from './components/app/UpgradeBanner.vue';
import PaymentPendingBanner from './components/app/PaymentPendingBanner.vue'; import PaymentPendingBanner from './components/app/PaymentPendingBanner.vue';
import vueActionCable from './helper/actionCable'; import vueActionCable from './helper/actionCable';
import WootSnackbarBox from './components/SnackbarContainer'; import WootSnackbarBox from './components/SnackbarContainer.vue';
import rtlMixin from 'shared/mixins/rtlMixin'; import rtlMixin from 'shared/mixins/rtlMixin';
import { setColorTheme } from './helper/themeHelper'; import { setColorTheme } from './helper/themeHelper';
import { import {

View File

@ -81,11 +81,6 @@ $conv-header-height: 2.5rem;
$inbox-thumb-size: 3rem; $inbox-thumb-size: 3rem;
// Spinner
$spinkit-spinner-color: $color-white !default;
$spinkit-spinner-margin: 0 0 0 1rem !default;
$spinkit-size: 1rem !default;
// Snackbar default // Snackbar default
$woot-snackbar-bg: #323232; $woot-snackbar-bg: #323232;
$woot-snackbar-button: #ffeb3b; $woot-snackbar-button: #ffeb3b;

View File

@ -9,7 +9,6 @@
@import 'shared/assets/stylesheets/border-radius'; @import 'shared/assets/stylesheets/border-radius';
@import 'variables'; @import 'variables';
@import '~spinkit/scss/spinners/7-three-bounce';
@import 'vue-multiselect/dist/vue-multiselect.min.css'; @import 'vue-multiselect/dist/vue-multiselect.min.css';
@import '~shared/assets/stylesheets/ionicons'; @import '~shared/assets/stylesheets/ionicons';

View File

@ -31,7 +31,7 @@
</template> </template>
<script> <script>
import EmojiOrIcon from 'shared/components/EmojiOrIcon'; import EmojiOrIcon from 'shared/components/EmojiOrIcon.vue';
export default { export default {
components: { components: {

View File

@ -193,17 +193,17 @@
<script> <script>
import { mapGetters } from 'vuex'; import { mapGetters } from 'vuex';
import ConversationAdvancedFilter from './widgets/conversation/ConversationAdvancedFilter'; import ConversationAdvancedFilter from './widgets/conversation/ConversationAdvancedFilter.vue';
import ConversationBasicFilter from './widgets/conversation/ConversationBasicFilter'; import ConversationBasicFilter from './widgets/conversation/ConversationBasicFilter.vue';
import ChatTypeTabs from './widgets/ChatTypeTabs'; import ChatTypeTabs from './widgets/ChatTypeTabs.vue';
import ConversationCard from './widgets/conversation/ConversationCard'; import ConversationCard from './widgets/conversation/ConversationCard.vue';
import timeMixin from '../mixins/time'; import timeMixin from '../mixins/time';
import eventListenerMixins from 'shared/mixins/eventListenerMixins'; import eventListenerMixins from 'shared/mixins/eventListenerMixins';
import conversationMixin from '../mixins/conversations'; import conversationMixin from '../mixins/conversations';
import wootConstants from 'dashboard/constants/globals'; import wootConstants from 'dashboard/constants/globals';
import advancedFilterTypes from './widgets/conversation/advancedFilterItems'; import advancedFilterTypes from './widgets/conversation/advancedFilterItems';
import filterQueryGenerator from '../helper/filterQueryGenerator.js'; import filterQueryGenerator from '../helper/filterQueryGenerator.js';
import AddCustomViews from 'dashboard/routes/dashboard/customviews/AddCustomViews'; import AddCustomViews from 'dashboard/routes/dashboard/customviews/AddCustomViews.vue';
import DeleteCustomViews from 'dashboard/routes/dashboard/customviews/DeleteCustomViews.vue'; import DeleteCustomViews from 'dashboard/routes/dashboard/customviews/DeleteCustomViews.vue';
import ConversationBulkActions from './widgets/conversation/conversationBulkActions/Index.vue'; import ConversationBulkActions from './widgets/conversation/conversationBulkActions/Index.vue';
import alertMixin from 'shared/mixins/alertMixin'; import alertMixin from 'shared/mixins/alertMixin';

View File

@ -10,7 +10,7 @@
</template> </template>
<script> <script>
import WootSnackbar from './Snackbar'; import WootSnackbar from './Snackbar.vue';
export default { export default {
components: { components: {

View File

@ -13,7 +13,7 @@
</template> </template>
<script> <script>
import Spinner from 'shared/components/Spinner'; import Spinner from 'shared/components/Spinner.vue';
export default { export default {
components: { components: {

View File

@ -90,7 +90,7 @@ import { getUnixTime } from 'date-fns';
import { mapGetters } from 'vuex'; import { mapGetters } from 'vuex';
import { mixin as clickaway } from 'vue-clickaway'; import { mixin as clickaway } from 'vue-clickaway';
import alertMixin from 'shared/mixins/alertMixin'; import alertMixin from 'shared/mixins/alertMixin';
import CustomSnoozeModal from 'dashboard/components/CustomSnoozeModal'; import CustomSnoozeModal from 'dashboard/components/CustomSnoozeModal.vue';
import eventListenerMixins from 'shared/mixins/eventListenerMixins'; import eventListenerMixins from 'shared/mixins/eventListenerMixins';
import { import {
hasPressedAltAndEKey, hasPressedAltAndEKey,

View File

@ -49,11 +49,11 @@
import { mapGetters } from 'vuex'; import { mapGetters } from 'vuex';
import { mixin as clickaway } from 'vue-clickaway'; import { mixin as clickaway } from 'vue-clickaway';
import alertMixin from 'shared/mixins/alertMixin'; import alertMixin from 'shared/mixins/alertMixin';
import WootDropdownItem from 'shared/components/ui/dropdown/DropdownItem'; import WootDropdownItem from 'shared/components/ui/dropdown/DropdownItem.vue';
import WootDropdownMenu from 'shared/components/ui/dropdown/DropdownMenu'; import WootDropdownMenu from 'shared/components/ui/dropdown/DropdownMenu.vue';
import WootDropdownHeader from 'shared/components/ui/dropdown/DropdownHeader'; import WootDropdownHeader from 'shared/components/ui/dropdown/DropdownHeader.vue';
import WootDropdownDivider from 'shared/components/ui/dropdown/DropdownDivider'; import WootDropdownDivider from 'shared/components/ui/dropdown/DropdownDivider.vue';
import AvailabilityStatusBadge from '../widgets/conversation/AvailabilityStatusBadge'; import AvailabilityStatusBadge from '../widgets/conversation/AvailabilityStatusBadge.vue';
import wootConstants from 'dashboard/constants/globals'; import wootConstants from 'dashboard/constants/globals';
const { AVAILABILITY_STATUS_KEYS } = wootConstants; const { AVAILABILITY_STATUS_KEYS } = wootConstants;

View File

@ -35,8 +35,8 @@ import adminMixin from '../../mixins/isAdmin';
import { getSidebarItems } from './config/default-sidebar'; import { getSidebarItems } from './config/default-sidebar';
import alertMixin from 'shared/mixins/alertMixin'; import alertMixin from 'shared/mixins/alertMixin';
import PrimarySidebar from './sidebarComponents/Primary'; import PrimarySidebar from './sidebarComponents/Primary.vue';
import SecondarySidebar from './sidebarComponents/Secondary'; import SecondarySidebar from './sidebarComponents/Secondary.vue';
import { import {
hasPressedAltAndCKey, hasPressedAltAndCKey,
hasPressedAltAndRKey, hasPressedAltAndRKey,

View File

@ -16,7 +16,7 @@
</template> </template>
<script> <script>
import { mapGetters } from 'vuex'; import { mapGetters } from 'vuex';
import Thumbnail from '../../widgets/Thumbnail'; import Thumbnail from '../../widgets/Thumbnail.vue';
export default { export default {
components: { components: {

View File

@ -109,9 +109,9 @@
import { mixin as clickaway } from 'vue-clickaway'; import { mixin as clickaway } from 'vue-clickaway';
import { mapGetters } from 'vuex'; import { mapGetters } from 'vuex';
import Auth from '../../../api/auth'; import Auth from '../../../api/auth';
import WootDropdownItem from 'shared/components/ui/dropdown/DropdownItem'; import WootDropdownItem from 'shared/components/ui/dropdown/DropdownItem.vue';
import WootDropdownMenu from 'shared/components/ui/dropdown/DropdownMenu'; import WootDropdownMenu from 'shared/components/ui/dropdown/DropdownMenu.vue';
import AvailabilityStatus from 'dashboard/components/layout/AvailabilityStatus'; import AvailabilityStatus from 'dashboard/components/layout/AvailabilityStatus.vue';
export default { export default {
components: { components: {

View File

@ -39,11 +39,11 @@
</div> </div>
</template> </template>
<script> <script>
import Logo from './Logo'; import Logo from './Logo.vue';
import PrimaryNavItem from './PrimaryNavItem'; import PrimaryNavItem from './PrimaryNavItem.vue';
import OptionsMenu from './OptionsMenu'; import OptionsMenu from './OptionsMenu.vue';
import AgentDetails from './AgentDetails'; import AgentDetails from './AgentDetails.vue';
import NotificationBell from './NotificationBell'; import NotificationBell from './NotificationBell.vue';
import wootConstants from 'dashboard/constants/globals'; import wootConstants from 'dashboard/constants/globals';
import { frontendURL } from 'dashboard/helper/URLHelper'; import { frontendURL } from 'dashboard/helper/URLHelper';
import { ACCOUNT_EVENTS } from '../../../helper/AnalyticsHelper/events'; import { ACCOUNT_EVENTS } from '../../../helper/AnalyticsHelper/events';

View File

@ -97,7 +97,7 @@ import {
getInboxWarningIconClass, getInboxWarningIconClass,
} from 'dashboard/helper/inbox'; } from 'dashboard/helper/inbox';
import SecondaryChildNavItem from './SecondaryChildNavItem'; import SecondaryChildNavItem from './SecondaryChildNavItem.vue';
import { import {
isOnMentionsView, isOnMentionsView,
isOnUnattendedView, isOnUnattendedView,

View File

@ -28,8 +28,8 @@
</button> </button>
</template> </template>
<script> <script>
import Spinner from 'shared/components/Spinner'; import Spinner from 'shared/components/Spinner.vue';
import EmojiOrIcon from 'shared/components/EmojiOrIcon'; import EmojiOrIcon from 'shared/components/EmojiOrIcon.vue';
export default { export default {
name: 'WootButton', name: 'WootButton',

View File

@ -108,7 +108,7 @@
<script> <script>
import AutomationActionTeamMessageInput from './AutomationActionTeamMessageInput.vue'; import AutomationActionTeamMessageInput from './AutomationActionTeamMessageInput.vue';
import AutomationActionFileInput from './AutomationFileInput.vue'; import AutomationActionFileInput from './AutomationFileInput.vue';
import WootMessageEditor from 'dashboard/components/widgets/WootWriter/Editor'; import WootMessageEditor from 'dashboard/components/widgets/WootWriter/Editor.vue';
export default { export default {
components: { components: {
AutomationActionTeamMessageInput, AutomationActionTeamMessageInput,

View File

@ -26,7 +26,7 @@
</template> </template>
<script> <script>
import Spinner from 'shared/components/Spinner'; import Spinner from 'shared/components/Spinner.vue';
import alertMixin from 'shared/mixins/alertMixin'; import alertMixin from 'shared/mixins/alertMixin';
export default { export default {
components: { components: {

View File

@ -7,7 +7,7 @@
/> />
</template> </template>
<script> <script>
import ChannelSelector from '../ChannelSelector'; import ChannelSelector from '../ChannelSelector.vue';
export default { export default {
components: { ChannelSelector }, components: { ChannelSelector },
props: { props: {

View File

@ -21,7 +21,7 @@
</template> </template>
<script> <script>
import LoadingState from 'dashboard/components/widgets/LoadingState'; import LoadingState from 'dashboard/components/widgets/LoadingState.vue';
export default { export default {
components: { components: {
LoadingState, LoadingState,

View File

@ -30,9 +30,9 @@
</template> </template>
<script> <script>
import AddLabel from 'shared/components/ui/dropdown/AddLabel'; import AddLabel from 'shared/components/ui/dropdown/AddLabel.vue';
import eventListenerMixins from 'shared/mixins/eventListenerMixins'; import eventListenerMixins from 'shared/mixins/eventListenerMixins';
import LabelDropdown from 'shared/components/ui/label/LabelDropdown'; import LabelDropdown from 'shared/components/ui/label/LabelDropdown.vue';
import { mixin as clickaway } from 'vue-clickaway'; import { mixin as clickaway } from 'vue-clickaway';
import adminMixin from 'dashboard/mixins/isAdmin'; import adminMixin from 'dashboard/mixins/isAdmin';
import { import {

View File

@ -42,7 +42,7 @@
* Badge - Chat source indication { fb / telegram } * Badge - Chat source indication { fb / telegram }
* Username - Username for avatar * Username - Username for avatar
*/ */
import Avatar from './Avatar'; import Avatar from './Avatar.vue';
import { removeEmoji } from 'shared/helpers/emoji'; import { removeEmoji } from 'shared/helpers/emoji';
export default { export default {

View File

@ -17,7 +17,7 @@
</div> </div>
</template> </template>
<script> <script>
import Thumbnail from './Thumbnail'; import Thumbnail from './Thumbnail.vue';
export default { export default {
components: { components: {

View File

@ -41,9 +41,9 @@ import {
triggerCharacters, triggerCharacters,
} from '@chatwoot/prosemirror-schema/src/mentions/plugin'; } from '@chatwoot/prosemirror-schema/src/mentions/plugin';
import TagAgents from '../conversation/TagAgents'; import TagAgents from '../conversation/TagAgents.vue';
import CannedResponse from '../conversation/CannedResponse'; import CannedResponse from '../conversation/CannedResponse.vue';
import VariableList from '../conversation/VariableList'; import VariableList from '../conversation/VariableList.vue';
import { import {
appendSignature, appendSignature,
removeSignature, removeSignature,
@ -670,6 +670,10 @@ export default {
.ProseMirror-prompt { .ProseMirror-prompt {
@apply z-50 bg-slate-25 dark:bg-slate-700 rounded-md border border-solid border-slate-75 dark:border-slate-800; @apply z-50 bg-slate-25 dark:bg-slate-700 rounded-md border border-solid border-slate-75 dark:border-slate-800;
h5 {
@apply dark:text-slate-25 text-slate-800;
}
} }
.is-private { .is-private {

View File

@ -134,7 +134,7 @@ import {
ALLOWED_FILE_TYPES, ALLOWED_FILE_TYPES,
ALLOWED_FILE_TYPES_FOR_TWILIO_WHATSAPP, ALLOWED_FILE_TYPES_FOR_TWILIO_WHATSAPP,
} from 'shared/constants/messages'; } from 'shared/constants/messages';
import VideoCallButton from '../VideoCallButton'; import VideoCallButton from '../VideoCallButton.vue';
import AIAssistanceButton from '../AIAssistanceButton.vue'; import AIAssistanceButton from '../AIAssistanceButton.vue';
import { REPLY_EDITOR_MODES } from './constants'; import { REPLY_EDITOR_MODES } from './constants';
import { mapGetters } from 'vuex'; import { mapGetters } from 'vuex';

View File

@ -46,7 +46,7 @@
import wootConstants from 'dashboard/constants/globals'; import wootConstants from 'dashboard/constants/globals';
import { mapGetters } from 'vuex'; import { mapGetters } from 'vuex';
import { mixin as clickaway } from 'vue-clickaway'; import { mixin as clickaway } from 'vue-clickaway';
import FilterItem from './FilterItem'; import FilterItem from './FilterItem.vue';
export default { export default {
components: { components: {

View File

@ -58,11 +58,11 @@
</template> </template>
<script> <script>
import { mapGetters } from 'vuex'; import { mapGetters } from 'vuex';
import ContactPanel from 'dashboard/routes/dashboard/conversation/ContactPanel'; import ContactPanel from 'dashboard/routes/dashboard/conversation/ContactPanel.vue';
import ConversationHeader from './ConversationHeader'; import ConversationHeader from './ConversationHeader.vue';
import DashboardAppFrame from '../DashboardApp/Frame.vue'; import DashboardAppFrame from '../DashboardApp/Frame.vue';
import EmptyState from './EmptyState/EmptyState'; import EmptyState from './EmptyState/EmptyState.vue';
import MessagesView from './MessagesView'; import MessagesView from './MessagesView.vue';
export default { export default {
components: { components: {

View File

@ -147,16 +147,16 @@
import { mapGetters } from 'vuex'; import { mapGetters } from 'vuex';
import { MESSAGE_TYPE } from 'widget/helpers/constants'; import { MESSAGE_TYPE } from 'widget/helpers/constants';
import messageFormatterMixin from 'shared/mixins/messageFormatterMixin'; import messageFormatterMixin from 'shared/mixins/messageFormatterMixin';
import Thumbnail from '../Thumbnail'; import Thumbnail from '../Thumbnail.vue';
import conversationMixin from '../../../mixins/conversations'; import conversationMixin from '../../../mixins/conversations';
import timeMixin from '../../../mixins/time'; import timeMixin from '../../../mixins/time';
import router from '../../../routes'; import router from '../../../routes';
import { frontendURL, conversationUrl } from '../../../helper/URLHelper'; import { frontendURL, conversationUrl } from '../../../helper/URLHelper';
import InboxName from '../InboxName'; import InboxName from '../InboxName.vue';
import inboxMixin from 'shared/mixins/inboxMixin'; import inboxMixin from 'shared/mixins/inboxMixin';
import ConversationContextMenu from './contextMenu/Index.vue'; import ConversationContextMenu from './contextMenu/Index.vue';
import alertMixin from 'shared/mixins/alertMixin'; import alertMixin from 'shared/mixins/alertMixin';
import TimeAgo from 'dashboard/components/ui/TimeAgo'; import TimeAgo from 'dashboard/components/ui/TimeAgo.vue';
import CardLabels from './conversationCardComponents/CardLabels.vue'; import CardLabels from './conversationCardComponents/CardLabels.vue';
import PriorityMark from './PriorityMark.vue'; import PriorityMark from './PriorityMark.vue';
const ATTACHMENT_ICONS = { const ATTACHMENT_ICONS = {

View File

@ -73,12 +73,12 @@
import { hasPressedAltAndOKey } from 'shared/helpers/KeyboardHelpers'; import { hasPressedAltAndOKey } from 'shared/helpers/KeyboardHelpers';
import { mapGetters } from 'vuex'; import { mapGetters } from 'vuex';
import agentMixin from '../../../mixins/agentMixin.js'; import agentMixin from '../../../mixins/agentMixin.js';
import BackButton from '../BackButton'; import BackButton from '../BackButton.vue';
import eventListenerMixins from 'shared/mixins/eventListenerMixins'; import eventListenerMixins from 'shared/mixins/eventListenerMixins';
import inboxMixin from 'shared/mixins/inboxMixin'; import inboxMixin from 'shared/mixins/inboxMixin';
import InboxName from '../InboxName'; import InboxName from '../InboxName.vue';
import MoreActions from './MoreActions'; import MoreActions from './MoreActions.vue';
import Thumbnail from '../Thumbnail'; import Thumbnail from '../Thumbnail.vue';
import wootConstants from 'dashboard/constants/globals'; import wootConstants from 'dashboard/constants/globals';
import { conversationListPageURL } from 'dashboard/helper/URLHelper'; import { conversationListPageURL } from 'dashboard/helper/URLHelper';
import { conversationReopenTime } from 'dashboard/helper/snoozeHelpers'; import { conversationReopenTime } from 'dashboard/helper/snoozeHelpers';

View File

@ -37,8 +37,8 @@
import { mapGetters } from 'vuex'; import { mapGetters } from 'vuex';
import adminMixin from 'dashboard/mixins/isAdmin'; import adminMixin from 'dashboard/mixins/isAdmin';
import accountMixin from 'dashboard/mixins/account'; import accountMixin from 'dashboard/mixins/account';
import OnboardingView from '../OnboardingView'; import OnboardingView from '../OnboardingView.vue';
import EmptyStateMessage from './EmptyStateMessage'; import EmptyStateMessage from './EmptyStateMessage.vue';
export default { export default {
components: { components: {

View File

@ -27,7 +27,7 @@
</template> </template>
<script> <script>
import Hotkey from 'dashboard/components/base/Hotkey'; import Hotkey from 'dashboard/components/base/Hotkey.vue';
export default { export default {
components: { components: {

View File

@ -130,18 +130,18 @@
</template> </template>
<script> <script>
import messageFormatterMixin from 'shared/mixins/messageFormatterMixin'; import messageFormatterMixin from 'shared/mixins/messageFormatterMixin';
import BubbleActions from './bubble/Actions'; import BubbleActions from './bubble/Actions.vue';
import BubbleFile from './bubble/File'; import BubbleFile from './bubble/File.vue';
import BubbleImage from './bubble/Image'; import BubbleImage from './bubble/Image.vue';
import BubbleVideo from './bubble/Video'; import BubbleVideo from './bubble/Video.vue';
import BubbleImageAudioVideo from './bubble/ImageAudioVideo'; import BubbleImageAudioVideo from './bubble/ImageAudioVideo.vue';
import BubbleIntegration from './bubble/Integration.vue'; import BubbleIntegration from './bubble/Integration.vue';
import BubbleLocation from './bubble/Location'; import BubbleLocation from './bubble/Location.vue';
import BubbleMailHead from './bubble/MailHead'; import BubbleMailHead from './bubble/MailHead.vue';
import BubbleText from './bubble/Text'; import BubbleText from './bubble/Text.vue';
import BubbleContact from './bubble/Contact'; import BubbleContact from './bubble/Contact.vue';
import Spinner from 'shared/components/Spinner'; import Spinner from 'shared/components/Spinner.vue';
import ContextMenu from 'dashboard/modules/conversations/components/MessageContextMenu'; import ContextMenu from 'dashboard/modules/conversations/components/MessageContextMenu.vue';
import instagramImageErrorPlaceholder from './instagramImageErrorPlaceholder.vue'; import instagramImageErrorPlaceholder from './instagramImageErrorPlaceholder.vue';
import alertMixin from 'shared/mixins/alertMixin'; import alertMixin from 'shared/mixins/alertMixin';
import contentTypeMixin from 'shared/mixins/contentTypeMixin'; import contentTypeMixin from 'shared/mixins/contentTypeMixin';

View File

@ -98,9 +98,9 @@
<script> <script>
// components // components
import ReplyBox from './ReplyBox'; import ReplyBox from './ReplyBox.vue';
import Message from './Message'; import Message from './Message.vue';
import ConversationLabelSuggestion from './conversation/LabelSuggestion'; import ConversationLabelSuggestion from './conversation/LabelSuggestion.vue';
import Banner from 'dashboard/components/ui/Banner.vue'; import Banner from 'dashboard/components/ui/Banner.vue';
// stores and apis // stores and apis

View File

@ -39,8 +39,8 @@
import { mapGetters } from 'vuex'; import { mapGetters } from 'vuex';
import { mixin as clickaway } from 'vue-clickaway'; import { mixin as clickaway } from 'vue-clickaway';
import alertMixin from 'shared/mixins/alertMixin'; import alertMixin from 'shared/mixins/alertMixin';
import EmailTranscriptModal from './EmailTranscriptModal'; import EmailTranscriptModal from './EmailTranscriptModal.vue';
import ResolveAction from '../../buttons/ResolveAction'; import ResolveAction from '../../buttons/ResolveAction.vue';
import { import {
CMD_MUTE_CONVERSATION, CMD_MUTE_CONVERSATION,
CMD_SEND_TRANSCRIPT, CMD_SEND_TRANSCRIPT,

View File

@ -148,16 +148,16 @@ import { mapGetters } from 'vuex';
import { mixin as clickaway } from 'vue-clickaway'; import { mixin as clickaway } from 'vue-clickaway';
import alertMixin from 'shared/mixins/alertMixin'; import alertMixin from 'shared/mixins/alertMixin';
import CannedResponse from './CannedResponse'; import CannedResponse from './CannedResponse.vue';
import ResizableTextArea from 'shared/components/ResizableTextArea'; import ResizableTextArea from 'shared/components/ResizableTextArea.vue';
import AttachmentPreview from 'dashboard/components/widgets/AttachmentsPreview'; import AttachmentPreview from 'dashboard/components/widgets/AttachmentsPreview.vue';
import ReplyTopPanel from 'dashboard/components/widgets/WootWriter/ReplyTopPanel'; import ReplyTopPanel from 'dashboard/components/widgets/WootWriter/ReplyTopPanel.vue';
import ReplyEmailHead from './ReplyEmailHead'; import ReplyEmailHead from './ReplyEmailHead.vue';
import ReplyBottomPanel from 'dashboard/components/widgets/WootWriter/ReplyBottomPanel'; import ReplyBottomPanel from 'dashboard/components/widgets/WootWriter/ReplyBottomPanel.vue';
import Banner from 'dashboard/components/ui/Banner.vue'; import Banner from 'dashboard/components/ui/Banner.vue';
import { REPLY_EDITOR_MODES } from 'dashboard/components/widgets/WootWriter/constants'; import { REPLY_EDITOR_MODES } from 'dashboard/components/widgets/WootWriter/constants';
import WootMessageEditor from 'dashboard/components/widgets/WootWriter/Editor'; import WootMessageEditor from 'dashboard/components/widgets/WootWriter/Editor.vue';
import WootAudioRecorder from 'dashboard/components/widgets/WootWriter/AudioRecorder'; import WootAudioRecorder from 'dashboard/components/widgets/WootWriter/AudioRecorder.vue';
import messageFormatterMixin from 'shared/mixins/messageFormatterMixin'; import messageFormatterMixin from 'shared/mixins/messageFormatterMixin';
import { checkFileSizeLimit } from 'shared/helpers/FileHelper'; import { checkFileSizeLimit } from 'shared/helpers/FileHelper';
import { import {

View File

@ -31,7 +31,7 @@
import { mapGetters } from 'vuex'; import { mapGetters } from 'vuex';
import { hasPressedCommand } from 'shared/helpers/KeyboardHelpers'; import { hasPressedCommand } from 'shared/helpers/KeyboardHelpers';
import GalleryView from '../components/GalleryView'; import GalleryView from '../components/GalleryView.vue';
const ALLOWED_FILE_TYPES = { const ALLOWED_FILE_TYPES = {
IMAGE: 'image', IMAGE: 'image',

View File

@ -150,7 +150,7 @@ import {
import eventListenerMixins from 'shared/mixins/eventListenerMixins'; import eventListenerMixins from 'shared/mixins/eventListenerMixins';
import timeMixin from 'dashboard/mixins/time'; import timeMixin from 'dashboard/mixins/time';
import Thumbnail from 'dashboard/components/widgets/Thumbnail'; import Thumbnail from 'dashboard/components/widgets/Thumbnail.vue';
const ALLOWED_FILE_TYPES = { const ALLOWED_FILE_TYPES = {
IMAGE: 'image', IMAGE: 'image',

View File

@ -6,7 +6,7 @@
</template> </template>
<script> <script>
import Spinner from 'shared/components/Spinner'; import Spinner from 'shared/components/Spinner.vue';
export default { export default {
components: { components: {

View File

@ -96,7 +96,7 @@
<script> <script>
import { mapGetters } from 'vuex'; import { mapGetters } from 'vuex';
import Thumbnail from 'dashboard/components/widgets/Thumbnail.vue'; import Thumbnail from 'dashboard/components/widgets/Thumbnail.vue';
import Spinner from 'shared/components/Spinner'; import Spinner from 'shared/components/Spinner.vue';
import { mixin as clickaway } from 'vue-clickaway'; import { mixin as clickaway } from 'vue-clickaway';
export default { export default {

View File

@ -23,7 +23,7 @@
<script> <script>
import { required } from 'vuelidate/lib/validators'; import { required } from 'vuelidate/lib/validators';
import Modal from '../../Modal'; import Modal from '../../Modal.vue';
export default { export default {
components: { components: {

View File

@ -14,7 +14,7 @@
</modal> </modal>
</template> </template>
<script> <script>
import Modal from '../../Modal'; import Modal from '../../Modal.vue';
export default { export default {
components: { components: {

View File

@ -22,7 +22,7 @@
</template> </template>
<script> <script>
import Modal from '../../Modal'; import Modal from '../../Modal.vue';
export default { export default {
components: { components: {

View File

@ -95,7 +95,7 @@
<script> <script>
import { mixin as clickaway } from 'vue-clickaway'; import { mixin as clickaway } from 'vue-clickaway';
import { SHORTCUT_KEYS } from './constants'; import { SHORTCUT_KEYS } from './constants';
import Hotkey from 'dashboard/components/base/Hotkey'; import Hotkey from 'dashboard/components/base/Hotkey.vue';
export default { export default {
components: { components: {

View File

@ -1,3 +1,9 @@
import {
messageSchema,
MessageMarkdownTransformer,
MessageMarkdownSerializer,
} from '@chatwoot/prosemirror-schema';
/** /**
* The delimiter used to separate the signature from the rest of the body. * The delimiter used to separate the signature from the rest of the body.
* @type {string} * @type {string}
@ -5,12 +11,12 @@
export const SIGNATURE_DELIMITER = '--'; export const SIGNATURE_DELIMITER = '--';
/** /**
* Trim the signature and remove all " \r" from the signature * Parse and Serialize the markdown text to remove any extra spaces or new lines
* 1. Trim any extra lines or spaces at the start or end of the string
* 2. Converts all \r or \r\n to \f
*/ */
export function cleanSignature(signature) { export function cleanSignature(signature) {
return signature.trim().replace(/\r\n?/g, '\n'); // convert from markdown to common mark format
const nodes = new MessageMarkdownTransformer(messageSchema).parse(signature);
return MessageMarkdownSerializer.serialize(nodes);
} }
/** /**

View File

@ -1,21 +1,34 @@
const setArrayValues = item => { const setArrayValues = item => {
return item.values[0]?.id ? item.values.map(val => val.id) : item.values; return item.values[0]?.id ? item.values.map(val => val.id) : item.values;
}; };
const generateValues = item => {
if (item.attribute_key === 'content') {
const values = item.values || '';
return values.split(',');
}
if (Array.isArray(item.values)) {
return setArrayValues(item);
}
if (typeof item.values === 'object') {
return [item.values.id];
}
if (!item.values) {
return [];
}
return [item.values];
};
const generatePayload = data => { const generatePayload = data => {
// Make a copy of data to avoid vue data reactivity issues // Make a copy of data to avoid vue data reactivity issues
const filters = JSON.parse(JSON.stringify(data)); const filters = JSON.parse(JSON.stringify(data));
let payload = filters.map(item => { let payload = filters.map(item => {
if (Array.isArray(item.values)) { // If item key is content, we will split it using comma and return as array
item.values = setArrayValues(item); // FIX ME: Make this generic option instead of using the key directly here
} else if (typeof item.values === 'object') { item.values = generateValues(item);
item.values = [item.values.id];
} else if (!item.values) {
item.values = [];
} else {
item.values = [item.values];
}
return item; return item;
}); });
// For every query added, the query_operator is set default to and so the // For every query added, the query_operator is set default to and so the
// last query will have an extra query_operator, this would break the api. // last query will have an extra query_operator, this would break the api.
// Setting this to null for all query payload // Setting this to null for all query payload

View File

@ -3,6 +3,7 @@ import {
appendSignature, appendSignature,
removeSignature, removeSignature,
replaceSignature, replaceSignature,
cleanSignature,
extractTextFromMarkdown, extractTextFromMarkdown,
} from '../editorHelper'; } from '../editorHelper';
@ -17,10 +18,18 @@ const DOES_NOT_HAVE_SIGNATURE = {
body: 'This is a test\n\n--\n\nThis is a signature\n\nThis is more text', body: 'This is a test\n\n--\n\nThis is a signature\n\nThis is more text',
signature: 'This is a signature', signature: 'This is a signature',
}, },
signature_has_images: { 'signature has images': {
body: 'This is a test', body: 'This is a test',
signature: signature:
'Testing \n![](http://localhost:3000/rails/active_storage/blobs/redirect/some-hash/image.png)', 'Testing\n![](http://localhost:3000/rails/active_storage/blobs/redirect/some-hash/image.png)',
},
'signature has non commonmark syntax': {
body: 'This is a test',
signature: '- Signature',
},
'signature has trailing spaces': {
body: 'This is a test',
signature: '**hello** \n**world**',
}, },
}; };
@ -37,6 +46,10 @@ const HAS_SIGNATURE = {
body: '\n\n--\n\nThis is a signature', body: '\n\n--\n\nThis is a signature',
signature: 'This is a signature', signature: 'This is a signature',
}, },
'signature has non-commonmark syntax': {
body: '\n\n--\n\n* Signature',
signature: '- Signature',
},
}; };
describe('findSignatureInBody', () => { describe('findSignatureInBody', () => {
@ -58,9 +71,10 @@ describe('appendSignature', () => {
it('appends the signature if it is not present', () => { it('appends the signature if it is not present', () => {
Object.keys(DOES_NOT_HAVE_SIGNATURE).forEach(key => { Object.keys(DOES_NOT_HAVE_SIGNATURE).forEach(key => {
const { body, signature } = DOES_NOT_HAVE_SIGNATURE[key]; const { body, signature } = DOES_NOT_HAVE_SIGNATURE[key];
expect(appendSignature(body, signature)).toBe( const cleanedSignature = cleanSignature(signature);
`${body}\n\n--\n\n${signature}` expect(
); appendSignature(body, signature).includes(cleanedSignature)
).toBeTruthy();
}); });
}); });
it('does not append signature if already present', () => { it('does not append signature if already present', () => {

View File

@ -25,10 +25,10 @@ describe('#Upload Helpers', () => {
axios.post.mockResolvedValueOnce(mockResponse); axios.post.mockResolvedValueOnce(mockResponse);
const result = await uploadFile(mockFile); const result = await uploadFile(mockFile, '1602');
expect(axios.post).toHaveBeenCalledWith( expect(axios.post).toHaveBeenCalledWith(
'/api/v1/upload', '/api/v1/accounts/1602/upload',
expect.any(FormData), expect.any(FormData),
{ headers: { 'Content-Type': 'multipart/form-data' } } { headers: { 'Content-Type': 'multipart/form-data' } }
); );

View File

@ -21,17 +21,25 @@ const HEADERS = {
* @param {File} file - The file to be uploaded. It should be a File object (typically coming from a file input element). * @param {File} file - The file to be uploaded. It should be a File object (typically coming from a file input element).
* @returns {Promise} A promise that resolves with the server's response when the upload is successful, or rejects if there's an error. * @returns {Promise} A promise that resolves with the server's response when the upload is successful, or rejects if there's an error.
*/ */
export async function uploadFile(file) { export async function uploadFile(file, accountId) {
// Create a new FormData instance. // Create a new FormData instance.
let formData = new FormData(); let formData = new FormData();
if (!accountId) {
accountId = window.location.pathname.split('/')[3];
}
// Append the file to the FormData instance under the key 'attachment'. // Append the file to the FormData instance under the key 'attachment'.
formData.append('attachment', file); formData.append('attachment', file);
// Use axios to send a POST request to the upload endpoint. // Use axios to send a POST request to the upload endpoint.
const { data } = await axios.post(`/api/${API_VERSION}/upload`, formData, { const { data } = await axios.post(
headers: HEADERS, `/api/${API_VERSION}/accounts/${accountId}/upload`,
}); formData,
{
headers: HEADERS,
}
);
return { return {
fileUrl: data.file_url, fileUrl: data.file_url,

View File

@ -371,6 +371,8 @@
"DETAILS": { "DETAILS": {
"LOADING_FB": "Authenticating you with Facebook...", "LOADING_FB": "Authenticating you with Facebook...",
"ERROR_FB_AUTH": "Something went wrong, Please refresh page...", "ERROR_FB_AUTH": "Something went wrong, Please refresh page...",
"ERROR_FB_UNAUTHORIZED": "You're not authorized to perform this action. ",
"ERROR_FB_UNAUTHORIZED_HELP": "Please ensure you have access to the Facebook page with full control. You can read more about Facebook roles <a href=\" https://www.facebook.com/help/187316341316631\">here</a>.",
"CREATING_CHANNEL": "Creating your Inbox...", "CREATING_CHANNEL": "Creating your Inbox...",
"TITLE": "Configure Inbox Details", "TITLE": "Configure Inbox Details",
"DESC": "" "DESC": ""

View File

@ -36,7 +36,7 @@
}, },
"MESSAGE_SIGNATURE_SECTION": { "MESSAGE_SIGNATURE_SECTION": {
"TITLE": "Personal message signature", "TITLE": "Personal message signature",
"NOTE": "Create a personal message signature that would be added to all the messages you send from your email inbox. Use the rich content editor to create a highly personalised signature.", "NOTE": "Create a unique message signature to appear at the end of every message you send from any inbox. You can also include an inline image, which is supported in live-chat, email, and API inboxes.",
"BTN_TEXT": "Save message signature", "BTN_TEXT": "Save message signature",
"API_ERROR": "Couldn't save signature! Try again", "API_ERROR": "Couldn't save signature! Try again",
"API_SUCCESS": "Signature saved successfully", "API_SUCCESS": "Signature saved successfully",

View File

@ -110,7 +110,7 @@
"SNOOZE_CONVERSATION": "Adiar Conversa", "SNOOZE_CONVERSATION": "Adiar Conversa",
"ADD_LABEL": "Adicionar etiqueta à conversa", "ADD_LABEL": "Adicionar etiqueta à conversa",
"REMOVE_LABEL": "Remover etiqueta da conversa", "REMOVE_LABEL": "Remover etiqueta da conversa",
"SETTINGS": "Confirgurações", "SETTINGS": "Configurações",
"AI_ASSIST": "Assistente IA", "AI_ASSIST": "Assistente IA",
"APPEARANCE": "Aspeto" "APPEARANCE": "Aspeto"
}, },

View File

@ -40,8 +40,8 @@
"BTN_TEXT": "Salvar assinatura da mensagem", "BTN_TEXT": "Salvar assinatura da mensagem",
"API_ERROR": "Não foi possível salvar a assinatura! Tente novamente", "API_ERROR": "Não foi possível salvar a assinatura! Tente novamente",
"API_SUCCESS": "Assinatura salva com sucesso", "API_SUCCESS": "Assinatura salva com sucesso",
"IMAGE_UPLOAD_ERROR": "Couldn't upload image! Try again", "IMAGE_UPLOAD_ERROR": "Não foi possível carregar a imagem! Tente novamente",
"IMAGE_UPLOAD_SUCCESS": "Image added successfully. Please click on save to save the signature", "IMAGE_UPLOAD_SUCCESS": "Imagem adicionada. Clique em salvar para salvar a assinatura",
"IMAGE_UPLOAD_SIZE_ERROR": "O tamanho da imagem deve ser inferior a {size}MB" "IMAGE_UPLOAD_SIZE_ERROR": "O tamanho da imagem deve ser inferior a {size}MB"
}, },
"MESSAGE_SIGNATURE": { "MESSAGE_SIGNATURE": {

View File

@ -199,6 +199,12 @@ export default {
values: condition.values[0], values: condition.values[0],
}; };
} }
if (inputType === 'comma_separated_plain_text') {
return {
...condition,
values: condition.values.join(','),
};
}
return { return {
...condition, ...condition,
query_operator: condition.query_operator || 'and', query_operator: condition.query_operator || 'and',

View File

@ -19,7 +19,7 @@
<script> <script>
import alertMixin from 'shared/mixins/alertMixin'; import alertMixin from 'shared/mixins/alertMixin';
import MergeContact from 'dashboard/modules/contact/components/MergeContact'; import MergeContact from 'dashboard/modules/contact/components/MergeContact.vue';
import ContactAPI from 'dashboard/api/contacts'; import ContactAPI from 'dashboard/api/contacts';

View File

@ -36,7 +36,7 @@
</template> </template>
<script> <script>
import Modal from 'dashboard/components/Modal'; import Modal from 'dashboard/components/Modal.vue';
import alertMixin from 'shared/mixins/alertMixin'; import alertMixin from 'shared/mixins/alertMixin';
import { required, minLength } from 'vuelidate/lib/validators'; import { required, minLength } from 'vuelidate/lib/validators';

View File

@ -45,7 +45,7 @@
</template> </template>
<script> <script>
import EmojiOrIcon from 'shared/components/EmojiOrIcon'; import EmojiOrIcon from 'shared/components/EmojiOrIcon.vue';
export default { export default {
components: { components: {

View File

@ -24,7 +24,7 @@
</template> </template>
<script> <script>
import Thumbnail from '../../../components/widgets/Thumbnail'; import Thumbnail from '../../../components/widgets/Thumbnail.vue';
export default { export default {
components: { components: {

View File

@ -52,7 +52,7 @@
</div> </div>
</template> </template>
<script> <script>
import Attribute from './ContactAttribute'; import Attribute from './ContactAttribute.vue';
export default { export default {
components: { Attribute }, components: { Attribute },

View File

@ -42,8 +42,8 @@
</div> </div>
</template> </template>
<script> <script>
import Thumbnail from 'dashboard/components/widgets/Thumbnail'; import Thumbnail from 'dashboard/components/widgets/Thumbnail.vue';
import SocialIcons from 'dashboard/routes/dashboard/conversation/contact/SocialIcons'; import SocialIcons from 'dashboard/routes/dashboard/conversation/contact/SocialIcons.vue';
export default { export default {
components: { components: {

View File

@ -30,11 +30,11 @@
</div> </div>
</template> </template>
<script> <script>
import EditContact from 'dashboard/routes/dashboard/conversation/contact/EditContact'; import EditContact from 'dashboard/routes/dashboard/conversation/contact/EditContact.vue';
import NewConversation from 'dashboard/routes/dashboard/conversation/contact/NewConversation'; import NewConversation from 'dashboard/routes/dashboard/conversation/contact/NewConversation.vue';
import AddCustomAttribute from 'dashboard/modules/contact/components/AddCustomAttribute'; import AddCustomAttribute from 'dashboard/modules/contact/components/AddCustomAttribute.vue';
import ContactIntro from './ContactIntro'; import ContactIntro from './ContactIntro.vue';
import ContactFields from './ContactFields'; import ContactFields from './ContactFields.vue';
export default { export default {
components: { components: {

View File

@ -110,8 +110,8 @@
import alertMixin from 'shared/mixins/alertMixin'; import alertMixin from 'shared/mixins/alertMixin';
import { required } from 'vuelidate/lib/validators'; import { required } from 'vuelidate/lib/validators';
import MergeContactSummary from 'dashboard/modules/contact/components/MergeContactSummary'; import MergeContactSummary from 'dashboard/modules/contact/components/MergeContactSummary.vue';
import ContactDropdownItem from './ContactDropdownItem'; import ContactDropdownItem from './ContactDropdownItem.vue';
export default { export default {
components: { MergeContactSummary, ContactDropdownItem }, components: { MergeContactSummary, ContactDropdownItem },

View File

@ -101,11 +101,11 @@ import alertMixin from 'shared/mixins/alertMixin';
import { mapGetters } from 'vuex'; import { mapGetters } from 'vuex';
import { mixin as clickaway } from 'vue-clickaway'; import { mixin as clickaway } from 'vue-clickaway';
import messageFormatterMixin from 'shared/mixins/messageFormatterMixin'; import messageFormatterMixin from 'shared/mixins/messageFormatterMixin';
import AddCannedModal from 'dashboard/routes/dashboard/settings/canned/AddCanned'; import AddCannedModal from 'dashboard/routes/dashboard/settings/canned/AddCanned.vue';
import { copyTextToClipboard } from 'shared/helpers/clipboard'; import { copyTextToClipboard } from 'shared/helpers/clipboard';
import { conversationUrl, frontendURL } from '../../../helper/URLHelper'; import { conversationUrl, frontendURL } from '../../../helper/URLHelper';
import { ACCOUNT_EVENTS } from '../../../helper/AnalyticsHelper/events'; import { ACCOUNT_EVENTS } from '../../../helper/AnalyticsHelper/events';
import TranslateModal from 'dashboard/components/widgets/conversation/bubble/TranslateModal'; import TranslateModal from 'dashboard/components/widgets/conversation/bubble/TranslateModal.vue';
import MenuItem from '../../../components/widgets/conversation/contextMenu/menuItem.vue'; import MenuItem from '../../../components/widgets/conversation/contextMenu/menuItem.vue';
export default { export default {

View File

@ -9,7 +9,7 @@
<script> <script>
import { mapGetters } from 'vuex'; import { mapGetters } from 'vuex';
import NoteList from './components/NoteList'; import NoteList from './components/NoteList.vue';
export default { export default {
components: { components: {

View File

@ -22,7 +22,7 @@
</template> </template>
<script> <script>
import WootMessageEditor from 'dashboard/components/widgets/WootWriter/Editor'; import WootMessageEditor from 'dashboard/components/widgets/WootWriter/Editor.vue';
import { hasPressedCommandAndEnter } from 'shared/helpers/KeyboardHelpers'; import { hasPressedCommandAndEnter } from 'shared/helpers/KeyboardHelpers';
export default { export default {
components: { components: {

View File

@ -51,7 +51,7 @@
</template> </template>
<script> <script>
import Thumbnail from 'dashboard/components/widgets/Thumbnail'; import Thumbnail from 'dashboard/components/widgets/Thumbnail.vue';
import timeMixin from 'dashboard/mixins/time'; import timeMixin from 'dashboard/mixins/time';
import messageFormatterMixin from 'shared/mixins/messageFormatterMixin'; import messageFormatterMixin from 'shared/mixins/messageFormatterMixin';

View File

@ -23,9 +23,9 @@
</template> </template>
<script> <script>
import AddNote from './AddNote'; import AddNote from './AddNote.vue';
import ContactNote from './ContactNote'; import ContactNote from './ContactNote.vue';
import Spinner from 'shared/components/Spinner'; import Spinner from 'shared/components/Spinner.vue';
export default { export default {
components: { components: {

View File

@ -30,7 +30,7 @@
import { mapGetters } from 'vuex'; import { mapGetters } from 'vuex';
import SearchResultConversationItem from './SearchResultConversationItem.vue'; import SearchResultConversationItem from './SearchResultConversationItem.vue';
import SearchResultSection from './SearchResultSection.vue'; import SearchResultSection from './SearchResultSection.vue';
import MessageContent from './MessageContent'; import MessageContent from './MessageContent.vue';
export default { export default {
components: { components: {

View File

@ -48,10 +48,10 @@
</template> </template>
<script> <script>
import WidgetHead from './WidgetHead'; import WidgetHead from './WidgetHead.vue';
import WidgetBody from './WidgetBody'; import WidgetBody from './WidgetBody.vue';
import WidgetFooter from './WidgetFooter'; import WidgetFooter from './WidgetFooter.vue';
import InputRadioGroup from 'dashboard/routes/dashboard/settings/inbox/components/InputRadioGroup'; import InputRadioGroup from 'dashboard/routes/dashboard/settings/inbox/components/InputRadioGroup.vue';
import globalConfigMixin from 'shared/mixins/globalConfigMixin'; import globalConfigMixin from 'shared/mixins/globalConfigMixin';
import { mapGetters } from 'vuex'; import { mapGetters } from 'vuex';

View File

@ -47,7 +47,7 @@
</template> </template>
<script> <script>
import Thumbnail from 'dashboard/components/widgets/Thumbnail'; import Thumbnail from 'dashboard/components/widgets/Thumbnail.vue';
export default { export default {
name: 'WidgetBody', name: 'WidgetBody',
components: { components: {

View File

@ -26,8 +26,8 @@
</template> </template>
<script> <script>
import CustomButton from 'dashboard/components/buttons/Button'; import CustomButton from 'dashboard/components/buttons/Button.vue';
import ResizableTextArea from 'shared/components/ResizableTextArea'; import ResizableTextArea from 'shared/components/ResizableTextArea.vue';
export default { export default {
name: 'WidgetFooter', name: 'WidgetFooter',
components: { components: {

View File

@ -40,14 +40,14 @@
</template> </template>
<script> <script>
import Sidebar from '../../components/layout/Sidebar'; import Sidebar from '../../components/layout/Sidebar.vue';
import CommandBar from './commands/commandbar.vue'; import CommandBar from './commands/commandbar.vue';
import { BUS_EVENTS } from 'shared/constants/busEvents'; import { BUS_EVENTS } from 'shared/constants/busEvents';
import WootKeyShortcutModal from 'dashboard/components/widgets/modal/WootKeyShortcutModal'; import WootKeyShortcutModal from 'dashboard/components/widgets/modal/WootKeyShortcutModal.vue';
import AddAccountModal from 'dashboard/components/layout/sidebarComponents/AddAccountModal'; import AddAccountModal from 'dashboard/components/layout/sidebarComponents/AddAccountModal.vue';
import AccountSelector from 'dashboard/components/layout/sidebarComponents/AccountSelector'; import AccountSelector from 'dashboard/components/layout/sidebarComponents/AccountSelector.vue';
import AddLabelModal from 'dashboard/routes/dashboard/settings/labels/AddLabel'; import AddLabelModal from 'dashboard/routes/dashboard/settings/labels/AddLabel.vue';
import NotificationPanel from 'dashboard/routes/dashboard/notifications/components/NotificationPanel'; import NotificationPanel from 'dashboard/routes/dashboard/notifications/components/NotificationPanel.vue';
import uiSettingsMixin from 'dashboard/mixins/uiSettings'; import uiSettingsMixin from 'dashboard/mixins/uiSettings';
import wootConstants from 'dashboard/constants/globals'; import wootConstants from 'dashboard/constants/globals';

View File

@ -80,9 +80,9 @@
</template> </template>
<script> <script>
import AccordionItem from 'dashboard/components/Accordion/AccordionItem'; import AccordionItem from 'dashboard/components/Accordion/AccordionItem.vue';
import ContactConversations from 'dashboard/routes/dashboard/conversation/ContactConversations'; import ContactConversations from 'dashboard/routes/dashboard/conversation/ContactConversations.vue';
import ContactInfo from 'dashboard/routes/dashboard/conversation/contact/ContactInfo'; import ContactInfo from 'dashboard/routes/dashboard/conversation/contact/ContactInfo.vue';
import ContactLabel from 'dashboard/routes/dashboard/contacts/components/ContactLabels.vue'; import ContactLabel from 'dashboard/routes/dashboard/contacts/components/ContactLabels.vue';
import CustomAttributes from 'dashboard/routes/dashboard/conversation/customAttributes/CustomAttributes.vue'; import CustomAttributes from 'dashboard/routes/dashboard/conversation/customAttributes/CustomAttributes.vue';
import CustomAttributeSelector from 'dashboard/routes/dashboard/conversation/customAttributes/CustomAttributeSelector.vue'; import CustomAttributeSelector from 'dashboard/routes/dashboard/conversation/customAttributes/CustomAttributeSelector.vue';

View File

@ -37,7 +37,7 @@ import Thumbnail from 'dashboard/components/widgets/Thumbnail.vue';
import EmptyState from 'dashboard/components/widgets/EmptyState.vue'; import EmptyState from 'dashboard/components/widgets/EmptyState.vue';
import timeMixin from 'dashboard/mixins/time'; import timeMixin from 'dashboard/mixins/time';
import rtlMixin from 'shared/mixins/rtlMixin'; import rtlMixin from 'shared/mixins/rtlMixin';
import FluentIcon from 'shared/components/FluentIcon/DashboardIcon'; import FluentIcon from 'shared/components/FluentIcon/DashboardIcon.vue';
export default { export default {
components: { components: {

View File

@ -81,17 +81,17 @@
<script> <script>
import { mapGetters } from 'vuex'; import { mapGetters } from 'vuex';
import ContactsHeader from './Header'; import ContactsHeader from './Header.vue';
import ContactsTable from './ContactsTable'; import ContactsTable from './ContactsTable.vue';
import ContactInfoPanel from './ContactInfoPanel'; import ContactInfoPanel from './ContactInfoPanel.vue';
import CreateContact from 'dashboard/routes/dashboard/conversation/contact/CreateContact'; import CreateContact from 'dashboard/routes/dashboard/conversation/contact/CreateContact.vue';
import TableFooter from 'dashboard/components/widgets/TableFooter'; import TableFooter from 'dashboard/components/widgets/TableFooter.vue';
import ImportContacts from './ImportContacts.vue'; import ImportContacts from './ImportContacts.vue';
import ContactsAdvancedFilters from './ContactsAdvancedFilters.vue'; import ContactsAdvancedFilters from './ContactsAdvancedFilters.vue';
import contactFilterItems from '../contactFilterItems'; import contactFilterItems from '../contactFilterItems';
import filterQueryGenerator from '../../../../helper/filterQueryGenerator'; import filterQueryGenerator from '../../../../helper/filterQueryGenerator';
import AddCustomViews from 'dashboard/routes/dashboard/customviews/AddCustomViews'; import AddCustomViews from 'dashboard/routes/dashboard/customviews/AddCustomViews.vue';
import DeleteCustomViews from 'dashboard/routes/dashboard/customviews/DeleteCustomViews'; import DeleteCustomViews from 'dashboard/routes/dashboard/customviews/DeleteCustomViews.vue';
import { CONTACTS_EVENTS } from '../../../../helper/AnalyticsHelper/events'; import { CONTACTS_EVENTS } from '../../../../helper/AnalyticsHelper/events';
import alertMixin from 'shared/mixins/alertMixin'; import alertMixin from 'shared/mixins/alertMixin';
import countries from 'shared/constants/countries.js'; import countries from 'shared/constants/countries.js';

View File

@ -42,7 +42,7 @@
</template> </template>
<script> <script>
import Modal from '../../../../components/Modal'; import Modal from '../../../../components/Modal.vue';
import { mapGetters } from 'vuex'; import { mapGetters } from 'vuex';
import alertMixin from 'shared/mixins/alertMixin'; import alertMixin from 'shared/mixins/alertMixin';
import { CONTACTS_EVENTS } from '../../../../helper/AnalyticsHelper/events'; import { CONTACTS_EVENTS } from '../../../../helper/AnalyticsHelper/events';

View File

@ -56,10 +56,10 @@
<script> <script>
import { mapGetters } from 'vuex'; import { mapGetters } from 'vuex';
import ContactInfoPanel from '../components/ContactInfoPanel.vue'; import ContactInfoPanel from '../components/ContactInfoPanel.vue';
import ContactNotes from 'dashboard/modules/notes/NotesOnContactPage'; import ContactNotes from 'dashboard/modules/notes/NotesOnContactPage.vue';
import SettingsHeader from '../../settings/SettingsHeader.vue'; import SettingsHeader from '../../settings/SettingsHeader.vue';
import Spinner from 'shared/components/Spinner'; import Spinner from 'shared/components/Spinner.vue';
import Thumbnail from 'dashboard/components/widgets/Thumbnail'; import Thumbnail from 'dashboard/components/widgets/Thumbnail.vue';
export default { export default {
components: { components: {

View File

@ -22,9 +22,9 @@
</template> </template>
<script> <script>
import ConversationCard from 'dashboard/components/widgets/conversation/ConversationCard'; import ConversationCard from 'dashboard/components/widgets/conversation/ConversationCard.vue';
import { mapGetters } from 'vuex'; import { mapGetters } from 'vuex';
import Spinner from 'shared/components/Spinner'; import Spinner from 'shared/components/Spinner.vue';
export default { export default {
components: { components: {

View File

@ -134,18 +134,18 @@
<script> <script>
import { mapGetters } from 'vuex'; import { mapGetters } from 'vuex';
import alertMixin from 'shared/mixins/alertMixin'; import alertMixin from 'shared/mixins/alertMixin';
import AccordionItem from 'dashboard/components/Accordion/AccordionItem'; import AccordionItem from 'dashboard/components/Accordion/AccordionItem.vue';
import ContactConversations from './ContactConversations.vue'; import ContactConversations from './ContactConversations.vue';
import ConversationAction from './ConversationAction.vue'; import ConversationAction from './ConversationAction.vue';
import ConversationParticipant from './ConversationParticipant.vue'; import ConversationParticipant from './ConversationParticipant.vue';
import ContactInfo from './contact/ContactInfo'; import ContactInfo from './contact/ContactInfo.vue';
import ConversationInfo from './ConversationInfo'; import ConversationInfo from './ConversationInfo.vue';
import CustomAttributes from './customAttributes/CustomAttributes.vue'; import CustomAttributes from './customAttributes/CustomAttributes.vue';
import CustomAttributeSelector from './customAttributes/CustomAttributeSelector.vue'; import CustomAttributeSelector from './customAttributes/CustomAttributeSelector.vue';
import draggable from 'vuedraggable'; import draggable from 'vuedraggable';
import uiSettingsMixin from 'dashboard/mixins/uiSettings'; import uiSettingsMixin from 'dashboard/mixins/uiSettings';
import MacrosList from './Macros/List'; import MacrosList from './Macros/List.vue';
export default { export default {
components: { components: {

View File

@ -79,12 +79,12 @@
<script> <script>
import { mixin as clickaway } from 'vue-clickaway'; import { mixin as clickaway } from 'vue-clickaway';
import Spinner from 'shared/components/Spinner'; import Spinner from 'shared/components/Spinner.vue';
import alertMixin from 'shared/mixins/alertMixin'; import alertMixin from 'shared/mixins/alertMixin';
import { mapGetters } from 'vuex'; import { mapGetters } from 'vuex';
import agentMixin from 'dashboard/mixins/agentMixin'; import agentMixin from 'dashboard/mixins/agentMixin';
import ThumbnailGroup from 'dashboard/components/widgets/ThumbnailGroup'; import ThumbnailGroup from 'dashboard/components/widgets/ThumbnailGroup.vue';
import MultiselectDropdownItems from 'shared/components/ui/MultiselectDropdownItems'; import MultiselectDropdownItems from 'shared/components/ui/MultiselectDropdownItems.vue';
export default { export default {
components: { components: {

View File

@ -27,9 +27,9 @@
<script> <script>
import { mapGetters } from 'vuex'; import { mapGetters } from 'vuex';
import ChatList from '../../../components/ChatList'; import ChatList from '../../../components/ChatList.vue';
import ConversationBox from '../../../components/widgets/conversation/ConversationBox'; import ConversationBox from '../../../components/widgets/conversation/ConversationBox.vue';
import PopOverSearch from './search/PopOverSearch'; import PopOverSearch from './search/PopOverSearch.vue';
import uiSettingsMixin from 'dashboard/mixins/uiSettings'; import uiSettingsMixin from 'dashboard/mixins/uiSettings';
import { BUS_EVENTS } from 'shared/constants/busEvents'; import { BUS_EVENTS } from 'shared/constants/busEvents';
import wootConstants from 'dashboard/constants/globals'; import wootConstants from 'dashboard/constants/globals';

View File

@ -34,7 +34,7 @@
</template> </template>
<script> <script>
import { mapGetters } from 'vuex'; import { mapGetters } from 'vuex';
import MacroItem from './MacroItem'; import MacroItem from './MacroItem.vue';
import accountMixin from 'dashboard/mixins/account.js'; import accountMixin from 'dashboard/mixins/account.js';
export default { export default {

View File

@ -36,7 +36,7 @@
<script> <script>
import alertMixin from 'shared/mixins/alertMixin'; import alertMixin from 'shared/mixins/alertMixin';
import { mixin as clickaway } from 'vue-clickaway'; import { mixin as clickaway } from 'vue-clickaway';
import MacroPreview from './MacroPreview'; import MacroPreview from './MacroPreview.vue';
import { CONVERSATION_EVENTS } from '../../../../helper/AnalyticsHelper/events'; import { CONVERSATION_EVENTS } from '../../../../helper/AnalyticsHelper/events';
export default { export default {

View File

@ -166,13 +166,13 @@
<script> <script>
import { mixin as clickaway } from 'vue-clickaway'; import { mixin as clickaway } from 'vue-clickaway';
import timeMixin from 'dashboard/mixins/time'; import timeMixin from 'dashboard/mixins/time';
import ContactInfoRow from './ContactInfoRow'; import ContactInfoRow from './ContactInfoRow.vue';
import Thumbnail from 'dashboard/components/widgets/Thumbnail.vue'; import Thumbnail from 'dashboard/components/widgets/Thumbnail.vue';
import SocialIcons from './SocialIcons'; import SocialIcons from './SocialIcons.vue';
import EditContact from './EditContact'; import EditContact from './EditContact.vue';
import NewConversation from './NewConversation'; import NewConversation from './NewConversation.vue';
import ContactMergeModal from 'dashboard/modules/contact/ContactMergeModal'; import ContactMergeModal from 'dashboard/modules/contact/ContactMergeModal.vue';
import alertMixin from 'shared/mixins/alertMixin'; import alertMixin from 'shared/mixins/alertMixin';
import adminMixin from '../../../../mixins/isAdmin'; import adminMixin from '../../../../mixins/isAdmin';
import { mapGetters } from 'vuex'; import { mapGetters } from 'vuex';

View File

@ -58,7 +58,7 @@
</template> </template>
<script> <script>
import alertMixin from 'shared/mixins/alertMixin'; import alertMixin from 'shared/mixins/alertMixin';
import EmojiOrIcon from 'shared/components/EmojiOrIcon'; import EmojiOrIcon from 'shared/components/EmojiOrIcon.vue';
import { copyTextToClipboard } from 'shared/helpers/clipboard'; import { copyTextToClipboard } from 'shared/helpers/clipboard';
export default { export default {

View File

@ -158,11 +158,11 @@
<script> <script>
import { mapGetters } from 'vuex'; import { mapGetters } from 'vuex';
import Thumbnail from 'dashboard/components/widgets/Thumbnail'; import Thumbnail from 'dashboard/components/widgets/Thumbnail.vue';
import WootMessageEditor from 'dashboard/components/widgets/WootWriter/Editor'; import WootMessageEditor from 'dashboard/components/widgets/WootWriter/Editor.vue';
import ReplyEmailHead from 'dashboard/components/widgets/conversation/ReplyEmailHead'; import ReplyEmailHead from 'dashboard/components/widgets/conversation/ReplyEmailHead.vue';
import CannedResponse from 'dashboard/components/widgets/conversation/CannedResponse.vue'; import CannedResponse from 'dashboard/components/widgets/conversation/CannedResponse.vue';
import InboxDropdownItem from 'dashboard/components/widgets/InboxDropdownItem'; import InboxDropdownItem from 'dashboard/components/widgets/InboxDropdownItem.vue';
import WhatsappTemplates from './WhatsappTemplates.vue'; import WhatsappTemplates from './WhatsappTemplates.vue';
import alertMixin from 'shared/mixins/alertMixin'; import alertMixin from 'shared/mixins/alertMixin';
import { INBOX_TYPES } from 'shared/mixins/inboxMixin'; import { INBOX_TYPES } from 'shared/mixins/inboxMixin';
@ -393,8 +393,6 @@ export default {
.mention--box { .mention--box {
@apply left-0 m-auto right-0 top-auto h-fit; @apply left-0 m-auto right-0 top-auto h-fit;
} }
/* TODO: Remove when have standardized a component out of multiselect */
.multiselect .multiselect__content .multiselect__option span { .multiselect .multiselect__content .multiselect__option span {
@apply inline-flex w-6 text-slate-600 dark:text-slate-400; @apply inline-flex w-6 text-slate-600 dark:text-slate-400;
} }

View File

@ -17,7 +17,7 @@
<script> <script>
import { mapGetters } from 'vuex'; import { mapGetters } from 'vuex';
import ContactForm from './ContactForm'; import ContactForm from './ContactForm.vue';
export default { export default {
components: { components: {

View File

@ -20,7 +20,7 @@
<script> <script>
import { mapGetters } from 'vuex'; import { mapGetters } from 'vuex';
import ContactForm from './ContactForm'; import ContactForm from './ContactForm.vue';
export default { export default {
components: { components: {

View File

@ -16,7 +16,7 @@
</template> </template>
<script> <script>
import ConversationForm from './ConversationForm'; import ConversationForm from './ConversationForm.vue';
export default { export default {
components: { components: {

View File

@ -44,9 +44,9 @@
<script> <script>
import { mapGetters } from 'vuex'; import { mapGetters } from 'vuex';
import Spinner from 'shared/components/Spinner'; import Spinner from 'shared/components/Spinner.vue';
import LabelDropdown from 'shared/components/ui/label/LabelDropdown'; import LabelDropdown from 'shared/components/ui/label/LabelDropdown.vue';
import AddLabel from 'shared/components/ui/dropdown/AddLabel'; import AddLabel from 'shared/components/ui/dropdown/AddLabel.vue';
import { mixin as clickaway } from 'vue-clickaway'; import { mixin as clickaway } from 'vue-clickaway';
import adminMixin from 'dashboard/mixins/isAdmin'; import adminMixin from 'dashboard/mixins/isAdmin';
import eventListenerMixins from 'shared/mixins/eventListenerMixins'; import eventListenerMixins from 'shared/mixins/eventListenerMixins';

Some files were not shown because too many files have changed in this diff Show More