mirror of
https://github.com/lingble/chatwoot.git
synced 2025-11-03 04:27:53 +00:00
feat: Rewrite uiSettings mixin to a composable (#9819)
This commit is contained in:
@@ -116,6 +116,7 @@
|
|||||||
|
|
||||||
<script>
|
<script>
|
||||||
import { mapGetters } from 'vuex';
|
import { mapGetters } from 'vuex';
|
||||||
|
import { useUISettings } from 'dashboard/composables/useUISettings';
|
||||||
import { useAlert } from 'dashboard/composables';
|
import { useAlert } from 'dashboard/composables';
|
||||||
import VirtualList from 'vue-virtual-scroll-list';
|
import VirtualList from 'vue-virtual-scroll-list';
|
||||||
|
|
||||||
@@ -132,7 +133,6 @@ import AddCustomViews from 'dashboard/routes/dashboard/customviews/AddCustomView
|
|||||||
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 filterMixin from 'shared/mixins/filterMixin';
|
import filterMixin from 'shared/mixins/filterMixin';
|
||||||
import uiSettingsMixin from 'dashboard/mixins/uiSettings';
|
|
||||||
import languages from 'dashboard/components/widgets/conversation/advancedFilterItems/languages';
|
import languages from 'dashboard/components/widgets/conversation/advancedFilterItems/languages';
|
||||||
import countries from 'shared/constants/countries';
|
import countries from 'shared/constants/countries';
|
||||||
import { generateValuesForEditCustomViews } from 'dashboard/helper/customViewsHelper';
|
import { generateValuesForEditCustomViews } from 'dashboard/helper/customViewsHelper';
|
||||||
@@ -157,12 +157,7 @@ export default {
|
|||||||
IntersectionObserver,
|
IntersectionObserver,
|
||||||
VirtualList,
|
VirtualList,
|
||||||
},
|
},
|
||||||
mixins: [
|
mixins: [conversationMixin, keyboardEventListenerMixins, filterMixin],
|
||||||
conversationMixin,
|
|
||||||
keyboardEventListenerMixins,
|
|
||||||
filterMixin,
|
|
||||||
uiSettingsMixin,
|
|
||||||
],
|
|
||||||
provide() {
|
provide() {
|
||||||
return {
|
return {
|
||||||
// Actions to be performed on virtual list item and context menu.
|
// Actions to be performed on virtual list item and context menu.
|
||||||
@@ -207,6 +202,13 @@ export default {
|
|||||||
type: Boolean,
|
type: Boolean,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
setup() {
|
||||||
|
const { uiSettings } = useUISettings();
|
||||||
|
|
||||||
|
return {
|
||||||
|
uiSettings,
|
||||||
|
};
|
||||||
|
},
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
activeAssigneeTab: wootConstants.ASSIGNEE_TYPE.ME,
|
activeAssigneeTab: wootConstants.ASSIGNEE_TYPE.ME,
|
||||||
|
|||||||
@@ -36,12 +36,12 @@
|
|||||||
<script>
|
<script>
|
||||||
import { mapGetters } from 'vuex';
|
import { mapGetters } from 'vuex';
|
||||||
import { useAdmin } from 'dashboard/composables/useAdmin';
|
import { useAdmin } from 'dashboard/composables/useAdmin';
|
||||||
|
import { useUISettings } from 'dashboard/composables/useUISettings';
|
||||||
import AICTAModal from './AICTAModal.vue';
|
import AICTAModal from './AICTAModal.vue';
|
||||||
import AIAssistanceModal from './AIAssistanceModal.vue';
|
import AIAssistanceModal from './AIAssistanceModal.vue';
|
||||||
import aiMixin from 'dashboard/mixins/aiMixin';
|
import aiMixin from 'dashboard/mixins/aiMixin';
|
||||||
import { CMD_AI_ASSIST } from 'dashboard/routes/dashboard/commands/commandBarBusEvents';
|
import { CMD_AI_ASSIST } from 'dashboard/routes/dashboard/commands/commandBarBusEvents';
|
||||||
import keyboardEventListenerMixins from 'shared/mixins/keyboardEventListenerMixins';
|
import keyboardEventListenerMixins from 'shared/mixins/keyboardEventListenerMixins';
|
||||||
import uiSettingsMixin from 'dashboard/mixins/uiSettings';
|
|
||||||
import AIAssistanceCTAButton from './AIAssistanceCTAButton.vue';
|
import AIAssistanceCTAButton from './AIAssistanceCTAButton.vue';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
@@ -50,10 +50,14 @@ export default {
|
|||||||
AICTAModal,
|
AICTAModal,
|
||||||
AIAssistanceCTAButton,
|
AIAssistanceCTAButton,
|
||||||
},
|
},
|
||||||
mixins: [aiMixin, keyboardEventListenerMixins, uiSettingsMixin],
|
mixins: [aiMixin, keyboardEventListenerMixins],
|
||||||
setup() {
|
setup() {
|
||||||
|
const { uiSettings, updateUISettings } = useUISettings();
|
||||||
const { isAdmin } = useAdmin();
|
const { isAdmin } = useAdmin();
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
uiSettings,
|
||||||
|
updateUISettings,
|
||||||
isAdmin,
|
isAdmin,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -1,14 +1,14 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="px-0 min-w-0 flex-1">
|
<div class="flex-1 min-w-0 px-0">
|
||||||
<woot-modal-header
|
<woot-modal-header
|
||||||
:header-title="$t('INTEGRATION_SETTINGS.OPEN_AI.CTA_MODAL.TITLE')"
|
:header-title="$t('INTEGRATION_SETTINGS.OPEN_AI.CTA_MODAL.TITLE')"
|
||||||
:header-content="$t('INTEGRATION_SETTINGS.OPEN_AI.CTA_MODAL.DESC')"
|
:header-content="$t('INTEGRATION_SETTINGS.OPEN_AI.CTA_MODAL.DESC')"
|
||||||
/>
|
/>
|
||||||
<form
|
<form
|
||||||
class="flex flex-wrap flex-col modal-content"
|
class="flex flex-col flex-wrap modal-content"
|
||||||
@submit.prevent="finishOpenAI"
|
@submit.prevent="finishOpenAI"
|
||||||
>
|
>
|
||||||
<div class="mt-2 w-full">
|
<div class="w-full mt-2">
|
||||||
<woot-input
|
<woot-input
|
||||||
v-model="value"
|
v-model="value"
|
||||||
type="text"
|
type="text"
|
||||||
@@ -19,7 +19,7 @@
|
|||||||
@blur="$v.value.$touch"
|
@blur="$v.value.$touch"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div class="flex flex-row justify-between gap-2 py-2 px-0 w-full">
|
<div class="flex flex-row justify-between w-full gap-2 px-0 py-2">
|
||||||
<woot-button variant="link" @click.prevent="openOpenAIDoc">
|
<woot-button variant="link" @click.prevent="openOpenAIDoc">
|
||||||
{{ $t('INTEGRATION_SETTINGS.OPEN_AI.CTA_MODAL.BUTTONS.NEED_HELP') }}
|
{{ $t('INTEGRATION_SETTINGS.OPEN_AI.CTA_MODAL.BUTTONS.NEED_HELP') }}
|
||||||
</woot-button>
|
</woot-button>
|
||||||
@@ -39,13 +39,20 @@
|
|||||||
<script>
|
<script>
|
||||||
import { required } from 'vuelidate/lib/validators';
|
import { required } from 'vuelidate/lib/validators';
|
||||||
import { mapGetters } from 'vuex';
|
import { mapGetters } from 'vuex';
|
||||||
import aiMixin from 'dashboard/mixins/aiMixin';
|
|
||||||
import { useAlert } from 'dashboard/composables';
|
import { useAlert } from 'dashboard/composables';
|
||||||
import uiSettingsMixin from 'dashboard/mixins/uiSettings';
|
import { useUISettings } from 'dashboard/composables/useUISettings';
|
||||||
|
import aiMixin from 'dashboard/mixins/aiMixin';
|
||||||
import { OPEN_AI_EVENTS } from 'dashboard/helper/AnalyticsHelper/events';
|
import { OPEN_AI_EVENTS } from 'dashboard/helper/AnalyticsHelper/events';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
mixins: [aiMixin, uiSettingsMixin],
|
mixins: [aiMixin],
|
||||||
|
setup() {
|
||||||
|
const { updateUISettings } = useUISettings();
|
||||||
|
|
||||||
|
return {
|
||||||
|
updateUISettings,
|
||||||
|
};
|
||||||
|
},
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
value: '',
|
value: '',
|
||||||
|
|||||||
@@ -80,8 +80,7 @@ import {
|
|||||||
hasPressedCommandAndEnter,
|
hasPressedCommandAndEnter,
|
||||||
} from 'shared/helpers/KeyboardHelpers';
|
} from 'shared/helpers/KeyboardHelpers';
|
||||||
import keyboardEventListenerMixins from 'shared/mixins/keyboardEventListenerMixins';
|
import keyboardEventListenerMixins from 'shared/mixins/keyboardEventListenerMixins';
|
||||||
import uiSettingsMixin from 'dashboard/mixins/uiSettings';
|
import { useUISettings } from 'dashboard/composables/useUISettings';
|
||||||
import { isEditorHotKeyEnabled } from 'dashboard/mixins/uiSettings';
|
|
||||||
import {
|
import {
|
||||||
replaceVariablesInMessage,
|
replaceVariablesInMessage,
|
||||||
createTypingIndicator,
|
createTypingIndicator,
|
||||||
@@ -119,7 +118,7 @@ const createState = (
|
|||||||
export default {
|
export default {
|
||||||
name: 'WootMessageEditor',
|
name: 'WootMessageEditor',
|
||||||
components: { TagAgents, CannedResponse, VariableList },
|
components: { TagAgents, CannedResponse, VariableList },
|
||||||
mixins: [keyboardEventListenerMixins, uiSettingsMixin],
|
mixins: [keyboardEventListenerMixins],
|
||||||
props: {
|
props: {
|
||||||
value: { type: String, default: '' },
|
value: { type: String, default: '' },
|
||||||
editorId: { type: String, default: '' },
|
editorId: { type: String, default: '' },
|
||||||
@@ -139,6 +138,19 @@ export default {
|
|||||||
channelType: { type: String, default: '' },
|
channelType: { type: String, default: '' },
|
||||||
showImageResizeToolbar: { type: Boolean, default: false }, // A kill switch to show or hide the image toolbar
|
showImageResizeToolbar: { type: Boolean, default: false }, // A kill switch to show or hide the image toolbar
|
||||||
},
|
},
|
||||||
|
setup() {
|
||||||
|
const {
|
||||||
|
uiSettings,
|
||||||
|
isEditorHotKeyEnabled,
|
||||||
|
fetchSignatureFlagFromUISettings,
|
||||||
|
} = useUISettings();
|
||||||
|
|
||||||
|
return {
|
||||||
|
uiSettings,
|
||||||
|
isEditorHotKeyEnabled,
|
||||||
|
fetchSignatureFlagFromUISettings,
|
||||||
|
};
|
||||||
|
},
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
typingIndicator: createTypingIndicator(
|
typingIndicator: createTypingIndicator(
|
||||||
@@ -278,7 +290,7 @@ export default {
|
|||||||
// this is considered the source of truth, we watch this property
|
// this is considered the source of truth, we watch this property
|
||||||
// on change, we toggle the signature in the editor
|
// on change, we toggle the signature in the editor
|
||||||
if (this.allowSignature && !this.isPrivate && this.channelType) {
|
if (this.allowSignature && !this.isPrivate && this.channelType) {
|
||||||
return this.fetchSignatureFlagFromUiSettings(this.channelType);
|
return this.fetchSignatureFlagFromUISettings(this.channelType);
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
@@ -521,10 +533,10 @@ export default {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
isEnterToSendEnabled() {
|
isEnterToSendEnabled() {
|
||||||
return isEditorHotKeyEnabled(this.uiSettings, 'enter');
|
return this.isEditorHotKeyEnabled('enter');
|
||||||
},
|
},
|
||||||
isCmdPlusEnterToSendEnabled() {
|
isCmdPlusEnterToSendEnabled() {
|
||||||
return isEditorHotKeyEnabled(this.uiSettings, 'cmd_enter');
|
return this.isEditorHotKeyEnabled('cmd_enter');
|
||||||
},
|
},
|
||||||
getKeyboardEvents() {
|
getKeyboardEvents() {
|
||||||
return {
|
return {
|
||||||
|
|||||||
@@ -25,8 +25,8 @@ import {
|
|||||||
} from '@chatwoot/prosemirror-schema';
|
} from '@chatwoot/prosemirror-schema';
|
||||||
import { checkFileSizeLimit } from 'shared/helpers/FileHelper';
|
import { checkFileSizeLimit } from 'shared/helpers/FileHelper';
|
||||||
import { useAlert } from 'dashboard/composables';
|
import { useAlert } from 'dashboard/composables';
|
||||||
|
import { useUISettings } from 'dashboard/composables/useUISettings';
|
||||||
import keyboardEventListenerMixins from 'shared/mixins/keyboardEventListenerMixins';
|
import keyboardEventListenerMixins from 'shared/mixins/keyboardEventListenerMixins';
|
||||||
import uiSettingsMixin from 'dashboard/mixins/uiSettings';
|
|
||||||
|
|
||||||
const MAXIMUM_FILE_UPLOAD_SIZE = 4; // in MB
|
const MAXIMUM_FILE_UPLOAD_SIZE = 4; // in MB
|
||||||
const createState = (
|
const createState = (
|
||||||
@@ -51,13 +51,21 @@ const createState = (
|
|||||||
};
|
};
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
mixins: [keyboardEventListenerMixins, uiSettingsMixin],
|
mixins: [keyboardEventListenerMixins],
|
||||||
props: {
|
props: {
|
||||||
value: { type: String, default: '' },
|
value: { type: String, default: '' },
|
||||||
editorId: { type: String, default: '' },
|
editorId: { type: String, default: '' },
|
||||||
placeholder: { type: String, default: '' },
|
placeholder: { type: String, default: '' },
|
||||||
enabledMenuOptions: { type: Array, default: () => [] },
|
enabledMenuOptions: { type: Array, default: () => [] },
|
||||||
},
|
},
|
||||||
|
setup() {
|
||||||
|
const { uiSettings, updateUISettings } = useUISettings();
|
||||||
|
|
||||||
|
return {
|
||||||
|
uiSettings,
|
||||||
|
updateUISettings,
|
||||||
|
};
|
||||||
|
},
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
editorView: null,
|
editorView: null,
|
||||||
|
|||||||
@@ -134,10 +134,10 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
|
import { useUISettings } from 'dashboard/composables/useUISettings';
|
||||||
import FileUpload from 'vue-upload-component';
|
import FileUpload from 'vue-upload-component';
|
||||||
import * as ActiveStorage from 'activestorage';
|
import * as ActiveStorage from 'activestorage';
|
||||||
import keyboardEventListenerMixins from 'shared/mixins/keyboardEventListenerMixins';
|
import keyboardEventListenerMixins from 'shared/mixins/keyboardEventListenerMixins';
|
||||||
import uiSettingsMixin from 'dashboard/mixins/uiSettings';
|
|
||||||
import inboxMixin from 'shared/mixins/inboxMixin';
|
import inboxMixin from 'shared/mixins/inboxMixin';
|
||||||
import { FEATURE_FLAGS } from 'dashboard/featureFlags';
|
import { FEATURE_FLAGS } from 'dashboard/featureFlags';
|
||||||
import {
|
import {
|
||||||
@@ -153,7 +153,7 @@ import { mapGetters } from 'vuex';
|
|||||||
export default {
|
export default {
|
||||||
name: 'ReplyBottomPanel',
|
name: 'ReplyBottomPanel',
|
||||||
components: { FileUpload, VideoCallButton, AIAssistanceButton },
|
components: { FileUpload, VideoCallButton, AIAssistanceButton },
|
||||||
mixins: [keyboardEventListenerMixins, uiSettingsMixin, inboxMixin],
|
mixins: [keyboardEventListenerMixins, inboxMixin],
|
||||||
props: {
|
props: {
|
||||||
mode: {
|
mode: {
|
||||||
type: String,
|
type: String,
|
||||||
@@ -248,6 +248,15 @@ export default {
|
|||||||
required: true,
|
required: true,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
setup() {
|
||||||
|
const { setSignatureFlagForInbox, fetchSignatureFlagFromUISettings } =
|
||||||
|
useUISettings();
|
||||||
|
|
||||||
|
return {
|
||||||
|
setSignatureFlagForInbox,
|
||||||
|
fetchSignatureFlagFromUISettings,
|
||||||
|
};
|
||||||
|
},
|
||||||
computed: {
|
computed: {
|
||||||
...mapGetters({
|
...mapGetters({
|
||||||
accountId: 'getCurrentAccountId',
|
accountId: 'getCurrentAccountId',
|
||||||
@@ -320,7 +329,7 @@ export default {
|
|||||||
},
|
},
|
||||||
sendWithSignature() {
|
sendWithSignature() {
|
||||||
// channelType is sourced from inboxMixin
|
// channelType is sourced from inboxMixin
|
||||||
return this.fetchSignatureFlagFromUiSettings(this.channelType);
|
return this.fetchSignatureFlagFromUISettings(this.channelType);
|
||||||
},
|
},
|
||||||
signatureToggleTooltip() {
|
signatureToggleTooltip() {
|
||||||
return this.sendWithSignature
|
return this.sendWithSignature
|
||||||
|
|||||||
@@ -12,10 +12,10 @@
|
|||||||
<div
|
<div
|
||||||
v-if="showActionsDropdown"
|
v-if="showActionsDropdown"
|
||||||
v-on-clickaway="closeDropdown"
|
v-on-clickaway="closeDropdown"
|
||||||
class="dropdown-pane dropdown-pane--open mt-1 right-0 basic-filter"
|
class="right-0 mt-1 dropdown-pane dropdown-pane--open basic-filter"
|
||||||
>
|
>
|
||||||
<div class="items-center flex justify-between last:mt-4">
|
<div class="flex items-center justify-between last:mt-4">
|
||||||
<span class="text-slate-800 dark:text-slate-100 text-xs font-medium">{{
|
<span class="text-xs font-medium text-slate-800 dark:text-slate-100">{{
|
||||||
$t('CHAT_LIST.CHAT_SORT.STATUS')
|
$t('CHAT_LIST.CHAT_SORT.STATUS')
|
||||||
}}</span>
|
}}</span>
|
||||||
<filter-item
|
<filter-item
|
||||||
@@ -26,8 +26,8 @@
|
|||||||
@onChangeFilter="onChangeFilter"
|
@onChangeFilter="onChangeFilter"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div class="items-center flex justify-between last:mt-4">
|
<div class="flex items-center justify-between last:mt-4">
|
||||||
<span class="text-slate-800 dark:text-slate-100 text-xs font-medium">{{
|
<span class="text-xs font-medium text-slate-800 dark:text-slate-100">{{
|
||||||
$t('CHAT_LIST.CHAT_SORT.ORDER_BY')
|
$t('CHAT_LIST.CHAT_SORT.ORDER_BY')
|
||||||
}}</span>
|
}}</span>
|
||||||
<filter-item
|
<filter-item
|
||||||
@@ -46,13 +46,19 @@
|
|||||||
import wootConstants from 'dashboard/constants/globals';
|
import wootConstants from 'dashboard/constants/globals';
|
||||||
import { mapGetters } from 'vuex';
|
import { mapGetters } from 'vuex';
|
||||||
import FilterItem from './FilterItem.vue';
|
import FilterItem from './FilterItem.vue';
|
||||||
import uiSettingsMixin from 'dashboard/mixins/uiSettings';
|
import { useUISettings } from 'dashboard/composables/useUISettings';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
components: {
|
components: {
|
||||||
FilterItem,
|
FilterItem,
|
||||||
},
|
},
|
||||||
mixins: [uiSettingsMixin],
|
setup() {
|
||||||
|
const { updateUISettings } = useUISettings();
|
||||||
|
|
||||||
|
return {
|
||||||
|
updateUISettings,
|
||||||
|
};
|
||||||
|
},
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
showActionsDropdown: false,
|
showActionsDropdown: false,
|
||||||
|
|||||||
@@ -154,6 +154,7 @@
|
|||||||
<script>
|
<script>
|
||||||
import { mapGetters } from 'vuex';
|
import { mapGetters } from 'vuex';
|
||||||
import { useAlert } from 'dashboard/composables';
|
import { useAlert } from 'dashboard/composables';
|
||||||
|
import { useUISettings } from 'dashboard/composables/useUISettings';
|
||||||
import keyboardEventListenerMixins from 'shared/mixins/keyboardEventListenerMixins';
|
import keyboardEventListenerMixins from 'shared/mixins/keyboardEventListenerMixins';
|
||||||
|
|
||||||
import CannedResponse from './CannedResponse.vue';
|
import CannedResponse from './CannedResponse.vue';
|
||||||
@@ -180,10 +181,8 @@ import {
|
|||||||
import WhatsappTemplates from './WhatsappTemplates/Modal.vue';
|
import WhatsappTemplates from './WhatsappTemplates/Modal.vue';
|
||||||
import { MESSAGE_MAX_LENGTH } from 'shared/helpers/MessageTypeHelper';
|
import { MESSAGE_MAX_LENGTH } from 'shared/helpers/MessageTypeHelper';
|
||||||
import inboxMixin, { INBOX_FEATURES } from 'shared/mixins/inboxMixin';
|
import inboxMixin, { INBOX_FEATURES } from 'shared/mixins/inboxMixin';
|
||||||
import uiSettingsMixin from 'dashboard/mixins/uiSettings';
|
|
||||||
import { trimContent, debounce } from '@chatwoot/utils';
|
import { trimContent, debounce } from '@chatwoot/utils';
|
||||||
import wootConstants from 'dashboard/constants/globals';
|
import wootConstants from 'dashboard/constants/globals';
|
||||||
import { isEditorHotKeyEnabled } from 'dashboard/mixins/uiSettings';
|
|
||||||
import { CONVERSATION_EVENTS } from '../../../helper/AnalyticsHelper/events';
|
import { CONVERSATION_EVENTS } from '../../../helper/AnalyticsHelper/events';
|
||||||
import rtlMixin from 'shared/mixins/rtlMixin';
|
import rtlMixin from 'shared/mixins/rtlMixin';
|
||||||
import fileUploadMixin from 'dashboard/mixins/fileUploadMixin';
|
import fileUploadMixin from 'dashboard/mixins/fileUploadMixin';
|
||||||
@@ -218,7 +217,6 @@ export default {
|
|||||||
},
|
},
|
||||||
mixins: [
|
mixins: [
|
||||||
inboxMixin,
|
inboxMixin,
|
||||||
uiSettingsMixin,
|
|
||||||
messageFormatterMixin,
|
messageFormatterMixin,
|
||||||
rtlMixin,
|
rtlMixin,
|
||||||
fileUploadMixin,
|
fileUploadMixin,
|
||||||
@@ -230,6 +228,21 @@ export default {
|
|||||||
default: false,
|
default: false,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
setup() {
|
||||||
|
const {
|
||||||
|
uiSettings,
|
||||||
|
updateUISettings,
|
||||||
|
isEditorHotKeyEnabled,
|
||||||
|
fetchSignatureFlagFromUISettings,
|
||||||
|
} = useUISettings();
|
||||||
|
|
||||||
|
return {
|
||||||
|
uiSettings,
|
||||||
|
updateUISettings,
|
||||||
|
isEditorHotKeyEnabled,
|
||||||
|
fetchSignatureFlagFromUISettings,
|
||||||
|
};
|
||||||
|
},
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
message: '',
|
message: '',
|
||||||
@@ -405,7 +418,7 @@ export default {
|
|||||||
if (this.isPrivate) {
|
if (this.isPrivate) {
|
||||||
sendMessageText = this.$t('CONVERSATION.REPLYBOX.CREATE');
|
sendMessageText = this.$t('CONVERSATION.REPLYBOX.CREATE');
|
||||||
}
|
}
|
||||||
const keyLabel = isEditorHotKeyEnabled(this.uiSettings, 'cmd_enter')
|
const keyLabel = this.isEditorHotKeyEnabled('cmd_enter')
|
||||||
? '(⌘ + ↵)'
|
? '(⌘ + ↵)'
|
||||||
: '(↵)';
|
: '(↵)';
|
||||||
return `${sendMessageText} ${keyLabel}`;
|
return `${sendMessageText} ${keyLabel}`;
|
||||||
@@ -478,7 +491,7 @@ export default {
|
|||||||
return !!this.signatureToApply;
|
return !!this.signatureToApply;
|
||||||
},
|
},
|
||||||
sendWithSignature() {
|
sendWithSignature() {
|
||||||
return this.fetchSignatureFlagFromUiSettings(this.channelType);
|
return this.fetchSignatureFlagFromUISettings(this.channelType);
|
||||||
},
|
},
|
||||||
editorMessageKey() {
|
editorMessageKey() {
|
||||||
const { editor_message_key: isEnabled } = this.uiSettings;
|
const { editor_message_key: isEnabled } = this.uiSettings;
|
||||||
@@ -747,7 +760,7 @@ export default {
|
|||||||
!this.showCannedMenu &&
|
!this.showCannedMenu &&
|
||||||
!this.showVariablesMenu &&
|
!this.showVariablesMenu &&
|
||||||
this.isFocused &&
|
this.isFocused &&
|
||||||
isEditorHotKeyEnabled(this.uiSettings, selectedKey)
|
this.isEditorHotKeyEnabled(selectedKey)
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
onPaste(e) {
|
onPaste(e) {
|
||||||
|
|||||||
138
app/javascript/dashboard/composables/spec/useUISettings.spec.js
Normal file
138
app/javascript/dashboard/composables/spec/useUISettings.spec.js
Normal file
@@ -0,0 +1,138 @@
|
|||||||
|
import { ref } from 'vue';
|
||||||
|
import {
|
||||||
|
useUISettings,
|
||||||
|
DEFAULT_CONVERSATION_SIDEBAR_ITEMS_ORDER,
|
||||||
|
DEFAULT_CONTACT_SIDEBAR_ITEMS_ORDER,
|
||||||
|
} from 'dashboard/composables/useUISettings';
|
||||||
|
|
||||||
|
// Mocking the store composables
|
||||||
|
const mockDispatch = vi.fn();
|
||||||
|
|
||||||
|
const getUISettingsMock = ref({
|
||||||
|
is_ct_labels_open: true,
|
||||||
|
conversation_sidebar_items_order: DEFAULT_CONVERSATION_SIDEBAR_ITEMS_ORDER,
|
||||||
|
contact_sidebar_items_order: DEFAULT_CONTACT_SIDEBAR_ITEMS_ORDER,
|
||||||
|
editor_message_key: 'enter',
|
||||||
|
});
|
||||||
|
|
||||||
|
vi.mock('dashboard/composables/store', () => ({
|
||||||
|
useStoreGetters: () => ({
|
||||||
|
getUISettings: getUISettingsMock,
|
||||||
|
}),
|
||||||
|
useStore: () => ({
|
||||||
|
dispatch: mockDispatch,
|
||||||
|
}),
|
||||||
|
}));
|
||||||
|
|
||||||
|
describe('useUISettings', () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
mockDispatch.mockClear();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('returns uiSettings', () => {
|
||||||
|
const { uiSettings } = useUISettings();
|
||||||
|
expect(uiSettings.value).toEqual({
|
||||||
|
is_ct_labels_open: true,
|
||||||
|
conversation_sidebar_items_order:
|
||||||
|
DEFAULT_CONVERSATION_SIDEBAR_ITEMS_ORDER,
|
||||||
|
contact_sidebar_items_order: DEFAULT_CONTACT_SIDEBAR_ITEMS_ORDER,
|
||||||
|
editor_message_key: 'enter',
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('updates UI settings correctly', () => {
|
||||||
|
const { updateUISettings } = useUISettings();
|
||||||
|
updateUISettings({ enter_to_send_enabled: true });
|
||||||
|
expect(mockDispatch).toHaveBeenCalledWith('updateUISettings', {
|
||||||
|
uiSettings: {
|
||||||
|
enter_to_send_enabled: true,
|
||||||
|
is_ct_labels_open: true,
|
||||||
|
conversation_sidebar_items_order:
|
||||||
|
DEFAULT_CONVERSATION_SIDEBAR_ITEMS_ORDER,
|
||||||
|
contact_sidebar_items_order: DEFAULT_CONTACT_SIDEBAR_ITEMS_ORDER,
|
||||||
|
editor_message_key: 'enter',
|
||||||
|
},
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('toggles sidebar UI state correctly', () => {
|
||||||
|
const { toggleSidebarUIState } = useUISettings();
|
||||||
|
toggleSidebarUIState('is_ct_labels_open');
|
||||||
|
expect(mockDispatch).toHaveBeenCalledWith('updateUISettings', {
|
||||||
|
uiSettings: {
|
||||||
|
is_ct_labels_open: false,
|
||||||
|
conversation_sidebar_items_order:
|
||||||
|
DEFAULT_CONVERSATION_SIDEBAR_ITEMS_ORDER,
|
||||||
|
contact_sidebar_items_order: DEFAULT_CONTACT_SIDEBAR_ITEMS_ORDER,
|
||||||
|
editor_message_key: 'enter',
|
||||||
|
},
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('returns correct conversation sidebar items order', () => {
|
||||||
|
const { conversationSidebarItemsOrder } = useUISettings();
|
||||||
|
expect(conversationSidebarItemsOrder.value).toEqual(
|
||||||
|
DEFAULT_CONVERSATION_SIDEBAR_ITEMS_ORDER
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('returns correct contact sidebar items order', () => {
|
||||||
|
const { contactSidebarItemsOrder } = useUISettings();
|
||||||
|
expect(contactSidebarItemsOrder.value).toEqual(
|
||||||
|
DEFAULT_CONTACT_SIDEBAR_ITEMS_ORDER
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('returns correct value for isContactSidebarItemOpen', () => {
|
||||||
|
const { isContactSidebarItemOpen } = useUISettings();
|
||||||
|
expect(isContactSidebarItemOpen('is_ct_labels_open')).toBe(true);
|
||||||
|
expect(isContactSidebarItemOpen('non_existent_key')).toBe(false);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('sets signature flag for inbox correctly', () => {
|
||||||
|
const { setSignatureFlagForInbox } = useUISettings();
|
||||||
|
setSignatureFlagForInbox('email', true);
|
||||||
|
expect(mockDispatch).toHaveBeenCalledWith('updateUISettings', {
|
||||||
|
uiSettings: {
|
||||||
|
is_ct_labels_open: true,
|
||||||
|
conversation_sidebar_items_order:
|
||||||
|
DEFAULT_CONVERSATION_SIDEBAR_ITEMS_ORDER,
|
||||||
|
contact_sidebar_items_order: DEFAULT_CONTACT_SIDEBAR_ITEMS_ORDER,
|
||||||
|
email_signature_enabled: true,
|
||||||
|
editor_message_key: 'enter',
|
||||||
|
},
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('fetches signature flag from UI settings correctly', () => {
|
||||||
|
const { fetchSignatureFlagFromUISettings } = useUISettings();
|
||||||
|
expect(fetchSignatureFlagFromUISettings('email')).toBe(undefined);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('returns correct value for isEditorHotKeyEnabled when editor_message_key is configured', () => {
|
||||||
|
getUISettingsMock.value.enter_to_send_enabled = false;
|
||||||
|
const { isEditorHotKeyEnabled } = useUISettings();
|
||||||
|
expect(isEditorHotKeyEnabled('enter')).toBe(true);
|
||||||
|
expect(isEditorHotKeyEnabled('cmd_enter')).toBe(false);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('returns correct value for isEditorHotKeyEnabled when editor_message_key is not configured', () => {
|
||||||
|
getUISettingsMock.value.editor_message_key = undefined;
|
||||||
|
const { isEditorHotKeyEnabled } = useUISettings();
|
||||||
|
expect(isEditorHotKeyEnabled('enter')).toBe(false);
|
||||||
|
expect(isEditorHotKeyEnabled('cmd_enter')).toBe(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('handles non-existent keys', () => {
|
||||||
|
const {
|
||||||
|
isContactSidebarItemOpen,
|
||||||
|
fetchSignatureFlagFromUISettings,
|
||||||
|
isEditorHotKeyEnabled,
|
||||||
|
} = useUISettings();
|
||||||
|
expect(isContactSidebarItemOpen('non_existent_key')).toBe(false);
|
||||||
|
expect(fetchSignatureFlagFromUISettings('non_existent_key')).toBe(
|
||||||
|
undefined
|
||||||
|
);
|
||||||
|
expect(isEditorHotKeyEnabled('non_existent_key')).toBe(false);
|
||||||
|
});
|
||||||
|
});
|
||||||
149
app/javascript/dashboard/composables/useUISettings.js
Normal file
149
app/javascript/dashboard/composables/useUISettings.js
Normal file
@@ -0,0 +1,149 @@
|
|||||||
|
import { computed } from 'vue';
|
||||||
|
import { useStore, useStoreGetters } from 'dashboard/composables/store';
|
||||||
|
|
||||||
|
export const DEFAULT_CONVERSATION_SIDEBAR_ITEMS_ORDER = Object.freeze([
|
||||||
|
{ name: 'conversation_actions' },
|
||||||
|
{ name: 'macros' },
|
||||||
|
{ name: 'conversation_info' },
|
||||||
|
{ name: 'contact_attributes' },
|
||||||
|
{ name: 'previous_conversation' },
|
||||||
|
{ name: 'conversation_participants' },
|
||||||
|
]);
|
||||||
|
|
||||||
|
export const DEFAULT_CONTACT_SIDEBAR_ITEMS_ORDER = Object.freeze([
|
||||||
|
{ name: 'contact_attributes' },
|
||||||
|
{ name: 'contact_labels' },
|
||||||
|
{ name: 'previous_conversation' },
|
||||||
|
]);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Slugifies the channel name.
|
||||||
|
* Replaces spaces, hyphens, and double colons with underscores.
|
||||||
|
* @param {string} name - The channel name to slugify.
|
||||||
|
* @returns {string} The slugified channel name.
|
||||||
|
*/
|
||||||
|
const slugifyChannel = name =>
|
||||||
|
name?.toLowerCase().replace(' ', '_').replace('-', '_').replace('::', '_');
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Computes the order of items in the conversation sidebar, using defaults if not present.
|
||||||
|
* @param {Object} uiSettings - Reactive UI settings object.
|
||||||
|
* @returns {Array} Ordered list of sidebar items.
|
||||||
|
*/
|
||||||
|
const useConversationSidebarItemsOrder = uiSettings => {
|
||||||
|
return computed(() => {
|
||||||
|
const { conversation_sidebar_items_order: itemsOrder } = uiSettings.value;
|
||||||
|
// If the sidebar order is not set, use the default order.
|
||||||
|
if (!itemsOrder) {
|
||||||
|
return DEFAULT_CONVERSATION_SIDEBAR_ITEMS_ORDER;
|
||||||
|
}
|
||||||
|
// Create a copy of itemsOrder to avoid mutating the original store object.
|
||||||
|
const itemsOrderCopy = [...itemsOrder];
|
||||||
|
// If the sidebar order doesn't have the new elements, then add them to the list.
|
||||||
|
DEFAULT_CONVERSATION_SIDEBAR_ITEMS_ORDER.forEach(item => {
|
||||||
|
if (!itemsOrderCopy.find(i => i.name === item.name)) {
|
||||||
|
itemsOrderCopy.push(item);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return itemsOrderCopy;
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Computes the order of items in the contact sidebar,using defaults if not present.
|
||||||
|
* @param {Object} uiSettings - Reactive UI settings object.
|
||||||
|
* @returns {Array} Ordered list of sidebar items.
|
||||||
|
*/
|
||||||
|
const useContactSidebarItemsOrder = uiSettings => {
|
||||||
|
return computed(() => {
|
||||||
|
const { contact_sidebar_items_order: itemsOrder } = uiSettings.value;
|
||||||
|
return itemsOrder || DEFAULT_CONTACT_SIDEBAR_ITEMS_ORDER;
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Toggles the open state of a sidebar item.
|
||||||
|
* @param {string} key - The key of the sidebar item to toggle.
|
||||||
|
* @param {Object} uiSettings - Reactive UI settings object.
|
||||||
|
* @param {Function} updateUISettings - Function to update UI settings.
|
||||||
|
*/
|
||||||
|
const toggleSidebarUIState = (key, uiSettings, updateUISettings) => {
|
||||||
|
updateUISettings({ [key]: !uiSettings.value[key] });
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the signature flag for a specific channel type in the inbox settings.
|
||||||
|
* @param {string} channelType - The type of the channel.
|
||||||
|
* @param {boolean} value - The value to set for the signature enabled flag.
|
||||||
|
* @param {Function} updateUISettings - Function to update UI settings.
|
||||||
|
*/
|
||||||
|
const setSignatureFlagForInbox = (channelType, value, updateUISettings) => {
|
||||||
|
if (!channelType) return;
|
||||||
|
|
||||||
|
const slugifiedChannel = slugifyChannel(channelType);
|
||||||
|
updateUISettings({ [`${slugifiedChannel}_signature_enabled`]: value });
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fetches the signature flag for a specific channel type from UI settings.
|
||||||
|
* @param {string} channelType - The type of the channel.
|
||||||
|
* @param {Object} uiSettings - Reactive UI settings object.
|
||||||
|
* @returns {boolean} The value of the signature enabled flag.
|
||||||
|
*/
|
||||||
|
const fetchSignatureFlagFromUISettings = (channelType, uiSettings) => {
|
||||||
|
if (!channelType) return false;
|
||||||
|
|
||||||
|
const slugifiedChannel = slugifyChannel(channelType);
|
||||||
|
return uiSettings.value[`${slugifiedChannel}_signature_enabled`];
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if a specific editor hotkey is enabled.
|
||||||
|
* @param {string} key - The key to check.
|
||||||
|
* @param {Object} uiSettings - Reactive UI settings object.
|
||||||
|
* @returns {boolean} True if the hotkey is enabled, otherwise false.
|
||||||
|
*/
|
||||||
|
const isEditorHotKeyEnabled = (key, uiSettings) => {
|
||||||
|
const {
|
||||||
|
editor_message_key: editorMessageKey,
|
||||||
|
enter_to_send_enabled: enterToSendEnabled,
|
||||||
|
} = uiSettings.value || {};
|
||||||
|
if (!editorMessageKey) {
|
||||||
|
return key === (enterToSendEnabled ? 'enter' : 'cmd_enter');
|
||||||
|
}
|
||||||
|
return editorMessageKey === key;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Main composable function for managing UI settings.
|
||||||
|
* @returns {Object} An object containing reactive properties and methods for UI settings management.
|
||||||
|
*/
|
||||||
|
export function useUISettings() {
|
||||||
|
const getters = useStoreGetters();
|
||||||
|
const store = useStore();
|
||||||
|
const uiSettings = computed(() => getters.getUISettings.value);
|
||||||
|
|
||||||
|
const updateUISettings = (settings = {}) => {
|
||||||
|
store.dispatch('updateUISettings', {
|
||||||
|
uiSettings: {
|
||||||
|
...uiSettings.value,
|
||||||
|
...settings,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
return {
|
||||||
|
uiSettings,
|
||||||
|
updateUISettings,
|
||||||
|
conversationSidebarItemsOrder: useConversationSidebarItemsOrder(uiSettings),
|
||||||
|
contactSidebarItemsOrder: useContactSidebarItemsOrder(uiSettings),
|
||||||
|
isContactSidebarItemOpen: key => !!uiSettings.value[key],
|
||||||
|
toggleSidebarUIState: key =>
|
||||||
|
toggleSidebarUIState(key, uiSettings, updateUISettings),
|
||||||
|
setSignatureFlagForInbox: (channelType, value) =>
|
||||||
|
setSignatureFlagForInbox(channelType, value, updateUISettings),
|
||||||
|
fetchSignatureFlagFromUISettings: channelType =>
|
||||||
|
fetchSignatureFlagFromUISettings(channelType, uiSettings),
|
||||||
|
isEditorHotKeyEnabled: key => isEditorHotKeyEnabled(key, uiSettings),
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -1,169 +0,0 @@
|
|||||||
import { shallowMount, createLocalVue } from '@vue/test-utils';
|
|
||||||
import uiSettingsMixin, {
|
|
||||||
DEFAULT_CONVERSATION_SIDEBAR_ITEMS_ORDER,
|
|
||||||
DEFAULT_CONTACT_SIDEBAR_ITEMS_ORDER,
|
|
||||||
isEditorHotKeyEnabled,
|
|
||||||
} from '../uiSettings';
|
|
||||||
import Vuex from 'vuex';
|
|
||||||
const localVue = createLocalVue();
|
|
||||||
localVue.use(Vuex);
|
|
||||||
|
|
||||||
describe('uiSettingsMixin', () => {
|
|
||||||
let getters;
|
|
||||||
let actions;
|
|
||||||
let store;
|
|
||||||
|
|
||||||
beforeEach(() => {
|
|
||||||
actions = { updateUISettings: vi.fn(), toggleSidebarUIState: vi.fn() };
|
|
||||||
getters = {
|
|
||||||
getUISettings: () => ({
|
|
||||||
enter_to_send_enabled: false,
|
|
||||||
is_ct_labels_open: true,
|
|
||||||
conversation_sidebar_items_order:
|
|
||||||
DEFAULT_CONVERSATION_SIDEBAR_ITEMS_ORDER,
|
|
||||||
contact_sidebar_items_order: DEFAULT_CONTACT_SIDEBAR_ITEMS_ORDER,
|
|
||||||
}),
|
|
||||||
};
|
|
||||||
store = new Vuex.Store({ actions, getters });
|
|
||||||
});
|
|
||||||
|
|
||||||
it('returns uiSettings', () => {
|
|
||||||
const Component = {
|
|
||||||
render() {},
|
|
||||||
title: 'TestComponent',
|
|
||||||
mixins: [uiSettingsMixin],
|
|
||||||
};
|
|
||||||
const wrapper = shallowMount(Component, { store, localVue });
|
|
||||||
expect(wrapper.vm.uiSettings).toEqual({
|
|
||||||
enter_to_send_enabled: false,
|
|
||||||
is_ct_labels_open: true,
|
|
||||||
conversation_sidebar_items_order:
|
|
||||||
DEFAULT_CONVERSATION_SIDEBAR_ITEMS_ORDER,
|
|
||||||
contact_sidebar_items_order: DEFAULT_CONTACT_SIDEBAR_ITEMS_ORDER,
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('#updateUISettings', () => {
|
|
||||||
it('dispatches store actions correctly', () => {
|
|
||||||
const Component = {
|
|
||||||
render() {},
|
|
||||||
title: 'TestComponent',
|
|
||||||
mixins: [uiSettingsMixin],
|
|
||||||
};
|
|
||||||
const wrapper = shallowMount(Component, { store, localVue });
|
|
||||||
wrapper.vm.updateUISettings({ enter_to_send_enabled: true });
|
|
||||||
expect(actions.updateUISettings).toHaveBeenCalledWith(
|
|
||||||
expect.anything(),
|
|
||||||
{
|
|
||||||
uiSettings: {
|
|
||||||
enter_to_send_enabled: true,
|
|
||||||
is_ct_labels_open: true,
|
|
||||||
conversation_sidebar_items_order:
|
|
||||||
DEFAULT_CONVERSATION_SIDEBAR_ITEMS_ORDER,
|
|
||||||
contact_sidebar_items_order: DEFAULT_CONTACT_SIDEBAR_ITEMS_ORDER,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
undefined
|
|
||||||
);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('#toggleSidebarUIState', () => {
|
|
||||||
it('dispatches store actions correctly', () => {
|
|
||||||
const Component = {
|
|
||||||
render() {},
|
|
||||||
title: 'TestComponent',
|
|
||||||
mixins: [uiSettingsMixin],
|
|
||||||
};
|
|
||||||
const wrapper = shallowMount(Component, { store, localVue });
|
|
||||||
wrapper.vm.toggleSidebarUIState('is_ct_labels_open');
|
|
||||||
expect(actions.updateUISettings).toHaveBeenCalledWith(
|
|
||||||
expect.anything(),
|
|
||||||
{
|
|
||||||
uiSettings: {
|
|
||||||
enter_to_send_enabled: false,
|
|
||||||
is_ct_labels_open: false,
|
|
||||||
conversation_sidebar_items_order:
|
|
||||||
DEFAULT_CONVERSATION_SIDEBAR_ITEMS_ORDER,
|
|
||||||
contact_sidebar_items_order: DEFAULT_CONTACT_SIDEBAR_ITEMS_ORDER,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
undefined
|
|
||||||
);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('#isContactSidebarItemOpen', () => {
|
|
||||||
it('returns correct values', () => {
|
|
||||||
const Component = {
|
|
||||||
render() {},
|
|
||||||
title: 'TestComponent',
|
|
||||||
mixins: [uiSettingsMixin],
|
|
||||||
};
|
|
||||||
const wrapper = shallowMount(Component, { store, localVue });
|
|
||||||
expect(wrapper.vm.isContactSidebarItemOpen('is_ct_labels_open')).toEqual(
|
|
||||||
true
|
|
||||||
);
|
|
||||||
expect(
|
|
||||||
wrapper.vm.isContactSidebarItemOpen('is_ct_prev_conv_open')
|
|
||||||
).toEqual(false);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('#conversationSidebarItemsOrder', () => {
|
|
||||||
it('returns correct values', () => {
|
|
||||||
const Component = {
|
|
||||||
render() {},
|
|
||||||
title: 'TestComponent',
|
|
||||||
mixins: [uiSettingsMixin],
|
|
||||||
};
|
|
||||||
const wrapper = shallowMount(Component, { store, localVue });
|
|
||||||
expect(wrapper.vm.conversationSidebarItemsOrder).toEqual([
|
|
||||||
{ name: 'conversation_actions' },
|
|
||||||
{ name: 'macros' },
|
|
||||||
{ name: 'conversation_info' },
|
|
||||||
{ name: 'contact_attributes' },
|
|
||||||
{ name: 'previous_conversation' },
|
|
||||||
{ name: 'conversation_participants' },
|
|
||||||
]);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
describe('#contactSidebarItemsOrder', () => {
|
|
||||||
it('returns correct values', () => {
|
|
||||||
const Component = {
|
|
||||||
render() {},
|
|
||||||
title: 'TestComponent',
|
|
||||||
mixins: [uiSettingsMixin],
|
|
||||||
};
|
|
||||||
const wrapper = shallowMount(Component, { store, localVue });
|
|
||||||
expect(wrapper.vm.contactSidebarItemsOrder).toEqual([
|
|
||||||
{ name: 'contact_attributes' },
|
|
||||||
{ name: 'contact_labels' },
|
|
||||||
{ name: 'previous_conversation' },
|
|
||||||
]);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('isEditorHotKeyEnabled', () => {
|
|
||||||
it('returns true if hot key is not configured and enter to send flag is true', () => {
|
|
||||||
expect(
|
|
||||||
isEditorHotKeyEnabled({ enter_to_send_enabled: true }, 'enter')
|
|
||||||
).toEqual(true);
|
|
||||||
expect(
|
|
||||||
isEditorHotKeyEnabled({ enter_to_send_enabled: true }, 'cmd_enter')
|
|
||||||
).toEqual(false);
|
|
||||||
|
|
||||||
expect(isEditorHotKeyEnabled({}, 'cmd_enter')).toEqual(true);
|
|
||||||
expect(isEditorHotKeyEnabled({}, 'enter')).toEqual(false);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('returns correct value if hot key is configured', () => {
|
|
||||||
expect(
|
|
||||||
isEditorHotKeyEnabled({ editor_message_key: 'enter' }, 'enter')
|
|
||||||
).toEqual(true);
|
|
||||||
expect(
|
|
||||||
isEditorHotKeyEnabled({ editor_message_key: 'cmd_enter' }, 'enter')
|
|
||||||
).toEqual(false);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
@@ -1,87 +0,0 @@
|
|||||||
import { mapGetters } from 'vuex';
|
|
||||||
|
|
||||||
export const DEFAULT_CONVERSATION_SIDEBAR_ITEMS_ORDER = [
|
|
||||||
{ name: 'conversation_actions' },
|
|
||||||
{ name: 'macros' },
|
|
||||||
{ name: 'conversation_info' },
|
|
||||||
{ name: 'contact_attributes' },
|
|
||||||
{ name: 'previous_conversation' },
|
|
||||||
{ name: 'conversation_participants' },
|
|
||||||
];
|
|
||||||
export const DEFAULT_CONTACT_SIDEBAR_ITEMS_ORDER = [
|
|
||||||
{ name: 'contact_attributes' },
|
|
||||||
{ name: 'contact_labels' },
|
|
||||||
{ name: 'previous_conversation' },
|
|
||||||
];
|
|
||||||
|
|
||||||
const slugifyChannel = name =>
|
|
||||||
name?.toLowerCase().replace(' ', '_').replace('-', '_').replace('::', '_');
|
|
||||||
|
|
||||||
export const isEditorHotKeyEnabled = (uiSettings, key) => {
|
|
||||||
const {
|
|
||||||
editor_message_key: editorMessageKey,
|
|
||||||
enter_to_send_enabled: enterToSendEnabled,
|
|
||||||
} = uiSettings || {};
|
|
||||||
if (!editorMessageKey) {
|
|
||||||
if (enterToSendEnabled) {
|
|
||||||
return key === 'enter';
|
|
||||||
}
|
|
||||||
return key === 'cmd_enter';
|
|
||||||
}
|
|
||||||
return editorMessageKey === key;
|
|
||||||
};
|
|
||||||
|
|
||||||
export default {
|
|
||||||
computed: {
|
|
||||||
...mapGetters({ uiSettings: 'getUISettings' }),
|
|
||||||
conversationSidebarItemsOrder() {
|
|
||||||
const { conversation_sidebar_items_order: itemsOrder } = this.uiSettings;
|
|
||||||
// If the sidebar order is not set, use the default order.
|
|
||||||
if (!itemsOrder) {
|
|
||||||
return DEFAULT_CONVERSATION_SIDEBAR_ITEMS_ORDER;
|
|
||||||
}
|
|
||||||
// If the sidebar order doesn't have the new elements, then add them to the list.
|
|
||||||
DEFAULT_CONVERSATION_SIDEBAR_ITEMS_ORDER.forEach(item => {
|
|
||||||
if (!itemsOrder.find(i => i.name === item.name)) {
|
|
||||||
itemsOrder.push(item);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
return itemsOrder;
|
|
||||||
},
|
|
||||||
contactSidebarItemsOrder() {
|
|
||||||
const { contact_sidebar_items_order: itemsOrder } = this.uiSettings;
|
|
||||||
return itemsOrder || DEFAULT_CONTACT_SIDEBAR_ITEMS_ORDER;
|
|
||||||
},
|
|
||||||
},
|
|
||||||
methods: {
|
|
||||||
updateUISettings(uiSettings = {}) {
|
|
||||||
this.$store.dispatch('updateUISettings', {
|
|
||||||
uiSettings: {
|
|
||||||
...this.uiSettings,
|
|
||||||
...uiSettings,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
},
|
|
||||||
isContactSidebarItemOpen(key) {
|
|
||||||
const { [key]: isOpen } = this.uiSettings;
|
|
||||||
return !!isOpen;
|
|
||||||
},
|
|
||||||
toggleSidebarUIState(key) {
|
|
||||||
this.updateUISettings({ [key]: !this.isContactSidebarItemOpen(key) });
|
|
||||||
},
|
|
||||||
setSignatureFlagForInbox(channelType, value) {
|
|
||||||
if (!channelType) return;
|
|
||||||
|
|
||||||
channelType = slugifyChannel(channelType);
|
|
||||||
this.updateUISettings({
|
|
||||||
[`${channelType}_signature_enabled`]: value,
|
|
||||||
});
|
|
||||||
},
|
|
||||||
fetchSignatureFlagFromUiSettings(channelType) {
|
|
||||||
if (!channelType) return false;
|
|
||||||
|
|
||||||
channelType = slugifyChannel(channelType);
|
|
||||||
return this.uiSettings[`${channelType}_signature_enabled`];
|
|
||||||
},
|
|
||||||
},
|
|
||||||
};
|
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
<template>
|
<template>
|
||||||
<div
|
<div
|
||||||
class="app-wrapper h-full flex-grow-0 min-h-0 w-full max-w-full ml-auto mr-auto flex flex-wrap dark:text-slate-300"
|
class="flex flex-wrap flex-grow-0 w-full h-full max-w-full min-h-0 ml-auto mr-auto app-wrapper dark:text-slate-300"
|
||||||
>
|
>
|
||||||
<sidebar
|
<sidebar
|
||||||
:route="currentRoute"
|
:route="currentRoute"
|
||||||
@@ -11,7 +11,7 @@
|
|||||||
@close-key-shortcut-modal="closeKeyShortcutModal"
|
@close-key-shortcut-modal="closeKeyShortcutModal"
|
||||||
@show-add-label-popup="showAddLabelPopup"
|
@show-add-label-popup="showAddLabelPopup"
|
||||||
/>
|
/>
|
||||||
<section class="flex h-full min-h-0 overflow-hidden flex-1 px-0">
|
<section class="flex flex-1 h-full min-h-0 px-0 overflow-hidden">
|
||||||
<router-view />
|
<router-view />
|
||||||
<command-bar />
|
<command-bar />
|
||||||
<account-selector
|
<account-selector
|
||||||
@@ -47,7 +47,7 @@ import AddAccountModal from 'dashboard/components/layout/sidebarComponents/AddAc
|
|||||||
import AccountSelector from 'dashboard/components/layout/sidebarComponents/AccountSelector.vue';
|
import AccountSelector from 'dashboard/components/layout/sidebarComponents/AccountSelector.vue';
|
||||||
import AddLabelModal from 'dashboard/routes/dashboard/settings/labels/AddLabel.vue';
|
import AddLabelModal from 'dashboard/routes/dashboard/settings/labels/AddLabel.vue';
|
||||||
import NotificationPanel from 'dashboard/routes/dashboard/notifications/components/NotificationPanel.vue';
|
import NotificationPanel from 'dashboard/routes/dashboard/notifications/components/NotificationPanel.vue';
|
||||||
import uiSettingsMixin from 'dashboard/mixins/uiSettings';
|
import { useUISettings } from 'dashboard/composables/useUISettings';
|
||||||
import wootConstants from 'dashboard/constants/globals';
|
import wootConstants from 'dashboard/constants/globals';
|
||||||
const CommandBar = () => import('./commands/commandbar.vue');
|
const CommandBar = () => import('./commands/commandbar.vue');
|
||||||
|
|
||||||
@@ -61,7 +61,14 @@ export default {
|
|||||||
AddLabelModal,
|
AddLabelModal,
|
||||||
NotificationPanel,
|
NotificationPanel,
|
||||||
},
|
},
|
||||||
mixins: [uiSettingsMixin],
|
setup() {
|
||||||
|
const { uiSettings, updateUISettings } = useUISettings();
|
||||||
|
|
||||||
|
return {
|
||||||
|
uiSettings,
|
||||||
|
updateUISettings,
|
||||||
|
};
|
||||||
|
},
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
showAccountModal: false,
|
showAccountModal: false,
|
||||||
|
|||||||
@@ -86,7 +86,7 @@ import ContactInfo from 'dashboard/routes/dashboard/conversation/contact/Contact
|
|||||||
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 draggable from 'vuedraggable';
|
import draggable from 'vuedraggable';
|
||||||
import uiSettingsMixin from 'dashboard/mixins/uiSettings';
|
import { useUISettings } from 'dashboard/composables/useUISettings';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
components: {
|
components: {
|
||||||
@@ -97,7 +97,6 @@ export default {
|
|||||||
CustomAttributes,
|
CustomAttributes,
|
||||||
draggable,
|
draggable,
|
||||||
},
|
},
|
||||||
mixins: [uiSettingsMixin],
|
|
||||||
props: {
|
props: {
|
||||||
contact: {
|
contact: {
|
||||||
type: Object,
|
type: Object,
|
||||||
@@ -116,6 +115,21 @@ export default {
|
|||||||
default: true,
|
default: true,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
setup() {
|
||||||
|
const {
|
||||||
|
updateUISettings,
|
||||||
|
isContactSidebarItemOpen,
|
||||||
|
contactSidebarItemsOrder,
|
||||||
|
toggleSidebarUIState,
|
||||||
|
} = useUISettings();
|
||||||
|
|
||||||
|
return {
|
||||||
|
updateUISettings,
|
||||||
|
isContactSidebarItemOpen,
|
||||||
|
contactSidebarItemsOrder,
|
||||||
|
toggleSidebarUIState,
|
||||||
|
};
|
||||||
|
},
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
dragEnabled: true,
|
dragEnabled: true,
|
||||||
|
|||||||
@@ -133,6 +133,7 @@
|
|||||||
|
|
||||||
<script>
|
<script>
|
||||||
import { mapGetters } from 'vuex';
|
import { mapGetters } from 'vuex';
|
||||||
|
import { useUISettings } from 'dashboard/composables/useUISettings';
|
||||||
import AccordionItem from 'dashboard/components/Accordion/AccordionItem.vue';
|
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';
|
||||||
@@ -142,7 +143,6 @@ import ContactInfo from './contact/ContactInfo.vue';
|
|||||||
import ConversationInfo from './ConversationInfo.vue';
|
import ConversationInfo from './ConversationInfo.vue';
|
||||||
import CustomAttributes from './customAttributes/CustomAttributes.vue';
|
import CustomAttributes from './customAttributes/CustomAttributes.vue';
|
||||||
import draggable from 'vuedraggable';
|
import draggable from 'vuedraggable';
|
||||||
import uiSettingsMixin from 'dashboard/mixins/uiSettings';
|
|
||||||
import MacrosList from './Macros/List.vue';
|
import MacrosList from './Macros/List.vue';
|
||||||
export default {
|
export default {
|
||||||
components: {
|
components: {
|
||||||
@@ -156,7 +156,6 @@ export default {
|
|||||||
draggable,
|
draggable,
|
||||||
MacrosList,
|
MacrosList,
|
||||||
},
|
},
|
||||||
mixins: [uiSettingsMixin],
|
|
||||||
props: {
|
props: {
|
||||||
conversationId: {
|
conversationId: {
|
||||||
type: [Number, String],
|
type: [Number, String],
|
||||||
@@ -171,6 +170,21 @@ export default {
|
|||||||
default: () => {},
|
default: () => {},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
setup() {
|
||||||
|
const {
|
||||||
|
updateUISettings,
|
||||||
|
isContactSidebarItemOpen,
|
||||||
|
conversationSidebarItemsOrder,
|
||||||
|
toggleSidebarUIState,
|
||||||
|
} = useUISettings();
|
||||||
|
|
||||||
|
return {
|
||||||
|
updateUISettings,
|
||||||
|
isContactSidebarItemOpen,
|
||||||
|
conversationSidebarItemsOrder,
|
||||||
|
toggleSidebarUIState,
|
||||||
|
};
|
||||||
|
},
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
dragEnabled: true,
|
dragEnabled: true,
|
||||||
|
|||||||
@@ -37,12 +37,12 @@
|
|||||||
<script>
|
<script>
|
||||||
import { mapGetters } from 'vuex';
|
import { mapGetters } from 'vuex';
|
||||||
import { useAlert } from 'dashboard/composables';
|
import { useAlert } from 'dashboard/composables';
|
||||||
|
import { useUISettings } from 'dashboard/composables/useUISettings';
|
||||||
import { getUnixTime } from 'date-fns';
|
import { getUnixTime } from 'date-fns';
|
||||||
import ChatList from '../../../components/ChatList.vue';
|
import ChatList from '../../../components/ChatList.vue';
|
||||||
import ConversationBox from '../../../components/widgets/conversation/ConversationBox.vue';
|
import ConversationBox from '../../../components/widgets/conversation/ConversationBox.vue';
|
||||||
import PopOverSearch from './search/PopOverSearch.vue';
|
import PopOverSearch from './search/PopOverSearch.vue';
|
||||||
import CustomSnoozeModal from 'dashboard/components/CustomSnoozeModal.vue';
|
import CustomSnoozeModal from 'dashboard/components/CustomSnoozeModal.vue';
|
||||||
import uiSettingsMixin from 'dashboard/mixins/uiSettings';
|
|
||||||
import wootConstants from 'dashboard/constants/globals';
|
import wootConstants from 'dashboard/constants/globals';
|
||||||
import { BUS_EVENTS } from 'shared/constants/busEvents';
|
import { BUS_EVENTS } from 'shared/constants/busEvents';
|
||||||
import { CMD_SNOOZE_CONVERSATION } from 'dashboard/routes/dashboard/commands/commandBarBusEvents';
|
import { CMD_SNOOZE_CONVERSATION } from 'dashboard/routes/dashboard/commands/commandBarBusEvents';
|
||||||
@@ -55,7 +55,6 @@ export default {
|
|||||||
PopOverSearch,
|
PopOverSearch,
|
||||||
CustomSnoozeModal,
|
CustomSnoozeModal,
|
||||||
},
|
},
|
||||||
mixins: [uiSettingsMixin],
|
|
||||||
props: {
|
props: {
|
||||||
inboxId: {
|
inboxId: {
|
||||||
type: [String, Number],
|
type: [String, Number],
|
||||||
@@ -82,6 +81,14 @@ export default {
|
|||||||
default: 0,
|
default: 0,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
setup() {
|
||||||
|
const { uiSettings, updateUISettings } = useUISettings();
|
||||||
|
|
||||||
|
return {
|
||||||
|
uiSettings,
|
||||||
|
updateUISettings,
|
||||||
|
};
|
||||||
|
},
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
showSearchModal: false,
|
showSearchModal: false,
|
||||||
|
|||||||
@@ -240,6 +240,7 @@
|
|||||||
<script>
|
<script>
|
||||||
import { mapGetters } from 'vuex';
|
import { mapGetters } from 'vuex';
|
||||||
import { useAlert } from 'dashboard/composables';
|
import { useAlert } from 'dashboard/composables';
|
||||||
|
import { useUISettings } from 'dashboard/composables/useUISettings';
|
||||||
import Thumbnail from 'dashboard/components/widgets/Thumbnail.vue';
|
import Thumbnail from 'dashboard/components/widgets/Thumbnail.vue';
|
||||||
import WootMessageEditor from 'dashboard/components/widgets/WootWriter/Editor.vue';
|
import WootMessageEditor from 'dashboard/components/widgets/WootWriter/Editor.vue';
|
||||||
import ReplyEmailHead from 'dashboard/components/widgets/conversation/ReplyEmailHead.vue';
|
import ReplyEmailHead from 'dashboard/components/widgets/conversation/ReplyEmailHead.vue';
|
||||||
@@ -260,7 +261,6 @@ import {
|
|||||||
appendSignature,
|
appendSignature,
|
||||||
removeSignature,
|
removeSignature,
|
||||||
} from 'dashboard/helper/editorHelper';
|
} from 'dashboard/helper/editorHelper';
|
||||||
import uiSettingsMixin from 'dashboard/mixins/uiSettings';
|
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
components: {
|
components: {
|
||||||
@@ -274,7 +274,7 @@ export default {
|
|||||||
AttachmentPreview,
|
AttachmentPreview,
|
||||||
MessageSignatureMissingAlert,
|
MessageSignatureMissingAlert,
|
||||||
},
|
},
|
||||||
mixins: [uiSettingsMixin, inboxMixin, fileUploadMixin],
|
mixins: [inboxMixin, fileUploadMixin],
|
||||||
props: {
|
props: {
|
||||||
contact: {
|
contact: {
|
||||||
type: Object,
|
type: Object,
|
||||||
@@ -289,6 +289,15 @@ export default {
|
|||||||
default: '',
|
default: '',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
setup() {
|
||||||
|
const { fetchSignatureFlagFromUISettings, setSignatureFlagForInbox } =
|
||||||
|
useUISettings();
|
||||||
|
|
||||||
|
return {
|
||||||
|
fetchSignatureFlagFromUISettings,
|
||||||
|
setSignatureFlagForInbox,
|
||||||
|
};
|
||||||
|
},
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
name: '',
|
name: '',
|
||||||
@@ -323,7 +332,7 @@ export default {
|
|||||||
messageSignature: 'getMessageSignature',
|
messageSignature: 'getMessageSignature',
|
||||||
}),
|
}),
|
||||||
sendWithSignature() {
|
sendWithSignature() {
|
||||||
return this.fetchSignatureFlagFromUiSettings(this.channelType);
|
return this.fetchSignatureFlagFromUISettings(this.channelType);
|
||||||
},
|
},
|
||||||
signatureToApply() {
|
signatureToApply() {
|
||||||
return this.messageSignature;
|
return this.messageSignature;
|
||||||
|
|||||||
@@ -41,17 +41,17 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import CustomAttribute from 'dashboard/components/CustomAttribute.vue';
|
|
||||||
import { useAlert } from 'dashboard/composables';
|
import { useAlert } from 'dashboard/composables';
|
||||||
import attributeMixin from 'dashboard/mixins/attributeMixin';
|
import { useUISettings } from 'dashboard/composables/useUISettings';
|
||||||
import uiSettingsMixin from 'dashboard/mixins/uiSettings';
|
|
||||||
import { copyTextToClipboard } from 'shared/helpers/clipboard';
|
import { copyTextToClipboard } from 'shared/helpers/clipboard';
|
||||||
|
import CustomAttribute from 'dashboard/components/CustomAttribute.vue';
|
||||||
|
import attributeMixin from 'dashboard/mixins/attributeMixin';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
components: {
|
components: {
|
||||||
CustomAttribute,
|
CustomAttribute,
|
||||||
},
|
},
|
||||||
mixins: [attributeMixin, uiSettingsMixin],
|
mixins: [attributeMixin],
|
||||||
props: {
|
props: {
|
||||||
attributeType: {
|
attributeType: {
|
||||||
type: String,
|
type: String,
|
||||||
@@ -71,6 +71,14 @@ export default {
|
|||||||
default: '',
|
default: '',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
setup() {
|
||||||
|
const { uiSettings, updateUISettings } = useUISettings();
|
||||||
|
|
||||||
|
return {
|
||||||
|
uiSettings,
|
||||||
|
updateUISettings,
|
||||||
|
};
|
||||||
|
},
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
showAllAttributes: false,
|
showAllAttributes: false,
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="app-wrapper flex h-full flex-grow-0 min-h-0 w-full">
|
<div class="flex flex-grow-0 w-full h-full min-h-0 app-wrapper">
|
||||||
<sidebar
|
<sidebar
|
||||||
:route="currentRoute"
|
:route="currentRoute"
|
||||||
@toggle-account-modal="toggleAccountModal"
|
@toggle-account-modal="toggleAccountModal"
|
||||||
@@ -20,7 +20,7 @@
|
|||||||
/>
|
/>
|
||||||
<section
|
<section
|
||||||
v-if="isHelpCenterEnabled"
|
v-if="isHelpCenterEnabled"
|
||||||
class="flex h-full min-h-0 overflow-hidden flex-1 px-0 bg-white dark:bg-slate-900"
|
class="flex flex-1 h-full min-h-0 px-0 overflow-hidden bg-white dark:bg-slate-900"
|
||||||
>
|
>
|
||||||
<router-view @reload-locale="fetchPortalAndItsCategories" />
|
<router-view @reload-locale="fetchPortalAndItsCategories" />
|
||||||
<command-bar />
|
<command-bar />
|
||||||
@@ -68,7 +68,7 @@ import HelpCenterSidebar from '../components/Sidebar/Sidebar.vue';
|
|||||||
import WootKeyShortcutModal from 'dashboard/components/widgets/modal/WootKeyShortcutModal.vue';
|
import WootKeyShortcutModal from 'dashboard/components/widgets/modal/WootKeyShortcutModal.vue';
|
||||||
import AccountSelector from 'dashboard/components/layout/sidebarComponents/AccountSelector.vue';
|
import AccountSelector from 'dashboard/components/layout/sidebarComponents/AccountSelector.vue';
|
||||||
import NotificationPanel from 'dashboard/routes/dashboard/notifications/components/NotificationPanel.vue';
|
import NotificationPanel from 'dashboard/routes/dashboard/notifications/components/NotificationPanel.vue';
|
||||||
import uiSettingsMixin from 'dashboard/mixins/uiSettings';
|
import { useUISettings } from 'dashboard/composables/useUISettings';
|
||||||
import portalMixin from '../mixins/portalMixin';
|
import portalMixin from '../mixins/portalMixin';
|
||||||
import AddCategory from '../pages/categories/AddCategory.vue';
|
import AddCategory from '../pages/categories/AddCategory.vue';
|
||||||
import { FEATURE_FLAGS } from 'dashboard/featureFlags';
|
import { FEATURE_FLAGS } from 'dashboard/featureFlags';
|
||||||
@@ -87,7 +87,15 @@ export default {
|
|||||||
UpgradePage,
|
UpgradePage,
|
||||||
WootKeyShortcutModal,
|
WootKeyShortcutModal,
|
||||||
},
|
},
|
||||||
mixins: [portalMixin, uiSettingsMixin],
|
mixins: [portalMixin],
|
||||||
|
setup() {
|
||||||
|
const { uiSettings, updateUISettings } = useUISettings();
|
||||||
|
|
||||||
|
return {
|
||||||
|
uiSettings,
|
||||||
|
updateUISettings,
|
||||||
|
};
|
||||||
|
},
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
isOnDesktop: true,
|
isOnDesktop: true,
|
||||||
|
|||||||
@@ -191,9 +191,9 @@
|
|||||||
|
|
||||||
<script>
|
<script>
|
||||||
import { useAlert } from 'dashboard/composables';
|
import { useAlert } from 'dashboard/composables';
|
||||||
|
import { useUISettings } from 'dashboard/composables/useUISettings';
|
||||||
import thumbnail from 'dashboard/components/widgets/Thumbnail.vue';
|
import thumbnail from 'dashboard/components/widgets/Thumbnail.vue';
|
||||||
import LocaleItemTable from './PortalListItemTable.vue';
|
import LocaleItemTable from './PortalListItemTable.vue';
|
||||||
import uiSettingsMixin from 'dashboard/mixins/uiSettings';
|
|
||||||
import { PORTALS_EVENTS } from '../../../../helper/AnalyticsHelper/events';
|
import { PORTALS_EVENTS } from '../../../../helper/AnalyticsHelper/events';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
@@ -201,7 +201,6 @@ export default {
|
|||||||
thumbnail,
|
thumbnail,
|
||||||
LocaleItemTable,
|
LocaleItemTable,
|
||||||
},
|
},
|
||||||
mixins: [uiSettingsMixin],
|
|
||||||
props: {
|
props: {
|
||||||
portal: {
|
portal: {
|
||||||
type: Object,
|
type: Object,
|
||||||
@@ -213,6 +212,13 @@ export default {
|
|||||||
values: ['archived', 'draft', 'published'],
|
values: ['archived', 'draft', 'published'],
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
setup() {
|
||||||
|
const { updateUISettings } = useUISettings();
|
||||||
|
|
||||||
|
return {
|
||||||
|
updateUISettings,
|
||||||
|
};
|
||||||
|
},
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
showDeleteConfirmationPopup: false,
|
showDeleteConfirmationPopup: false,
|
||||||
|
|||||||
@@ -1,17 +1,23 @@
|
|||||||
<template>
|
<template>
|
||||||
<div
|
<div
|
||||||
class="text-slate-600 dark:text-slate-200 flex items-center justify-center w-full"
|
class="flex items-center justify-center w-full text-slate-600 dark:text-slate-200"
|
||||||
>
|
>
|
||||||
Loading...
|
Loading...
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import uiSettingsMixin from 'dashboard/mixins/uiSettings';
|
|
||||||
import { mapGetters } from 'vuex';
|
import { mapGetters } from 'vuex';
|
||||||
|
import { useUISettings } from 'dashboard/composables/useUISettings';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
mixins: [uiSettingsMixin],
|
setup() {
|
||||||
|
const { uiSettings } = useUISettings();
|
||||||
|
|
||||||
|
return {
|
||||||
|
uiSettings,
|
||||||
|
};
|
||||||
|
},
|
||||||
computed: {
|
computed: {
|
||||||
...mapGetters({ portals: 'portals/allPortals' }),
|
...mapGetters({ portals: 'portals/allPortals' }),
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -47,13 +47,13 @@
|
|||||||
<script>
|
<script>
|
||||||
import { mapGetters } from 'vuex';
|
import { mapGetters } from 'vuex';
|
||||||
import { useAlert } from 'dashboard/composables';
|
import { useAlert } from 'dashboard/composables';
|
||||||
|
import { useUISettings } from 'dashboard/composables/useUISettings';
|
||||||
import wootConstants from 'dashboard/constants/globals';
|
import wootConstants from 'dashboard/constants/globals';
|
||||||
|
|
||||||
import InboxCard from './components/InboxCard.vue';
|
import InboxCard from './components/InboxCard.vue';
|
||||||
import InboxListHeader from './components/InboxListHeader.vue';
|
import InboxListHeader from './components/InboxListHeader.vue';
|
||||||
import { INBOX_EVENTS } from 'dashboard/helper/AnalyticsHelper/events';
|
import { INBOX_EVENTS } from 'dashboard/helper/AnalyticsHelper/events';
|
||||||
import IntersectionObserver from 'dashboard/components/IntersectionObserver.vue';
|
import IntersectionObserver from 'dashboard/components/IntersectionObserver.vue';
|
||||||
import uiSettingsMixin from 'dashboard/mixins/uiSettings';
|
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
components: {
|
components: {
|
||||||
@@ -61,7 +61,13 @@ export default {
|
|||||||
InboxListHeader,
|
InboxListHeader,
|
||||||
IntersectionObserver,
|
IntersectionObserver,
|
||||||
},
|
},
|
||||||
mixins: [uiSettingsMixin],
|
setup() {
|
||||||
|
const { uiSettings } = useUISettings();
|
||||||
|
|
||||||
|
return {
|
||||||
|
uiSettings,
|
||||||
|
};
|
||||||
|
},
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
infiniteLoaderOptions: {
|
infiniteLoaderOptions: {
|
||||||
|
|||||||
@@ -5,7 +5,7 @@
|
|||||||
:empty-state-message="$t('INBOX.LIST.NO_MESSAGES_AVAILABLE')"
|
:empty-state-message="$t('INBOX.LIST.NO_MESSAGES_AVAILABLE')"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div v-else class="flex flex-col h-full w-full">
|
<div v-else class="flex flex-col w-full h-full">
|
||||||
<inbox-item-header
|
<inbox-item-header
|
||||||
class="flex-1"
|
class="flex-1"
|
||||||
:total-length="totalNotificationCount"
|
:total-length="totalNotificationCount"
|
||||||
@@ -18,7 +18,7 @@
|
|||||||
v-if="isConversationLoading"
|
v-if="isConversationLoading"
|
||||||
class="flex items-center h-[calc(100%-56px)] justify-center bg-slate-25 dark:bg-slate-800"
|
class="flex items-center h-[calc(100%-56px)] justify-center bg-slate-25 dark:bg-slate-800"
|
||||||
>
|
>
|
||||||
<span class="spinner my-4" />
|
<span class="my-4 spinner" />
|
||||||
</div>
|
</div>
|
||||||
<conversation-box
|
<conversation-box
|
||||||
v-else
|
v-else
|
||||||
@@ -38,7 +38,7 @@ import { mapGetters } from 'vuex';
|
|||||||
import InboxItemHeader from './components/InboxItemHeader.vue';
|
import InboxItemHeader from './components/InboxItemHeader.vue';
|
||||||
import ConversationBox from 'dashboard/components/widgets/conversation/ConversationBox.vue';
|
import ConversationBox from 'dashboard/components/widgets/conversation/ConversationBox.vue';
|
||||||
import InboxEmptyState from './InboxEmptyState.vue';
|
import InboxEmptyState from './InboxEmptyState.vue';
|
||||||
import uiSettingsMixin from 'dashboard/mixins/uiSettings';
|
import { useUISettings } from 'dashboard/composables/useUISettings';
|
||||||
import { BUS_EVENTS } from 'shared/constants/busEvents';
|
import { BUS_EVENTS } from 'shared/constants/busEvents';
|
||||||
import { INBOX_EVENTS } from 'dashboard/helper/AnalyticsHelper/events';
|
import { INBOX_EVENTS } from 'dashboard/helper/AnalyticsHelper/events';
|
||||||
|
|
||||||
@@ -48,7 +48,14 @@ export default {
|
|||||||
InboxEmptyState,
|
InboxEmptyState,
|
||||||
ConversationBox,
|
ConversationBox,
|
||||||
},
|
},
|
||||||
mixins: [uiSettingsMixin],
|
setup() {
|
||||||
|
const { uiSettings, updateUISettings } = useUISettings();
|
||||||
|
|
||||||
|
return {
|
||||||
|
uiSettings,
|
||||||
|
updateUISettings,
|
||||||
|
};
|
||||||
|
},
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
isConversationLoading: false,
|
isConversationLoading: false,
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
<div
|
<div
|
||||||
class="flex flex-col bg-white z-50 dark:bg-slate-900 w-[170px] border shadow-md border-slate-100 dark:border-slate-700/50 rounded-xl divide-y divide-slate-100 dark:divide-slate-700/50"
|
class="flex flex-col bg-white z-50 dark:bg-slate-900 w-[170px] border shadow-md border-slate-100 dark:border-slate-700/50 rounded-xl divide-y divide-slate-100 dark:divide-slate-700/50"
|
||||||
>
|
>
|
||||||
<div class="flex items-center justify-between h-11 p-3 rounded-t-lg">
|
<div class="flex items-center justify-between p-3 rounded-t-lg h-11">
|
||||||
<div class="flex gap-1.5">
|
<div class="flex gap-1.5">
|
||||||
<fluent-icon
|
<fluent-icon
|
||||||
icon="arrow-sort"
|
icon="arrow-sort"
|
||||||
@@ -10,7 +10,7 @@
|
|||||||
size="16"
|
size="16"
|
||||||
class="text-slate-700 dark:text-slate-100"
|
class="text-slate-700 dark:text-slate-100"
|
||||||
/>
|
/>
|
||||||
<span class="font-medium text-xs text-slate-800 dark:text-slate-100">
|
<span class="text-xs font-medium text-slate-800 dark:text-slate-100">
|
||||||
{{ $t('INBOX.DISPLAY_MENU.SORT') }}
|
{{ $t('INBOX.DISPLAY_MENU.SORT') }}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
@@ -64,7 +64,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<span
|
<span
|
||||||
class="font-medium text-xs py-4 px-3 text-slate-400 dark:text-slate-400"
|
class="px-3 py-4 text-xs font-medium text-slate-400 dark:text-slate-400"
|
||||||
>
|
>
|
||||||
{{ $t('INBOX.DISPLAY_MENU.DISPLAY') }}
|
{{ $t('INBOX.DISPLAY_MENU.DISPLAY') }}
|
||||||
</span>
|
</span>
|
||||||
@@ -98,10 +98,17 @@
|
|||||||
|
|
||||||
<script>
|
<script>
|
||||||
import wootConstants from 'dashboard/constants/globals';
|
import wootConstants from 'dashboard/constants/globals';
|
||||||
import uiSettingsMixin from 'dashboard/mixins/uiSettings';
|
import { useUISettings } from 'dashboard/composables/useUISettings';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
mixins: [uiSettingsMixin],
|
setup() {
|
||||||
|
const { uiSettings, updateUISettings } = useUISettings();
|
||||||
|
|
||||||
|
return {
|
||||||
|
uiSettings,
|
||||||
|
updateUISettings,
|
||||||
|
};
|
||||||
|
},
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
showSortMenu: false,
|
showSortMenu: false,
|
||||||
|
|||||||
@@ -87,7 +87,7 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div
|
<div
|
||||||
class="p-4 border-slate-25 dark:border-slate-700 text-black-900 dark:text-slate-300 flex flex-row"
|
class="flex flex-row p-4 border-slate-25 dark:border-slate-700 text-black-900 dark:text-slate-300"
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
class="flex-grow-0 flex-shrink-0 flex-[25%] min-w-0 py-4 pr-6 pl-0"
|
class="flex-grow-0 flex-shrink-0 flex-[25%] min-w-0 py-4 pr-6 pl-0"
|
||||||
@@ -103,7 +103,7 @@
|
|||||||
<woot-code :script="getAccountId" />
|
<woot-code :script="getAccountId" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="text-sm text-center p-4">
|
<div class="p-4 text-sm text-center">
|
||||||
<div>{{ `v${globalConfig.appVersion}` }}</div>
|
<div>{{ `v${globalConfig.appVersion}` }}</div>
|
||||||
<div v-if="hasAnUpdateAvailable && globalConfig.displayManifest">
|
<div v-if="hasAnUpdateAvailable && globalConfig.displayManifest">
|
||||||
{{
|
{{
|
||||||
@@ -132,15 +132,22 @@
|
|||||||
import { required, minValue, maxValue } from 'vuelidate/lib/validators';
|
import { required, minValue, maxValue } from 'vuelidate/lib/validators';
|
||||||
import { mapGetters } from 'vuex';
|
import { mapGetters } from 'vuex';
|
||||||
import { useAlert } from 'dashboard/composables';
|
import { useAlert } from 'dashboard/composables';
|
||||||
|
import { useUISettings } from 'dashboard/composables/useUISettings';
|
||||||
import configMixin from 'shared/mixins/configMixin';
|
import configMixin from 'shared/mixins/configMixin';
|
||||||
import accountMixin from '../../../../mixins/account';
|
import accountMixin from '../../../../mixins/account';
|
||||||
import { FEATURE_FLAGS } from '../../../../featureFlags';
|
import { FEATURE_FLAGS } from '../../../../featureFlags';
|
||||||
import semver from 'semver';
|
import semver from 'semver';
|
||||||
import uiSettingsMixin from 'dashboard/mixins/uiSettings';
|
|
||||||
import { getLanguageDirection } from 'dashboard/components/widgets/conversation/advancedFilterItems/languages';
|
import { getLanguageDirection } from 'dashboard/components/widgets/conversation/advancedFilterItems/languages';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
mixins: [accountMixin, configMixin, uiSettingsMixin],
|
mixins: [accountMixin, configMixin],
|
||||||
|
setup() {
|
||||||
|
const { updateUISettings } = useUISettings();
|
||||||
|
|
||||||
|
return {
|
||||||
|
updateUISettings,
|
||||||
|
};
|
||||||
|
},
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
id: '',
|
id: '',
|
||||||
|
|||||||
@@ -32,7 +32,7 @@
|
|||||||
import { mapGetters } from 'vuex';
|
import { mapGetters } from 'vuex';
|
||||||
import { useAlert } from 'dashboard/composables';
|
import { useAlert } from 'dashboard/composables';
|
||||||
import configMixin from 'shared/mixins/configMixin';
|
import configMixin from 'shared/mixins/configMixin';
|
||||||
import uiSettingsMixin from 'dashboard/mixins/uiSettings';
|
import { useUISettings } from 'dashboard/composables/useUISettings';
|
||||||
import AudioAlertTone from './AudioAlertTone.vue';
|
import AudioAlertTone from './AudioAlertTone.vue';
|
||||||
import AudioAlertEvent from './AudioAlertEvent.vue';
|
import AudioAlertEvent from './AudioAlertEvent.vue';
|
||||||
import AudioAlertCondition from './AudioAlertCondition.vue';
|
import AudioAlertCondition from './AudioAlertCondition.vue';
|
||||||
@@ -43,7 +43,15 @@ export default {
|
|||||||
AudioAlertTone,
|
AudioAlertTone,
|
||||||
AudioAlertCondition,
|
AudioAlertCondition,
|
||||||
},
|
},
|
||||||
mixins: [configMixin, uiSettingsMixin],
|
mixins: [configMixin],
|
||||||
|
setup() {
|
||||||
|
const { uiSettings, updateUISettings } = useUISettings();
|
||||||
|
|
||||||
|
return {
|
||||||
|
uiSettings,
|
||||||
|
updateUISettings,
|
||||||
|
};
|
||||||
|
},
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
audioAlert: '',
|
audioAlert: '',
|
||||||
@@ -56,7 +64,6 @@ export default {
|
|||||||
computed: {
|
computed: {
|
||||||
...mapGetters({
|
...mapGetters({
|
||||||
accountId: 'getCurrentAccountId',
|
accountId: 'getCurrentAccountId',
|
||||||
uiSettings: 'getUISettings',
|
|
||||||
}),
|
}),
|
||||||
},
|
},
|
||||||
watch: {
|
watch: {
|
||||||
|
|||||||
@@ -47,7 +47,7 @@
|
|||||||
:description="hotKey.description"
|
:description="hotKey.description"
|
||||||
:light-image="hotKey.lightImage"
|
:light-image="hotKey.lightImage"
|
||||||
:dark-image="hotKey.darkImage"
|
:dark-image="hotKey.darkImage"
|
||||||
:active="isEditorHotKeyEnabled(uiSettings, hotKey.key)"
|
:active="isEditorHotKeyEnabled(hotKey.key)"
|
||||||
@click="toggleHotKey(hotKey.key)"
|
@click="toggleHotKey(hotKey.key)"
|
||||||
/>
|
/>
|
||||||
</button>
|
</button>
|
||||||
@@ -81,15 +81,12 @@
|
|||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<script>
|
<script>
|
||||||
import globalConfigMixin from 'shared/mixins/globalConfigMixin';
|
|
||||||
import uiSettingsMixin, {
|
|
||||||
isEditorHotKeyEnabled,
|
|
||||||
} from 'dashboard/mixins/uiSettings';
|
|
||||||
import { useAlert } from 'dashboard/composables';
|
|
||||||
import { mapGetters } from 'vuex';
|
import { mapGetters } from 'vuex';
|
||||||
|
import { useAlert } from 'dashboard/composables';
|
||||||
|
import { useUISettings } from 'dashboard/composables/useUISettings';
|
||||||
import { clearCookiesOnLogout } from 'dashboard/store/utils/api.js';
|
import { clearCookiesOnLogout } from 'dashboard/store/utils/api.js';
|
||||||
import { copyTextToClipboard } from 'shared/helpers/clipboard';
|
import { copyTextToClipboard } from 'shared/helpers/clipboard';
|
||||||
|
import globalConfigMixin from 'shared/mixins/globalConfigMixin';
|
||||||
import UserProfilePicture from './UserProfilePicture.vue';
|
import UserProfilePicture from './UserProfilePicture.vue';
|
||||||
import UserBasicDetails from './UserBasicDetails.vue';
|
import UserBasicDetails from './UserBasicDetails.vue';
|
||||||
import MessageSignature from './MessageSignature.vue';
|
import MessageSignature from './MessageSignature.vue';
|
||||||
@@ -112,7 +109,17 @@ export default {
|
|||||||
AudioNotifications,
|
AudioNotifications,
|
||||||
AccessToken,
|
AccessToken,
|
||||||
},
|
},
|
||||||
mixins: [globalConfigMixin, uiSettingsMixin],
|
mixins: [globalConfigMixin],
|
||||||
|
setup() {
|
||||||
|
const { uiSettings, updateUISettings, isEditorHotKeyEnabled } =
|
||||||
|
useUISettings();
|
||||||
|
|
||||||
|
return {
|
||||||
|
uiSettings,
|
||||||
|
updateUISettings,
|
||||||
|
isEditorHotKeyEnabled,
|
||||||
|
};
|
||||||
|
},
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
avatarFile: '',
|
avatarFile: '',
|
||||||
@@ -168,7 +175,6 @@ export default {
|
|||||||
this.displayName = this.currentUser.display_name;
|
this.displayName = this.currentUser.display_name;
|
||||||
this.messageSignature = this.currentUser.message_signature;
|
this.messageSignature = this.currentUser.message_signature;
|
||||||
},
|
},
|
||||||
isEditorHotKeyEnabled,
|
|
||||||
async dispatchUpdate(payload, successMessage, errorMessage) {
|
async dispatchUpdate(payload, successMessage, errorMessage) {
|
||||||
let alertMessage = '';
|
let alertMessage = '';
|
||||||
try {
|
try {
|
||||||
|
|||||||
@@ -134,7 +134,6 @@
|
|||||||
import { mapGetters } from 'vuex';
|
import { mapGetters } from 'vuex';
|
||||||
import { useAlert } from 'dashboard/composables';
|
import { useAlert } from 'dashboard/composables';
|
||||||
import configMixin from 'shared/mixins/configMixin';
|
import configMixin from 'shared/mixins/configMixin';
|
||||||
import uiSettingsMixin from 'dashboard/mixins/uiSettings';
|
|
||||||
import TableHeaderCell from 'dashboard/components/widgets/TableHeaderCell.vue';
|
import TableHeaderCell from 'dashboard/components/widgets/TableHeaderCell.vue';
|
||||||
import CheckBox from 'v3/components/Form/CheckBox.vue';
|
import CheckBox from 'v3/components/Form/CheckBox.vue';
|
||||||
import {
|
import {
|
||||||
@@ -152,7 +151,7 @@ export default {
|
|||||||
FormSwitch,
|
FormSwitch,
|
||||||
CheckBox,
|
CheckBox,
|
||||||
},
|
},
|
||||||
mixins: [configMixin, uiSettingsMixin],
|
mixins: [configMixin],
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
selectedEmailFlags: [],
|
selectedEmailFlags: [],
|
||||||
@@ -167,7 +166,6 @@ export default {
|
|||||||
accountId: 'getCurrentAccountId',
|
accountId: 'getCurrentAccountId',
|
||||||
emailFlags: 'userNotificationSettings/getSelectedEmailFlags',
|
emailFlags: 'userNotificationSettings/getSelectedEmailFlags',
|
||||||
pushFlags: 'userNotificationSettings/getSelectedPushFlags',
|
pushFlags: 'userNotificationSettings/getSelectedPushFlags',
|
||||||
uiSettings: 'getUISettings',
|
|
||||||
isFeatureEnabledonAccount: 'accounts/isFeatureEnabledonAccount',
|
isFeatureEnabledonAccount: 'accounts/isFeatureEnabledonAccount',
|
||||||
}),
|
}),
|
||||||
hasPushAPISupport() {
|
hasPushAPISupport() {
|
||||||
@@ -242,31 +240,6 @@ export default {
|
|||||||
useAlert(this.$t('PROFILE_SETTINGS.FORM.API.UPDATE_ERROR'));
|
useAlert(this.$t('PROFILE_SETTINGS.FORM.API.UPDATE_ERROR'));
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
handleAudioInput(e) {
|
|
||||||
this.enableAudioAlerts = e.target.value;
|
|
||||||
this.updateUISettings({
|
|
||||||
enable_audio_alerts: this.enableAudioAlerts,
|
|
||||||
});
|
|
||||||
useAlert(this.$t('PROFILE_SETTINGS.FORM.API.UPDATE_SUCCESS'));
|
|
||||||
},
|
|
||||||
handleAudioAlertConditions(e) {
|
|
||||||
let condition = e.target.value;
|
|
||||||
if (condition === 'tab_is_inactive') {
|
|
||||||
this.updateUISettings({
|
|
||||||
always_play_audio_alert: !e.target.checked,
|
|
||||||
});
|
|
||||||
} else if (condition === 'conversations_are_read') {
|
|
||||||
this.updateUISettings({
|
|
||||||
alert_if_unread_assigned_conversation_exist: e.target.checked,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
useAlert(this.$t('PROFILE_SETTINGS.FORM.API.UPDATE_SUCCESS'));
|
|
||||||
},
|
|
||||||
handleAudioToneChange(value) {
|
|
||||||
this.updateUISettings({ notification_tone: value });
|
|
||||||
useAlert(this.$t('PROFILE_SETTINGS.FORM.API.UPDATE_SUCCESS'));
|
|
||||||
},
|
|
||||||
handleInput(type, id) {
|
handleInput(type, id) {
|
||||||
if (type === 'email') {
|
if (type === 'email') {
|
||||||
this.handleEmailInput(id);
|
this.handleEmailInput(id);
|
||||||
|
|||||||
@@ -42,7 +42,7 @@ export default {
|
|||||||
type: Number,
|
type: Number,
|
||||||
default: 2,
|
default: 2,
|
||||||
},
|
},
|
||||||
// add this as a prop, so that we won't have to include uiSettingsMixin
|
// add this as a prop, so that we won't have to add useUISettings
|
||||||
sendWithSignature: {
|
sendWithSignature: {
|
||||||
type: Boolean,
|
type: Boolean,
|
||||||
default: false,
|
default: false,
|
||||||
|
|||||||
@@ -1,8 +1,15 @@
|
|||||||
import uiSettingsMixin from 'dashboard/mixins/uiSettings';
|
|
||||||
import { getLanguageDirection } from 'dashboard/components/widgets/conversation/advancedFilterItems/languages';
|
import { getLanguageDirection } from 'dashboard/components/widgets/conversation/advancedFilterItems/languages';
|
||||||
|
import { useUISettings } from 'dashboard/composables/useUISettings';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
mixins: [uiSettingsMixin],
|
setup() {
|
||||||
|
const { uiSettings, updateUISettings } = useUISettings();
|
||||||
|
|
||||||
|
return {
|
||||||
|
uiSettings,
|
||||||
|
updateUISettings,
|
||||||
|
};
|
||||||
|
},
|
||||||
computed: {
|
computed: {
|
||||||
isRTLView() {
|
isRTLView() {
|
||||||
const { rtl_view: isRTLView } = this.uiSettings;
|
const { rtl_view: isRTLView } = this.uiSettings;
|
||||||
|
|||||||
@@ -1,16 +1,19 @@
|
|||||||
import { shallowMount } from '@vue/test-utils';
|
import { shallowMount } from '@vue/test-utils';
|
||||||
import rtlMixin from 'shared/mixins/rtlMixin';
|
import rtlMixin from 'shared/mixins/rtlMixin';
|
||||||
|
import { useUISettings } from 'dashboard/composables/useUISettings';
|
||||||
|
|
||||||
|
vi.mock('dashboard/composables/useUISettings');
|
||||||
|
|
||||||
describe('rtlMixin', () => {
|
describe('rtlMixin', () => {
|
||||||
const createComponent = rtl_view => {
|
const createComponent = rtl_view => {
|
||||||
|
useUISettings.mockReturnValue({
|
||||||
|
uiSettings: { rtl_view },
|
||||||
|
updateUISettings: vi.fn(),
|
||||||
|
});
|
||||||
|
|
||||||
return shallowMount({
|
return shallowMount({
|
||||||
render() {},
|
render() {},
|
||||||
mixins: [rtlMixin],
|
mixins: [rtlMixin],
|
||||||
computed: {
|
|
||||||
uiSettings() {
|
|
||||||
return { rtl_view };
|
|
||||||
},
|
|
||||||
},
|
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user