Merge branch 'develop' into chore/conversation-participants
This commit is contained in:
commit
e62bb86a40
11 changed files with 139 additions and 23 deletions
|
@ -21,6 +21,7 @@ class Api::V1::Accounts::PortalsController < Api::V1::Accounts::BaseController
|
|||
|
||||
def create
|
||||
@portal = Current.account.portals.build(portal_params)
|
||||
@portal.custom_domain = parsed_custom_domain
|
||||
@portal.save!
|
||||
process_attached_logo
|
||||
end
|
||||
|
@ -28,6 +29,7 @@ class Api::V1::Accounts::PortalsController < Api::V1::Accounts::BaseController
|
|||
def update
|
||||
ActiveRecord::Base.transaction do
|
||||
@portal.update!(portal_params) if params[:portal].present?
|
||||
# @portal.custom_domain = parsed_custom_domain
|
||||
process_attached_logo
|
||||
rescue StandardError => e
|
||||
Rails.logger.error e
|
||||
|
@ -73,4 +75,9 @@ class Api::V1::Accounts::PortalsController < Api::V1::Accounts::BaseController
|
|||
def set_current_page
|
||||
@current_page = params[:page] || 1
|
||||
end
|
||||
|
||||
def parsed_custom_domain
|
||||
domain = URI.parse(@portal.custom_domain)
|
||||
domain.is_a?(URI::HTTP) ? domain.host : @portal.custom_domain
|
||||
end
|
||||
end
|
||||
|
|
|
@ -187,6 +187,10 @@ import {
|
|||
hasPressedAltAndKKey,
|
||||
} from 'shared/helpers/KeyboardHelpers';
|
||||
import { conversationListPageURL } from '../helper/URLHelper';
|
||||
import {
|
||||
isOnMentionsView,
|
||||
isOnUnattendedView,
|
||||
} from '../store/modules/conversations/helpers/actionHelpers';
|
||||
|
||||
export default {
|
||||
components: {
|
||||
|
@ -652,10 +656,16 @@ export default {
|
|||
params: { accountId, inbox_id: inboxId, label, teamId },
|
||||
name,
|
||||
} = this.$route;
|
||||
let conversationType = '';
|
||||
if (isOnMentionsView({ route: { name } })) {
|
||||
conversationType = 'mention';
|
||||
} else if (isOnUnattendedView({ route: { name } })) {
|
||||
conversationType = 'unattended';
|
||||
}
|
||||
this.$router.push(
|
||||
conversationListPageURL({
|
||||
accountId,
|
||||
conversationType: name === 'conversation_mentions' ? 'mention' : '',
|
||||
conversationType: conversationType,
|
||||
customViewId: this.foldersId,
|
||||
inboxId,
|
||||
label,
|
||||
|
|
|
@ -87,6 +87,10 @@ import {
|
|||
} from 'dashboard/helper/inbox';
|
||||
|
||||
import SecondaryChildNavItem from './SecondaryChildNavItem';
|
||||
import {
|
||||
isOnMentionsView,
|
||||
isOnUnattendedView,
|
||||
} from '../../../store/modules/conversations/helpers/actionHelpers';
|
||||
|
||||
export default {
|
||||
components: { SecondaryChildNavItem },
|
||||
|
@ -115,19 +119,31 @@ export default {
|
|||
this.menuItem.featureFlag
|
||||
);
|
||||
},
|
||||
isInboxConversation() {
|
||||
isAllConversations() {
|
||||
return (
|
||||
this.$store.state.route.name === 'inbox_conversation' &&
|
||||
this.menuItem.toStateName === 'home'
|
||||
);
|
||||
},
|
||||
isMentions() {
|
||||
return (
|
||||
isOnMentionsView({ route: this.$route }) &&
|
||||
this.menuItem.toStateName === 'conversation_mentions'
|
||||
);
|
||||
},
|
||||
isUnattended() {
|
||||
return (
|
||||
isOnUnattendedView({ route: this.$route }) &&
|
||||
this.menuItem.toStateName === 'conversation_unattended'
|
||||
);
|
||||
},
|
||||
isTeamsSettings() {
|
||||
return (
|
||||
this.$store.state.route.name === 'settings_teams_edit' &&
|
||||
this.menuItem.toStateName === 'settings_teams_list'
|
||||
);
|
||||
},
|
||||
isInboxsSettings() {
|
||||
isInboxSettings() {
|
||||
return (
|
||||
this.$store.state.route.name === 'settings_inbox_show' &&
|
||||
this.menuItem.toStateName === 'settings_inbox_list'
|
||||
|
@ -150,14 +166,20 @@ export default {
|
|||
},
|
||||
|
||||
computedClass() {
|
||||
// If active Inbox is present
|
||||
// donot highlight conversations
|
||||
// If active inbox is present, do not highlight conversations
|
||||
if (this.activeInbox) return ' ';
|
||||
if (
|
||||
this.isAllConversations ||
|
||||
this.isMentions ||
|
||||
this.isUnattended ||
|
||||
this.isCurrentRoute
|
||||
) {
|
||||
return 'is-active';
|
||||
}
|
||||
if (this.hasSubMenu) {
|
||||
if (
|
||||
this.isInboxConversation ||
|
||||
this.isTeamsSettings ||
|
||||
this.isInboxsSettings ||
|
||||
this.isInboxSettings ||
|
||||
this.isIntegrationsSettings ||
|
||||
this.isApplicationsSettings
|
||||
) {
|
||||
|
@ -166,10 +188,6 @@ export default {
|
|||
return ' ';
|
||||
}
|
||||
|
||||
if (this.isCurrentRoute) {
|
||||
return 'is-active';
|
||||
}
|
||||
|
||||
return '';
|
||||
},
|
||||
},
|
||||
|
|
|
@ -23,6 +23,7 @@ import 'videojs-wavesurfer/dist/videojs.wavesurfer.js';
|
|||
import 'videojs-record/dist/videojs.record.js';
|
||||
import 'videojs-record/dist/plugins/videojs.record.opus-recorder.js';
|
||||
import { format, addSeconds } from 'date-fns';
|
||||
import { AUDIO_FORMATS } from 'shared/constants/messages';
|
||||
|
||||
WaveSurfer.microphone = MicrophonePlugin;
|
||||
|
||||
|
@ -70,13 +71,26 @@ export default {
|
|||
record: {
|
||||
audio: true,
|
||||
video: false,
|
||||
displayMilliseconds: false,
|
||||
maxLength: 300,
|
||||
audioEngine: 'opus-recorder',
|
||||
audioWorkerURL: encoderWorker,
|
||||
audioChannels: 1,
|
||||
audioSampleRate: 48000,
|
||||
audioBitRate: 128,
|
||||
...(this.audioRecordFormat === AUDIO_FORMATS.WEBM && {
|
||||
monitorGain: 0,
|
||||
recordingGain: 1,
|
||||
numberOfChannels: 1,
|
||||
encoderSampleRate: 16000,
|
||||
originalSampleRateOverride: 16000,
|
||||
streamPages: true,
|
||||
maxFramesPerPage: 1,
|
||||
encoderFrameSize: 1,
|
||||
encoderPath: 'opus-recorder/dist/waveWorker.min.js',
|
||||
}),
|
||||
...(this.audioRecordFormat === AUDIO_FORMATS.OGG && {
|
||||
displayMilliseconds: false,
|
||||
maxLength: 300,
|
||||
audioEngine: 'opus-recorder',
|
||||
audioWorkerURL: encoderWorker,
|
||||
audioChannels: 1,
|
||||
audioSampleRate: 48000,
|
||||
audioBitRate: 128,
|
||||
}),
|
||||
},
|
||||
},
|
||||
},
|
||||
|
@ -86,6 +100,12 @@ export default {
|
|||
isRecording() {
|
||||
return this.player && this.player.record().isRecording();
|
||||
},
|
||||
audioRecordFormat() {
|
||||
if (this.isAWebWidgetInbox) {
|
||||
return AUDIO_FORMATS.WEBM;
|
||||
}
|
||||
return AUDIO_FORMATS.OGG;
|
||||
},
|
||||
},
|
||||
mounted() {
|
||||
window.Recorder = Recorder;
|
||||
|
|
|
@ -65,6 +65,7 @@ export default {
|
|||
placeholder: { type: String, default: '' },
|
||||
isPrivate: { type: Boolean, default: false },
|
||||
enableSuggestions: { type: Boolean, default: true },
|
||||
updateSelectionWith: { type: String, default: '' },
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
|
@ -162,6 +163,25 @@ export default {
|
|||
isPrivate() {
|
||||
this.reloadState();
|
||||
},
|
||||
|
||||
updateSelectionWith(newValue, oldValue) {
|
||||
if (!this.editorView) {
|
||||
return null;
|
||||
}
|
||||
if (newValue !== oldValue) {
|
||||
if (this.updateSelectionWith !== '') {
|
||||
const node = this.editorView.state.schema.text(
|
||||
this.updateSelectionWith
|
||||
);
|
||||
const tr = this.editorView.state.tr.replaceSelectionWith(node);
|
||||
this.editorView.focus();
|
||||
this.state = this.editorView.state.apply(tr);
|
||||
this.emitOnChange();
|
||||
this.$emit('clear-selection');
|
||||
}
|
||||
}
|
||||
return null;
|
||||
},
|
||||
},
|
||||
created() {
|
||||
this.state = createState(this.value, this.placeholder, this.plugins);
|
||||
|
|
|
@ -232,11 +232,18 @@ export default {
|
|||
return this.showFileUpload || this.isNote;
|
||||
},
|
||||
showAudioRecorderButton() {
|
||||
// Disable audio recorder for safari browser as recording is not supported
|
||||
const isSafari = /^((?!chrome|android|crios|fxios).)*safari/i.test(
|
||||
navigator.userAgent
|
||||
);
|
||||
|
||||
return (
|
||||
this.isFeatureEnabledonAccount(
|
||||
this.accountId,
|
||||
FEATURE_FLAGS.VOICE_RECORDER
|
||||
) && this.showAudioRecorder
|
||||
) &&
|
||||
this.showAudioRecorder &&
|
||||
!isSafari
|
||||
);
|
||||
},
|
||||
showAudioPlayStopButton() {
|
||||
|
|
|
@ -60,6 +60,7 @@
|
|||
class="input"
|
||||
:is-private="isOnPrivateNote"
|
||||
:placeholder="messagePlaceHolder"
|
||||
:update-selection-with="updateEditorSelectionWith"
|
||||
:min-height="4"
|
||||
@typing-off="onTypingOff"
|
||||
@typing-on="onTypingOn"
|
||||
|
@ -67,6 +68,7 @@
|
|||
@blur="onBlur"
|
||||
@toggle-user-mention="toggleUserMention"
|
||||
@toggle-canned-menu="toggleCannedMenu"
|
||||
@clear-selection="clearEditorSelection"
|
||||
/>
|
||||
</div>
|
||||
<div v-if="hasAttachments" class="attachment-preview-box" @paste="onPaste">
|
||||
|
@ -215,6 +217,7 @@ export default {
|
|||
ccEmails: '',
|
||||
doAutoSaveDraft: () => {},
|
||||
showWhatsAppTemplatesModal: false,
|
||||
updateEditorSelectionWith: '',
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
|
@ -707,8 +710,26 @@ export default {
|
|||
}
|
||||
this.$nextTick(() => this.$refs.messageInput.focus());
|
||||
},
|
||||
clearEditorSelection() {
|
||||
this.updateEditorSelectionWith = '';
|
||||
},
|
||||
insertEmoji(emoji, selectionStart, selectionEnd) {
|
||||
const { message } = this;
|
||||
const newMessage =
|
||||
message.slice(0, selectionStart) +
|
||||
emoji +
|
||||
message.slice(selectionEnd, message.length);
|
||||
this.message = newMessage;
|
||||
},
|
||||
emojiOnClick(emoji) {
|
||||
this.message = `${this.message}${emoji} `;
|
||||
if (this.showRichContentEditor) {
|
||||
this.updateEditorSelectionWith = emoji;
|
||||
this.onFocus();
|
||||
}
|
||||
if (!this.showRichContentEditor) {
|
||||
const { selectionStart, selectionEnd } = this.$refs.messageInput.$el;
|
||||
this.insertEmoji(emoji, selectionStart, selectionEnd);
|
||||
}
|
||||
},
|
||||
clearMessage() {
|
||||
this.message = '';
|
||||
|
|
|
@ -77,12 +77,16 @@ export const conversationListPageURL = ({
|
|||
url = `accounts/${accountId}/label/${label}`;
|
||||
} else if (teamId) {
|
||||
url = `accounts/${accountId}/team/${teamId}`;
|
||||
} else if (conversationType === 'mention') {
|
||||
url = `accounts/${accountId}/mentions/conversations`;
|
||||
} else if (inboxId) {
|
||||
url = `accounts/${accountId}/inbox/${inboxId}`;
|
||||
} else if (customViewId) {
|
||||
url = `accounts/${accountId}/custom_view/${customViewId}`;
|
||||
} else if (conversationType) {
|
||||
const urlMap = {
|
||||
mention: 'mentions/conversations',
|
||||
unattended: 'unattended/conversations',
|
||||
};
|
||||
url = `accounts/${accountId}/${urlMap[conversationType]}`;
|
||||
}
|
||||
return frontendURL(url);
|
||||
};
|
||||
|
|
|
@ -99,6 +99,8 @@ const MUTE_ACTION = {
|
|||
export const isAConversationRoute = routeName =>
|
||||
[
|
||||
'inbox_conversation',
|
||||
'conversation_through_mentions',
|
||||
'conversation_through_unattended',
|
||||
'conversation_through_inbox',
|
||||
'conversations_through_label',
|
||||
'conversations_through_team',
|
||||
|
|
|
@ -72,3 +72,8 @@ export const CSAT_RATINGS = [
|
|||
color: '#44CE4B',
|
||||
},
|
||||
];
|
||||
|
||||
export const AUDIO_FORMATS = {
|
||||
WEBM: 'audio/webm',
|
||||
OGG: 'audio/ogg',
|
||||
};
|
||||
|
|
|
@ -91,7 +91,8 @@ RSpec.describe 'Api::V1::Accounts::Portals', type: :request do
|
|||
portal_params = {
|
||||
portal: {
|
||||
name: 'test_portal',
|
||||
slug: 'test_kbase'
|
||||
slug: 'test_kbase',
|
||||
custom_domain: 'https://support.chatwoot.dev'
|
||||
},
|
||||
logo: file
|
||||
}
|
||||
|
@ -103,6 +104,7 @@ RSpec.describe 'Api::V1::Accounts::Portals', type: :request do
|
|||
json_response = JSON.parse(response.body)
|
||||
expect(json_response['name']).to eql('test_portal')
|
||||
expect(json_response['logo']['filename']).to eql('avatar.png')
|
||||
expect(json_response['custom_domain']).to eql('support.chatwoot.dev')
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
Loading…
Reference in a new issue