Compare commits

..
Author SHA1 Message Date
Shivam MishraandGitHub b9e32791a4 Merge branch 'develop' into feat/update-editor 2024-06-03 13:04:37 +05:30
a7945384e0 style: no need for assignment
Co-authored-by: Muhsin Keloth <muhsinkeramam@gmail.com>
2024-06-03 12:50:58 +05:30
f956530b36 chore: upgrade packages (#9555)
This PR upgrades the packages to the latest patch versions, no-breaking
changes. Can be merged once CI clears

Co-authored-by: Pranav <pranav@chatwoot.com>
2024-06-02 19:09:06 +05:30
Pavel KuzminandGitHub 803471e42f fix: browser info (#9569)
# Pull Request Template

## Description

fixed getting browser data

In Vue, without computed properties, the data doesn't update, and
because of this, it doesn't display information about the browser.

## Type of change

Please delete options that are not relevant.

- [x] Bug fix (non-breaking change which fixes an issue)
- [ ] New feature (non-breaking change which adds functionality)
- [ ] Breaking change (fix or feature that would cause existing
functionality not to work as expected)
- [ ] This change requires a documentation update

## Checklist:

- [x] My code follows the style guidelines of this project
- [x] I have performed a self-review of my code
- [ ] I have commented on my code, particularly in hard-to-understand
areas
- [ ] I have made corresponding changes to the documentation
- [ ] My changes generate no new warnings
- [ ] I have added tests that prove my fix is effective or that my
feature works
- [ ] New and existing unit tests pass locally with my changes
- [ ] Any dependent changes have been merged and published in downstream
modules
2024-06-02 19:06:10 +05:30
dependabot[bot]GitHubdependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
b0114dee42 chore(deps): bump pug from 3.0.2 to 3.0.3 (#9564)
Bumps [pug](https://github.com/pugjs/pug) from 3.0.2 to 3.0.3.
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/pugjs/pug/releases">pug's
releases</a>.</em></p>
<blockquote>
<h2>pug-code-gen@3.0.3</h2>
<h2>Bug Fixes</h2>
<ul>
<li>Validate <code>templateName</code> and <code>globals</code> are
valid JavaScript identifiers to prevent possible remote code execution
if un-trusted user input is passed to the compilation options (<a
href="https://redirect.github.com/pugjs/pug/issues/3438">#3438</a>)</li>
</ul>
<h2>pug@3.0.3</h2>
<h2>Bug Fixes</h2>
<ul>
<li>
<p>Update pug-code-gen with the following fix: (<a
href="https://redirect.github.com/pugjs/pug/issues/3438">#3438</a>)</p>
<p>Validate <code>templateName</code> and <code>globals</code> are valid
JavaScript identifiers to prevent possible remote code execution if
un-trusted user input is passed to the compilation options</p>
</li>
</ul>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/pugjs/pug/commit/32acfe8f197dc44c54e8af32c7d7b19aa9d350fb"><code>32acfe8</code></a>
fix: ensure template names are valid identifiers (<a
href="https://redirect.github.com/pugjs/pug/issues/3438">#3438</a>)</li>
<li><a
href="https://github.com/pugjs/pug/commit/4767cafea0af3d3f935553df0f9a8a6e76d470c2"><code>4767caf</code></a>
refactor: convert pug-error to TypeScript (<a
href="https://redirect.github.com/pugjs/pug/issues/3355">#3355</a>)</li>
<li><a
href="https://github.com/pugjs/pug/commit/a724446abb128f2a09acb143ce436021be8f6e6a"><code>a724446</code></a>
chore: update character-parser (<a
href="https://redirect.github.com/pugjs/pug/issues/3354">#3354</a>)</li>
<li><a
href="https://github.com/pugjs/pug/commit/6cca8f76befe7285eead0416ba4e2dbba825ab65"><code>6cca8f7</code></a>
docs: fix GitHub format in README (<a
href="https://redirect.github.com/pugjs/pug/issues/3335">#3335</a>)</li>
<li>See full diff in <a
href="https://github.com/pugjs/pug/compare/pug@3.0.2...pug@3.0.3">compare
view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=pug&package-manager=npm_and_yarn&previous-version=3.0.2&new-version=3.0.3)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)

Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot merge` will merge this PR after your CI passes on it
- `@dependabot squash and merge` will squash and merge this PR after
your CI passes on it
- `@dependabot cancel merge` will cancel a previously requested merge
and block automerging
- `@dependabot reopen` will reopen this PR if it is closed
- `@dependabot close` will close this PR and stop Dependabot recreating
it. You can achieve the same result by closing it manually
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore this major version` will close this PR and stop
Dependabot creating any more for this major version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop
Dependabot creating any more for this minor version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop
Dependabot creating any more for this dependency (unless you reopen the
PR or upgrade to it yourself)
You can disable automated security fix PRs for this repo from the
[Security Alerts
page](https://github.com/chatwoot/chatwoot/network/alerts).

</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-05-31 10:46:16 -07:00
Shivam MishraandGitHub ae35b47ae3 fix: Add the translation for Sign in with Microsoft button (#9567)
The sign in button for Microsoft inbox was not translated, this PR fixes it
2024-05-31 09:01:50 -07:00
Fayaz AhmedandGitHub b474929f5e chore: Replace eventBus with mitt.js [CW-3275] (#9539)
# Replace the deprecated `eventBus` with mitt.js

## Description

Since eventBus and it's respective methods are deprecated and removed
from all future releases of vue, this was blocking us from migrating.
This PR replaces eventBus with
[mitt](https://github.com/developit/mitt). I have created a wrapper
mitt.js to simulate the same old event names so it's backwards
compatible, without making a lot of changes.


Fixes # (issue)

## Type of change

Please delete options that are not relevant.

- [x] Bug fix (non-breaking change which fixes an issue)
- [ ] New feature (non-breaking change which adds functionality)
- [ ] Breaking change (fix or feature that would cause existing
functionality not to work as expected)
- [ ] This change requires a documentation update

## How Has This Been Tested?

1. Made sure all the places we're listening to bus events are working as
expected.
2. Respective specsf or the events from mitt.


## Checklist:

- [x] My code follows the style guidelines of this project
- [x] I have performed a self-review of my code
- [x] I have commented on my code, particularly in hard-to-understand
areas
- [x] I have made corresponding changes to the documentation
- [x] My changes generate no new warnings
- [x] I have added tests that prove my fix is effective or that my
feature works
- [x] New and existing unit tests pass locally with my changes
- [x] Any dependent changes have been merged and published in downstream
modules
2024-05-31 15:50:36 +05:30
Shivam MishraandGitHub 20c4b70e8d Merge branch 'develop' into feat/update-editor 2024-05-31 12:26:40 +05:30
Shivam Mishra c4e636fce0 test: unit tests for useSpecialContent 2024-05-09 18:43:58 +05:30
Shivam Mishra 8ac095dea5 chore: add comments to composable 2024-05-09 18:42:46 +05:30
Shivam Mishra ecb28383c1 refactor: move useSpecialContent to a composable 2024-05-09 18:28:40 +05:30
Shivam Mishra 6129cb5f80 feat: activate methods 2024-05-09 18:08:57 +05:30
Shivam Mishra 24a65fc483 refactor: editor.vue, make it simpler 2024-05-09 17:50:52 +05:30
Shivam Mishra 55b6e5fbf6 refactor: move create state to editorHelper 2024-05-09 17:20:14 +05:30
70 changed files with 702 additions and 359 deletions
@@ -514,14 +514,14 @@ export default {
this.$store.dispatch('campaigns/get');
}
bus.$on('fetch_conversation_stats', () => {
this.$emitter.on('fetch_conversation_stats', () => {
this.$store.dispatch('conversationStats/get', this.conversationFilters);
});
bus.$on(CMD_SNOOZE_CONVERSATION, this.onCmdSnoozeConversation);
this.$emitter.on(CMD_SNOOZE_CONVERSATION, this.onCmdSnoozeConversation);
},
beforeDestroy() {
bus.$off(CMD_SNOOZE_CONVERSATION, this.onCmdSnoozeConversation);
this.$emitter.off(CMD_SNOOZE_CONVERSATION, this.onCmdSnoozeConversation);
},
methods: {
updateVirtualListProps(key, value) {
@@ -742,7 +742,7 @@ export default {
updateAssigneeTab(selectedTab) {
if (this.activeAssigneeTab !== selectedTab) {
this.resetBulkActions();
bus.$emit('clearSearchInput');
this.$emitter.emit('clearSearchInput');
this.activeAssigneeTab = selectedTab;
if (!this.currentPage) {
this.fetchConversations();
+3 -1
View File
@@ -25,8 +25,10 @@
<script>
import 'highlight.js/styles/default.css';
import { copyTextToClipboard } from 'shared/helpers/clipboard';
import alertMixin from 'shared/mixins/alertMixin';
export default {
mixins: [alertMixin],
props: {
script: {
type: String,
@@ -59,7 +61,7 @@ export default {
async onCopy(e) {
e.preventDefault();
await copyTextToClipboard(this.script);
bus.$emit('newToastMessage', this.$t('COMPONENTS.CODE.COPY_SUCCESSFUL'));
this.showAlert(this.$t('COMPONENTS.CODE.COPY_SUCCESSFUL'));
},
},
};
@@ -270,10 +270,10 @@ export default {
},
mounted() {
this.editedValue = this.formattedValue;
bus.$on(BUS_EVENTS.FOCUS_CUSTOM_ATTRIBUTE, this.onFocusAttribute);
this.$emitter.on(BUS_EVENTS.FOCUS_CUSTOM_ATTRIBUTE, this.onFocusAttribute);
},
destroyed() {
bus.$off(BUS_EVENTS.FOCUS_CUSTOM_ATTRIBUTE, this.onFocusAttribute);
this.$emitter.off(BUS_EVENTS.FOCUS_CUSTOM_ATTRIBUTE, this.onFocusAttribute);
},
methods: {
onFocusAttribute(focusAttributeKey) {
@@ -18,8 +18,10 @@
<script>
import 'highlight.js/styles/default.css';
import { copyTextToClipboard } from 'shared/helpers/clipboard';
import alertMixin from 'shared/mixins/alertMixin';
export default {
mixins: [alertMixin],
props: {
value: {
type: String,
@@ -35,7 +37,7 @@ export default {
async onCopy(e) {
e.preventDefault();
await copyTextToClipboard(this.value);
bus.$emit('newToastMessage', this.$t('COMPONENTS.CODE.COPY_SUCCESSFUL'));
this.showAlert(this.$t('COMPONENTS.CODE.COPY_SUCCESSFUL'));
},
toggleMasked() {
this.masked = !this.masked;
@@ -55,7 +55,7 @@ export default {
mounted() {
window.addEventListener('offline', this.updateOnlineStatus);
window.bus.$on(BUS_EVENTS.WEBSOCKET_DISCONNECT, () => {
this.$emitter.on(BUS_EVENTS.WEBSOCKET_DISCONNECT, () => {
// TODO: Remove this after completing the conversation list refetching
// TODO: DIRTY FIX : CLEAN UP THIS WITH PROPER FIX, DELAYING THE RECONNECT FOR NOW
// THE CABLE IS FIRING IS VERY COMMON AND THUS INTERFERING USER EXPERIENCE
@@ -21,7 +21,7 @@ export default {
},
methods: {
onMenuItemClick() {
bus.$emit(BUS_EVENTS.TOGGLE_SIDEMENU);
this.$emitter.emit(BUS_EVENTS.TOGGLE_SIDEMENU);
},
},
};
@@ -15,11 +15,13 @@
<script>
import WootSnackbar from './Snackbar.vue';
import alertMixin from 'shared/mixins/alertMixin';
export default {
components: {
WootSnackbar,
},
mixins: [alertMixin],
props: {
duration: {
type: Number,
@@ -34,10 +36,10 @@ export default {
},
mounted() {
bus.$on('newToastMessage', this.onNewToastMessage);
this.$emitter.on('newToastMessage', this.onNewToastMessage);
},
beforeDestroy() {
bus.$off('newToastMessage', this.onNewToastMessage);
this.$emitter.off('newToastMessage', this.onNewToastMessage);
},
methods: {
onNewToastMessage(message, action) {
@@ -128,12 +128,12 @@ export default {
},
},
mounted() {
bus.$on(CMD_REOPEN_CONVERSATION, this.onCmdOpenConversation);
bus.$on(CMD_RESOLVE_CONVERSATION, this.onCmdResolveConversation);
this.$emitter.on(CMD_REOPEN_CONVERSATION, this.onCmdOpenConversation);
this.$emitter.on(CMD_RESOLVE_CONVERSATION, this.onCmdResolveConversation);
},
destroyed() {
bus.$off(CMD_REOPEN_CONVERSATION, this.onCmdOpenConversation);
bus.$off(CMD_RESOLVE_CONVERSATION, this.onCmdResolveConversation);
this.$emitter.off(CMD_REOPEN_CONVERSATION, this.onCmdOpenConversation);
this.$emitter.off(CMD_RESOLVE_CONVERSATION, this.onCmdResolveConversation);
},
methods: {
getKeyboardEvents() {
@@ -22,7 +22,7 @@ import {
setYear,
isAfter,
} from 'date-fns';
import { useAlert } from 'dashboard/composables';
import DatePickerButton from './components/DatePickerButton.vue';
import CalendarDateInput from './components/CalendarDateInput.vue';
import CalendarDateRange from './components/CalendarDateRange.vue';
@@ -185,7 +185,7 @@ const updateManualInput = (newDate, calendarType) => {
};
const handleManualInputError = message => {
bus.$emit('newToastMessage', message);
useAlert(message);
};
const resetDatePicker = () => {
@@ -201,7 +201,7 @@ const resetDatePicker = () => {
const emitDateRange = () => {
if (!isValid(selectedStartDate.value) || !isValid(selectedEndDate.value)) {
bus.$emit('newToastMessage', 'Please select a valid time range');
useAlert('Please select a valid time range');
} else {
showDatePicker.value = false;
emit('dateRangeChanged', [selectedStartDate.value, selectedEndDate.value]);
@@ -100,8 +100,6 @@ const shouldShowEmptyState = computed(() => {
:key="item.id"
:is-active="isFilterActive(item.id)"
:button-text="item.name"
:left-icon="item.leftIcon"
:left-icon-color="item.leftIconColor"
@click="$emit('click', item)"
/>
</slot>
@@ -8,14 +8,6 @@ defineProps({
type: Boolean,
default: false,
},
leftIcon: {
type: String,
default: '',
},
leftIconColor: {
type: String,
default: '',
},
});
</script>
<template>
@@ -26,13 +18,7 @@ defineProps({
@mouseleave="$emit('mouseleave')"
@focus="$emit('focus')"
>
<div class="inline-flex items-center gap-2 overflow-hidden">
<fluent-icon
v-if="leftIcon"
icon="status"
size="18"
:style="{ color: leftIconColor }"
/>
<div class="inline-flex items-center gap-3 overflow-hidden">
<span
class="text-sm font-medium truncate text-slate-900 dark:text-slate-50"
>
@@ -81,7 +81,7 @@ export default {
},
mounted() {
bus.$on(CMD_AI_ASSIST, this.onAIAssist);
this.$emitter.on(CMD_AI_ASSIST, this.onAIAssist);
this.initialMessage = this.draftMessage;
},
@@ -3,17 +3,17 @@
<tag-agents
v-if="showUserMentions && isPrivate"
:search-key="mentionSearchKey"
@click="insertMentionNode"
@click="content => insertSpecialContent('mention', content)"
/>
<canned-response
v-if="shouldShowCannedResponses"
:search-key="cannedSearchTerm"
@click="insertCannedResponse"
@click="content => insertSpecialContent('cannedResponse', content)"
/>
<variable-list
v-if="shouldShowVariables"
:search-key="variableSearchTerm"
@click="insertVariable"
@click="content => insertSpecialContent('variable', content)"
/>
<input
ref="imageUpload"
@@ -47,11 +47,9 @@
<script>
import {
messageSchema,
buildEditor,
EditorView,
MessageMarkdownTransformer,
MessageMarkdownSerializer,
EditorState,
Selection,
} from '@chatwoot/prosemirror-schema';
import {
@@ -70,6 +68,7 @@ import {
scrollCursorIntoView,
findNodeToInsertImage,
setURLWithQueryAndSize,
createState,
} from 'dashboard/helper/editorHelper';
const TYPING_INDICATOR_IDLE_TIME = 4000;
@@ -82,10 +81,7 @@ import {
import keyboardEventListenerMixins from 'shared/mixins/keyboardEventListenerMixins';
import uiSettingsMixin from 'dashboard/mixins/uiSettings';
import { isEditorHotKeyEnabled } from 'dashboard/mixins/uiSettings';
import {
replaceVariablesInMessage,
createTypingIndicator,
} from '@chatwoot/utils';
import { createTypingIndicator } from '@chatwoot/utils';
import { CONVERSATION_EVENTS } from '../../../helper/AnalyticsHelper/events';
import { checkFileSizeLimit } from 'shared/helpers/FileHelper';
import { uploadFile } from 'dashboard/helper/uploadHelper';
@@ -94,27 +90,7 @@ import {
MESSAGE_EDITOR_MENU_OPTIONS,
MESSAGE_EDITOR_IMAGE_RESIZES,
} from 'dashboard/constants/editor';
const createState = (
content,
placeholder,
// eslint-disable-next-line default-param-last
plugins = [],
// eslint-disable-next-line default-param-last
methods = {},
enabledMenuOptions
) => {
return EditorState.create({
doc: new MessageMarkdownTransformer(messageSchema).parse(content),
plugins: buildEditor({
schema: messageSchema,
placeholder,
methods,
plugins,
enabledMenuOptions,
}),
});
};
import useSpecialContent from 'dashboard/composables/editor/useSpecialContent';
export default {
name: 'WootMessageEditor',
@@ -139,6 +115,11 @@ export default {
channelType: { type: String, default: '' },
showImageResizeToolbar: { type: Boolean, default: false }, // A kill switch to show or hide the image toolbar
},
setup() {
const { getContentNode } = useSpecialContent();
return { getContentNode };
},
data() {
return {
typingIndicator: createTypingIndicator(
@@ -352,10 +333,16 @@ export default {
// Components using this
// 1. SearchPopover.vue
bus.$on(BUS_EVENTS.INSERT_INTO_RICH_EDITOR, this.insertContentIntoEditor);
this.$emitter.on(
BUS_EVENTS.INSERT_INTO_RICH_EDITOR,
this.insertContentIntoEditor
);
},
beforeDestroy() {
bus.$off(BUS_EVENTS.INSERT_INTO_RICH_EDITOR, this.insertContentIntoEditor);
this.$emitter.off(
BUS_EVENTS.INSERT_INTO_RICH_EDITOR,
this.insertContentIntoEditor
);
},
methods: {
reloadState(content = this.value) {
@@ -446,22 +433,12 @@ export default {
this.emitOnChange();
},
handleDOMEvents: {
keyup: () => {
this.onKeyup();
},
keydown: (view, event) => {
this.onKeydown(event);
},
focus: () => {
this.onFocus();
},
click: () => {
this.isEditorMouseFocusedOnAnImage();
},
blur: () => {
this.onBlur();
},
paste: (view, event) => {
keyup: this.onKeyup,
keydown: (_view, event) => this.onKeydown(event),
focus: this.onFocus,
click: this.isEditorMouseFocusedOnAnImage,
blur: this.onBlur,
paste: (_view, event) => {
const data = event.clipboardData.files;
if (data.length > 0) {
event.preventDefault();
@@ -545,57 +522,39 @@ export default {
this.editorView.dispatch(tr.setSelection(selection));
this.editorView.focus();
},
insertMentionNode(mentionItem) {
/**
* Inserts special content (mention, canned response, or variable) into the editor.
*
* @param {string} type - The type of special content to insert. Possible values: 'mention', 'canned_response', 'variable'.
* @param {Object|string} content - The content to insert, depending on the type.
* - For 'mention' type: An object with 'id' and 'name' properties representing the user mention.
* - For 'canned_response' type: A string representing the canned response.
* - For 'variable' type: A string representing the variable name.
*/
insertSpecialContent(type, content) {
if (!this.editorView) {
return null;
}
const node = this.editorView.state.schema.nodes.mention.create({
userId: mentionItem.id,
userFullName: mentionItem.name,
});
this.insertNodeIntoEditor(node, this.range.from, this.range.to);
this.$track(CONVERSATION_EVENTS.USED_MENTIONS);
return false;
},
insertCannedResponse(cannedItem) {
const updatedMessage = replaceVariablesInMessage({
message: cannedItem,
variables: this.variables,
});
if (!this.editorView) {
return null;
return;
}
let node = new MessageMarkdownTransformer(messageSchema).parse(
updatedMessage
let { node, from, to } = this.getContentNode(
this.editorView,
type,
content,
this.range,
this.variables
);
const from =
node.textContent === updatedMessage
? this.range.from
: this.range.from - 1;
this.insertNodeIntoEditor(node, from, this.range.to);
this.$track(CONVERSATION_EVENTS.INSERTED_A_CANNED_RESPONSE);
return false;
},
insertVariable(variable) {
if (!this.editorView) {
return null;
}
const content = `{{${variable}}}`;
let node = this.editorView.state.schema.text(content);
const { from, to } = this.range;
if (!node) return;
this.insertNodeIntoEditor(node, from, to);
this.showVariables = false;
this.$track(CONVERSATION_EVENTS.INSERTED_A_VARIABLE);
return false;
const event_map = {
mention: CONVERSATION_EVENTS.USED_MENTIONS,
cannedResponse: CONVERSATION_EVENTS.INSERTED_A_CANNED_RESPONSE,
variable: CONVERSATION_EVENTS.INSERTED_A_VARIABLE,
};
this.$track(event_map[type]);
},
openFileBrowser() {
this.$refs.imageUpload.click();
@@ -473,11 +473,11 @@ export default {
},
mounted() {
this.hasMediaLoadError = false;
bus.$on(BUS_EVENTS.ON_MESSAGE_LIST_SCROLL, this.closeContextMenu);
this.$emitter.on(BUS_EVENTS.ON_MESSAGE_LIST_SCROLL, this.closeContextMenu);
this.setupHighlightTimer();
},
beforeDestroy() {
bus.$off(BUS_EVENTS.ON_MESSAGE_LIST_SCROLL, this.closeContextMenu);
this.$emitter.off(BUS_EVENTS.ON_MESSAGE_LIST_SCROLL, this.closeContextMenu);
clearTimeout(this.higlightTimeout);
},
methods: {
@@ -531,7 +531,7 @@ export default {
const { conversation_id: conversationId, id: replyTo } = this.data;
LocalStorage.updateJsonStore(replyStorageKey, conversationId, replyTo);
bus.$emit(BUS_EVENTS.TOGGLE_REPLY_TO_MESSAGE, this.data);
this.$emitter.emit(BUS_EVENTS.TOGGLE_REPLY_TO_MESSAGE, this.data);
},
setupHighlightTimer() {
if (Number(this.$route.query.messageId) !== Number(this.data.id)) {
@@ -324,12 +324,12 @@ export default {
},
created() {
bus.$on(BUS_EVENTS.SCROLL_TO_MESSAGE, this.onScrollToMessage);
this.$emitter.on(BUS_EVENTS.SCROLL_TO_MESSAGE, this.onScrollToMessage);
// when a new message comes in, we refetch the label suggestions
bus.$on(BUS_EVENTS.FETCH_LABEL_SUGGESTIONS, this.fetchSuggestions);
this.$emitter.on(BUS_EVENTS.FETCH_LABEL_SUGGESTIONS, this.fetchSuggestions);
// when a message is sent we set the flag to true this hides the label suggestions,
// until the chat is changed and the flag is reset in the watch for currentChat
bus.$on(BUS_EVENTS.MESSAGE_SENT, () => {
this.$emitter.on(BUS_EVENTS.MESSAGE_SENT, () => {
this.messageSentSinceOpened = true;
});
},
@@ -396,7 +396,7 @@ export default {
this.$store.dispatch('fetchAllAttachments', this.currentChat.id);
},
removeBusListeners() {
bus.$off(BUS_EVENTS.SCROLL_TO_MESSAGE, this.onScrollToMessage);
this.$emitter.off(BUS_EVENTS.SCROLL_TO_MESSAGE, this.onScrollToMessage);
},
onScrollToMessage({ messageId = '' } = {}) {
this.$nextTick(() => {
@@ -514,7 +514,7 @@ export default {
} else {
this.hasUserScrolled = true;
}
bus.$emit(BUS_EVENTS.ON_MESSAGE_LIST_SCROLL);
this.$emitter.emit(BUS_EVENTS.ON_MESSAGE_LIST_SCROLL);
this.fetchPreviousMessages(e.target.scrollTop);
},
@@ -61,14 +61,14 @@ export default {
...mapGetters({ currentChat: 'getSelectedChat' }),
},
mounted() {
bus.$on(CMD_MUTE_CONVERSATION, this.mute);
bus.$on(CMD_UNMUTE_CONVERSATION, this.unmute);
bus.$on(CMD_SEND_TRANSCRIPT, this.toggleEmailActionsModal);
this.$emitter.on(CMD_MUTE_CONVERSATION, this.mute);
this.$emitter.on(CMD_UNMUTE_CONVERSATION, this.unmute);
this.$emitter.on(CMD_SEND_TRANSCRIPT, this.toggleEmailActionsModal);
},
destroyed() {
bus.$off(CMD_MUTE_CONVERSATION, this.mute);
bus.$off(CMD_UNMUTE_CONVERSATION, this.unmute);
bus.$off(CMD_SEND_TRANSCRIPT, this.toggleEmailActionsModal);
this.$emitter.off(CMD_MUTE_CONVERSATION, this.mute);
this.$emitter.off(CMD_UNMUTE_CONVERSATION, this.unmute);
this.$emitter.off(CMD_SEND_TRANSCRIPT, this.toggleEmailActionsModal);
},
methods: {
mute() {
@@ -596,12 +596,15 @@ export default {
);
this.fetchAndSetReplyTo();
bus.$on(BUS_EVENTS.TOGGLE_REPLY_TO_MESSAGE, this.fetchAndSetReplyTo);
this.$emitter.on(
BUS_EVENTS.TOGGLE_REPLY_TO_MESSAGE,
this.fetchAndSetReplyTo
);
// A hacky fix to solve the drag and drop
// Is showing on top of new conversation modal drag and drop
// TODO need to find a better solution
bus.$on(
this.$emitter.on(
BUS_EVENTS.NEW_CONVERSATION_MODAL,
this.onNewConversationModalActive
);
@@ -609,10 +612,13 @@ export default {
destroyed() {
document.removeEventListener('paste', this.onPaste);
document.removeEventListener('keydown', this.handleKeyEvents);
bus.$off(BUS_EVENTS.TOGGLE_REPLY_TO_MESSAGE, this.fetchAndSetReplyTo);
this.$emitter.off(
BUS_EVENTS.TOGGLE_REPLY_TO_MESSAGE,
this.fetchAndSetReplyTo
);
},
beforeDestroy() {
bus.$off(
this.$emitter.off(
BUS_EVENTS.NEW_CONVERSATION_MODAL,
this.onNewConversationModalActive
);
@@ -625,7 +631,7 @@ export default {
const lines = title.split('\n');
const nonEmptyLines = lines.filter(line => line.trim() !== '');
const filteredMarkdown = nonEmptyLines.join(' ');
bus.$emit(
this.$emitter.emit(
BUS_EVENTS.INSERT_INTO_RICH_EDITOR,
`[${filteredMarkdown}](${url})`
);
@@ -867,8 +873,8 @@ export default {
'createPendingMessageAndSend',
messagePayload
);
bus.$emit(BUS_EVENTS.SCROLL_TO_MESSAGE);
bus.$emit(BUS_EVENTS.MESSAGE_SENT);
this.$emitter.emit(BUS_EVENTS.SCROLL_TO_MESSAGE);
this.$emitter.emit(BUS_EVENTS.MESSAGE_SENT);
this.removeFromDraft();
this.sendMessageAnalyticsData(messagePayload.private);
} catch (error) {
@@ -1194,7 +1200,7 @@ export default {
resetReplyToMessage() {
const replyStorageKey = LOCAL_STORAGE_KEYS.MESSAGE_REPLY_TO;
LocalStorage.deleteFromJsonStore(replyStorageKey, this.conversationId);
bus.$emit(BUS_EVENTS.TOGGLE_REPLY_TO_MESSAGE);
this.$emitter.emit(BUS_EVENTS.TOGGLE_REPLY_TO_MESSAGE);
},
onNewConversationModalActive(isActive) {
// Issue is if the new conversation modal is open and we drag and drop the file
@@ -47,7 +47,9 @@ export default {
},
methods: {
scrollToMessage() {
bus.$emit(BUS_EVENTS.SCROLL_TO_MESSAGE, { messageId: this.message.id });
this.$emitter.emit(BUS_EVENTS.SCROLL_TO_MESSAGE, {
messageId: this.message.id,
});
},
},
};
@@ -167,17 +167,29 @@ export default {
};
},
mounted() {
bus.$on(CMD_BULK_ACTION_SNOOZE_CONVERSATION, this.onCmdSnoozeConversation);
bus.$on(CMD_BULK_ACTION_REOPEN_CONVERSATION, this.onCmdReopenConversation);
bus.$on(
this.$emitter.on(
CMD_BULK_ACTION_SNOOZE_CONVERSATION,
this.onCmdSnoozeConversation
);
this.$emitter.on(
CMD_BULK_ACTION_REOPEN_CONVERSATION,
this.onCmdReopenConversation
);
this.$emitter.on(
CMD_BULK_ACTION_RESOLVE_CONVERSATION,
this.onCmdResolveConversation
);
},
destroyed() {
bus.$off(CMD_BULK_ACTION_SNOOZE_CONVERSATION, this.onCmdSnoozeConversation);
bus.$off(CMD_BULK_ACTION_REOPEN_CONVERSATION, this.onCmdReopenConversation);
bus.$off(
this.$emitter.off(
CMD_BULK_ACTION_SNOOZE_CONVERSATION,
this.onCmdSnoozeConversation
);
this.$emitter.off(
CMD_BULK_ACTION_REOPEN_CONVERSATION,
this.onCmdReopenConversation
);
this.$emitter.off(
CMD_BULK_ACTION_RESOLVE_CONVERSATION,
this.onCmdResolveConversation
);
@@ -109,8 +109,6 @@ const onSearch = async value => {
issues.value = response.data.map(issue => ({
id: issue.id,
name: `${issue.identifier} ${issue.title}`,
leftIcon: 'status',
leftIconColor: issue.state.color,
}));
} catch (error) {
const errorMessage = parseLinearAPIErrorResponse(
@@ -2,12 +2,21 @@ import { createLocalVue, mount } from '@vue/test-utils';
import Vuex from 'vuex';
import VueI18n from 'vue-i18n';
import VTooltip from 'v-tooltip';
import Button from 'dashboard/components/buttons/Button';
import i18n from 'dashboard/i18n';
import FluentIcon from 'shared/components/FluentIcon/DashboardIcon';
import MoreActions from '../MoreActions';
jest.mock('shared/helpers/mitt', () => ({
emitter: {
emit: jest.fn(),
on: jest.fn(),
off: jest.fn(),
},
}));
import { emitter } from 'shared/helpers/mitt';
const localVue = createLocalVue();
localVue.use(Vuex);
localVue.use(VueI18n);
@@ -16,6 +25,12 @@ localVue.use(VTooltip);
localVue.component('fluent-icon', FluentIcon);
localVue.component('woot-button', Button);
localVue.prototype.$emitter = {
emit: jest.fn(),
on: jest.fn(),
off: jest.fn(),
};
const i18nConfig = new VueI18n({ locale: 'en', messages: i18n });
describe('MoveActions', () => {
@@ -29,12 +44,6 @@ describe('MoveActions', () => {
let moreActions = null;
beforeEach(() => {
window.bus = {
$emit: jest.fn(),
$on: jest.fn(),
$off: jest.fn(),
};
state = {
authenticated: true,
currentChat,
@@ -76,7 +85,7 @@ describe('MoveActions', () => {
it('shows alert', async () => {
await moreActions.find('button:first-child').trigger('click');
expect(window.bus.$emit).toBeCalledWith(
expect(emitter.emit).toBeCalledWith(
'newToastMessage',
'This contact is blocked successfully. You will not be notified of any future conversations.',
undefined
@@ -102,7 +111,7 @@ describe('MoveActions', () => {
it('shows alert', async () => {
await moreActions.find('button:first-child').trigger('click');
expect(window.bus.$emit).toBeCalledWith(
expect(emitter.emit).toBeCalledWith(
'newToastMessage',
'This contact is unblocked successfully.',
undefined
@@ -0,0 +1,101 @@
import { replaceVariablesInMessage } from '@chatwoot/utils';
import {
MessageMarkdownTransformer,
messageSchema,
} from '@chatwoot/prosemirror-schema';
/**
* Provides utility functions for creating special content nodes (mentions, canned responses, variables) in the editor state.
*
* @module useSpecialContent
* @returns {Object} - An object containing the `getContentNode` function.
*/
export default function useSpecialContent() {
/**
* Creates a mention node for the editor state
* @param {Object} editorView - The editor view instance
* @param {Object} content - The content object containing user id and name
* @param {number} from - The start position of the mention in the document
* @param {number} to - The end position of the mention in the document
* @returns {Object} - The created mention node and the updated from and to positions
*/
const getMentionNode = (editorView, content, from, to) => {
const node = editorView.state.schema.nodes.mention.create({
userId: content.id,
userFullName: content.name,
});
return { node, from, to };
};
/**
* Creates a canned response node for the editor state
* @param {Object} editorView - The editor view instance
* @param {string} content - The canned response content
* @param {number} from - The start position of the canned response in the document
* @param {number} to - The end position of the canned response in the document
* @param {Object} variables - The variables to replace in the canned response
* @returns {Object} - The created canned response node and the updated from and to positions
*/
const getCannedResponseNode = (editorView, content, from, to, variables) => {
const updatedMessage = replaceVariablesInMessage({
message: content,
variables,
});
const node = new MessageMarkdownTransformer(messageSchema).parse(
updatedMessage
);
from = node.textContent === updatedMessage ? from : from - 1;
return { node, from, to };
};
/**
* Creates a variable node for the editor state
* @param {Object} editorView - The editor view instance
* @param {string} content - The variable content
* @param {number} from - The start position of the variable in the document
* @param {number} to - The end position of the variable in the document
* @returns {Object} - The created variable node and the updated from and to positions
*/
const getVariableNode = (editorView, content, from, to) => {
const node = editorView.state.schema.text(`{{${content}}}`);
return { node, from, to };
};
/**
* Creates a content node based on the type (mention, canned response, or variable)
* @param {Object} editorView - The editor view instance
* @param {string} type - The type of content (mention, cannedResponse, or variable)
* @param {string|Object} content - The content to create the node from
* @param {Object} range - The range object containing the from and to positions
* @param {Object} variables - The variables to replace in the canned response (optional)
* @returns {Object} - The created content node and the updated from and to positions
*/
const getContentNode = (editorView, type, content, range, variables) => {
const methodMap = {
mention: getMentionNode,
cannedResponse: getCannedResponseNode,
variable: getVariableNode,
};
if (!methodMap[type]) {
return { node: null, from: range.from, to: range.to };
}
let { node, from, to } = methodMap[type](
editorView,
content,
range.from,
range.to,
variables
);
return { node, from, to };
};
return {
getContentNode,
};
}
@@ -1,4 +1,5 @@
import { getCurrentInstance } from 'vue';
import { emitter } from 'shared/helpers/mitt';
export const useTrack = () => {
const vm = getCurrentInstance();
@@ -8,5 +9,5 @@ export const useTrack = () => {
};
export function useAlert(message, action) {
bus.$emit('newToastMessage', message, action);
emitter.emit('newToastMessage', message, action);
}
@@ -0,0 +1,115 @@
import useSpecialContent from 'dashboard/composables/editor/useSpecialContent';
import {
MessageMarkdownTransformer,
messageSchema,
} from '@chatwoot/prosemirror-schema';
import { replaceVariablesInMessage } from '@chatwoot/utils';
jest.mock('@chatwoot/prosemirror-schema', () => ({
MessageMarkdownTransformer: jest.fn(),
messageSchema: {},
}));
jest.mock('@chatwoot/utils', () => ({
replaceVariablesInMessage: jest.fn(),
}));
describe('useSpecialContent', () => {
let editorView;
let specialContent;
beforeEach(() => {
editorView = {
state: {
schema: {
nodes: {
mention: {
create: jest.fn(),
},
},
text: jest.fn(),
},
},
};
specialContent = useSpecialContent();
});
describe('getMentionNode', () => {
it('should create a mention node', () => {
const content = { id: 1, name: 'John Doe' };
const from = 0;
const to = 10;
specialContent.getContentNode(editorView, 'mention', content, {
from,
to,
});
expect(editorView.state.schema.nodes.mention.create).toHaveBeenCalledWith(
{
userId: content.id,
userFullName: content.name,
}
);
});
});
describe('getCannedResponseNode', () => {
it('should create a canned response node', () => {
const content = 'Hello {{name}}';
const variables = { name: 'John' };
const from = 0;
const to = 10;
const updatedMessage = 'Hello John';
replaceVariablesInMessage.mockReturnValue(updatedMessage);
MessageMarkdownTransformer.mockImplementation(() => ({
parse: jest.fn().mockReturnValue({ textContent: updatedMessage }),
}));
const { node } = specialContent.getContentNode(
editorView,
'cannedResponse',
content,
{ from, to },
variables
);
expect(replaceVariablesInMessage).toHaveBeenCalledWith({
message: content,
variables,
});
expect(MessageMarkdownTransformer).toHaveBeenCalledWith(messageSchema);
expect(node.textContent).toBe(updatedMessage);
});
});
describe('getVariableNode', () => {
it('should create a variable node', () => {
const content = 'name';
const from = 0;
const to = 10;
specialContent.getContentNode(editorView, 'variable', content, {
from,
to,
});
expect(editorView.state.schema.text).toHaveBeenCalledWith('{{name}}');
});
});
describe('getContentNode', () => {
it('should return null for invalid type', () => {
const content = 'invalid';
const from = 0;
const to = 10;
const { node } = specialContent.getContentNode(
editorView,
'invalid',
content,
{ from, to }
);
expect(node).toBeNull();
});
});
});
@@ -1,6 +1,7 @@
import AuthAPI from '../api/auth';
import BaseActionCableConnector from '../../shared/helpers/BaseActionCableConnector';
import DashboardAudioNotificationHelper from './AudioAlerts/DashboardAudioNotificationHelper';
import { emitter } from 'shared/helpers/mitt';
class ActionCableConnector extends BaseActionCableConnector {
constructor(app, pubsubToken) {
@@ -177,8 +178,8 @@ class ActionCableConnector extends BaseActionCableConnector {
// eslint-disable-next-line class-methods-use-this
fetchConversationStats = () => {
bus.$emit('fetch_conversation_stats');
bus.$emit('fetch_overview_reports');
emitter.emit('fetch_conversation_stats');
emitter.emit('fetch_overview_reports');
};
onContactDelete = data => {
@@ -207,7 +208,7 @@ class ActionCableConnector extends BaseActionCableConnector {
// eslint-disable-next-line class-methods-use-this
onFirstReplyCreated = () => {
bus.$emit('fetch_overview_reports');
emitter.emit('fetch_overview_reports');
};
onCacheInvalidate = data => {
@@ -2,7 +2,10 @@ import {
messageSchema,
MessageMarkdownTransformer,
MessageMarkdownSerializer,
buildEditor,
EditorState,
} from '@chatwoot/prosemirror-schema';
import * as Sentry from '@sentry/browser';
/**
@@ -281,3 +284,24 @@ export function setURLWithQueryAndSize(selectedImageNode, size, editorView) {
}
}
}
export const createState = (
content,
placeholder,
// eslint-disable-next-line default-param-last
plugins = [],
// eslint-disable-next-line default-param-last
methods = {},
enabledMenuOptions
) => {
return EditorState.create({
doc: new MessageMarkdownTransformer(messageSchema).parse(content),
plugins: buildEditor({
schema: messageSchema,
placeholder,
methods,
plugins,
enabledMenuOptions,
}),
});
};
@@ -1,6 +1,7 @@
/* eslint-disable no-console */
import NotificationSubscriptions from '../api/notificationSubscription';
import auth from '../api/auth';
import { emitter } from 'shared/helpers/mitt';
export const verifyServiceWorkerExistence = (callback = () => {}) => {
if (!('serviceWorker' in navigator)) {
@@ -68,7 +69,7 @@ export const registerSubscription = (onSuccess = () => {}) => {
onSuccess();
})
.catch(() => {
window.bus.$emit(
emitter.emit(
'newToastMessage',
'This browser does not support desktop notification'
);
@@ -77,7 +78,7 @@ export const registerSubscription = (onSuccess = () => {}) => {
export const requestPushPermissions = ({ onSuccess }) => {
if (!('Notification' in window)) {
window.bus.$emit(
emitter.emit(
'newToastMessage',
'This browser does not support desktop notification'
);
@@ -1,5 +1,6 @@
import AnalyticsHelper from './AnalyticsHelper';
import DashboardAudioNotificationHelper from './AudioAlerts/DashboardAudioNotificationHelper';
import { emitter } from 'shared/helpers/mitt';
export const CHATWOOT_SET_USER = 'CHATWOOT_SET_USER';
export const CHATWOOT_RESET = 'CHATWOOT_RESET';
@@ -8,7 +9,7 @@ export const ANALYTICS_IDENTITY = 'ANALYTICS_IDENTITY';
export const ANALYTICS_RESET = 'ANALYTICS_RESET';
export const initializeAnalyticsEvents = () => {
window.bus.$on(ANALYTICS_IDENTITY, ({ user }) => {
emitter.on(ANALYTICS_IDENTITY, ({ user }) => {
AnalyticsHelper.identify(user);
});
};
@@ -34,12 +35,12 @@ const initializeAudioAlerts = user => {
};
export const initializeChatwootEvents = () => {
window.bus.$on(CHATWOOT_RESET, () => {
emitter.on(CHATWOOT_RESET, () => {
if (window.$chatwoot) {
window.$chatwoot.reset();
}
});
window.bus.$on(CHATWOOT_SET_USER, ({ user }) => {
emitter.on(CHATWOOT_SET_USER, ({ user }) => {
if (window.$chatwoot) {
window.$chatwoot.setUser(user.email, {
avatar_url: user.avatar_url,
@@ -366,6 +366,7 @@
"TITLE": "Microsoft Email",
"DESCRIPTION": "Click on the Sign in with Microsoft button to get started. You will redirected to the email sign in page. Once you accept the requested permissions, you would be redirected back to the inbox creation step.",
"EMAIL_PLACEHOLDER": "Enter email address",
"SIGN_IN": "Sign in with Microsoft",
"HELP": "To add your Microsoft account as a channel, you need to authenticate your Microsoft account by clicking on 'Sign in with Microsoft' ",
"ERROR_MESSAGE": "There was an error connecting to Microsoft, please try again"
}
@@ -738,4 +739,4 @@
"OTHER_PROVIDERS": "Other Providers"
}
}
}
}
@@ -110,11 +110,11 @@ export default {
mounted() {
this.handleResize();
window.addEventListener('resize', this.handleResize);
bus.$on(BUS_EVENTS.TOGGLE_SIDEMENU, this.toggleSidebar);
this.$emitter.on(BUS_EVENTS.TOGGLE_SIDEMENU, this.toggleSidebar);
},
beforeDestroy() {
window.removeEventListener('resize', this.handleResize);
bus.$off(BUS_EVENTS.TOGGLE_SIDEMENU, this.toggleSidebar);
this.$emitter.off(BUS_EVENTS.TOGGLE_SIDEMENU, this.toggleSidebar);
},
methods: {
@@ -11,6 +11,7 @@ import {
ICON_REOPEN_CONVERSATION,
ICON_RESOLVE_CONVERSATION,
} from './CommandBarIcons';
import { emitter } from 'shared/helpers/mitt';
import { createSnoozeHandlers } from './commandBarActions';
@@ -37,7 +38,7 @@ export const RESOLVED_CONVERSATION_BULK_ACTIONS = [
title: 'COMMAND_BAR.COMMANDS.REOPEN_CONVERSATION',
section: 'COMMAND_BAR.SECTIONS.BULK_ACTIONS',
icon: ICON_REOPEN_CONVERSATION,
handler: () => bus.$emit(CMD_BULK_ACTION_REOPEN_CONVERSATION),
handler: () => emitter.emit(CMD_BULK_ACTION_REOPEN_CONVERSATION),
},
];
@@ -47,7 +48,7 @@ export const OPEN_CONVERSATION_BULK_ACTIONS = [
title: 'COMMAND_BAR.COMMANDS.RESOLVE_CONVERSATION',
section: 'COMMAND_BAR.SECTIONS.BULK_ACTIONS',
icon: ICON_RESOLVE_CONVERSATION,
handler: () => bus.$emit(CMD_BULK_ACTION_RESOLVE_CONVERSATION),
handler: () => emitter.emit(CMD_BULK_ACTION_RESOLVE_CONVERSATION),
},
];
@@ -1,4 +1,5 @@
import wootConstants from 'dashboard/constants/globals';
import { emitter } from 'shared/helpers/mitt';
import {
CMD_MUTE_CONVERSATION,
@@ -26,7 +27,7 @@ export const OPEN_CONVERSATION_ACTIONS = [
title: 'COMMAND_BAR.COMMANDS.RESOLVE_CONVERSATION',
section: 'COMMAND_BAR.SECTIONS.CONVERSATION',
icon: ICON_RESOLVE_CONVERSATION,
handler: () => bus.$emit(CMD_RESOLVE_CONVERSATION),
handler: () => emitter.emit(CMD_RESOLVE_CONVERSATION),
},
];
@@ -37,7 +38,7 @@ export const createSnoozeHandlers = (busEventName, parentId, section) => {
parent: parentId,
section: section,
icon: ICON_SNOOZE_CONVERSATION,
handler: () => bus.$emit(busEventName, option),
handler: () => emitter.emit(busEventName, option),
}));
};
@@ -61,7 +62,7 @@ export const RESOLVED_CONVERSATION_ACTIONS = [
title: 'COMMAND_BAR.COMMANDS.REOPEN_CONVERSATION',
section: 'COMMAND_BAR.SECTIONS.CONVERSATION',
icon: ICON_REOPEN_CONVERSATION,
handler: () => bus.$emit(CMD_REOPEN_CONVERSATION),
handler: () => emitter.emit(CMD_REOPEN_CONVERSATION),
},
];
@@ -70,7 +71,7 @@ export const SEND_TRANSCRIPT_ACTION = {
title: 'COMMAND_BAR.COMMANDS.SEND_TRANSCRIPT',
section: 'COMMAND_BAR.SECTIONS.CONVERSATION',
icon: ICON_SEND_TRANSCRIPT,
handler: () => bus.$emit(CMD_SEND_TRANSCRIPT),
handler: () => emitter.emit(CMD_SEND_TRANSCRIPT),
};
export const UNMUTE_ACTION = {
@@ -78,7 +79,7 @@ export const UNMUTE_ACTION = {
title: 'COMMAND_BAR.COMMANDS.UNMUTE_CONVERSATION',
section: 'COMMAND_BAR.SECTIONS.CONVERSATION',
icon: ICON_UNMUTE_CONVERSATION,
handler: () => bus.$emit(CMD_UNMUTE_CONVERSATION),
handler: () => emitter.emit(CMD_UNMUTE_CONVERSATION),
};
export const MUTE_ACTION = {
@@ -86,5 +87,5 @@ export const MUTE_ACTION = {
title: 'COMMAND_BAR.COMMANDS.MUTE_CONVERSATION',
section: 'COMMAND_BAR.SECTIONS.CONVERSATION',
icon: ICON_MUTE_CONVERSATION,
handler: () => bus.$emit(CMD_MUTE_CONVERSATION),
handler: () => emitter.emit(CMD_MUTE_CONVERSATION),
};
@@ -1,5 +1,6 @@
import { mapGetters } from 'vuex';
import wootConstants from 'dashboard/constants/globals';
import { emitter } from 'shared/helpers/mitt';
import { CMD_AI_ASSIST } from './commandBarBusEvents';
import { REPLY_EDITOR_MODES } from 'dashboard/components/widgets/WootWriter/constants';
@@ -318,7 +319,7 @@ export default {
section: this.$t('COMMAND_BAR.SECTIONS.AI_ASSIST'),
priority: item,
icon: item.icon,
handler: () => bus.$emit(CMD_AI_ASSIST, item.key),
handler: () => emitter.emit(CMD_AI_ASSIST, item.key),
}));
return [
{
@@ -2,6 +2,7 @@ import wootConstants from 'dashboard/constants/globals';
import { CMD_SNOOZE_NOTIFICATION } from './commandBarBusEvents';
import { ICON_SNOOZE_NOTIFICATION } from './CommandBarIcons';
import { emitter } from 'shared/helpers/mitt';
import { isAInboxViewRoute } from 'dashboard/helper/routeHelpers';
@@ -21,7 +22,7 @@ const INBOX_SNOOZE_EVENTS = [
section: 'COMMAND_BAR.SECTIONS.SNOOZE_NOTIFICATION',
icon: ICON_SNOOZE_NOTIFICATION,
handler: () =>
bus.$emit(CMD_SNOOZE_NOTIFICATION, SNOOZE_OPTIONS.AN_HOUR_FROM_NOW),
emitter.emit(CMD_SNOOZE_NOTIFICATION, SNOOZE_OPTIONS.AN_HOUR_FROM_NOW),
},
{
id: SNOOZE_OPTIONS.UNTIL_TOMORROW,
@@ -30,7 +31,7 @@ const INBOX_SNOOZE_EVENTS = [
parent: 'snooze_notification',
icon: ICON_SNOOZE_NOTIFICATION,
handler: () =>
bus.$emit(CMD_SNOOZE_NOTIFICATION, SNOOZE_OPTIONS.UNTIL_TOMORROW),
emitter.emit(CMD_SNOOZE_NOTIFICATION, SNOOZE_OPTIONS.UNTIL_TOMORROW),
},
{
id: SNOOZE_OPTIONS.UNTIL_NEXT_WEEK,
@@ -39,7 +40,7 @@ const INBOX_SNOOZE_EVENTS = [
parent: 'snooze_notification',
icon: ICON_SNOOZE_NOTIFICATION,
handler: () =>
bus.$emit(CMD_SNOOZE_NOTIFICATION, SNOOZE_OPTIONS.UNTIL_NEXT_WEEK),
emitter.emit(CMD_SNOOZE_NOTIFICATION, SNOOZE_OPTIONS.UNTIL_NEXT_WEEK),
},
{
id: SNOOZE_OPTIONS.UNTIL_NEXT_MONTH,
@@ -48,7 +49,7 @@ const INBOX_SNOOZE_EVENTS = [
parent: 'snooze_notification',
icon: ICON_SNOOZE_NOTIFICATION,
handler: () =>
bus.$emit(CMD_SNOOZE_NOTIFICATION, SNOOZE_OPTIONS.UNTIL_NEXT_MONTH),
emitter.emit(CMD_SNOOZE_NOTIFICATION, SNOOZE_OPTIONS.UNTIL_NEXT_MONTH),
},
{
id: SNOOZE_OPTIONS.UNTIL_CUSTOM_TIME,
@@ -57,7 +58,7 @@ const INBOX_SNOOZE_EVENTS = [
parent: 'snooze_notification',
icon: ICON_SNOOZE_NOTIFICATION,
handler: () =>
bus.$emit(CMD_SNOOZE_NOTIFICATION, SNOOZE_OPTIONS.UNTIL_CUSTOM_TIME),
emitter.emit(CMD_SNOOZE_NOTIFICATION, SNOOZE_OPTIONS.UNTIL_CUSTOM_TIME),
},
];
export default {
@@ -19,12 +19,12 @@ const initiatedAt = computed(
() => props.conversationAttributes.initiated_at?.timestamp
);
const browserInfo = props.conversationAttributes.browser;
const browserInfo = computed(() => props.conversationAttributes.browser);
const browserName = computed(() => {
if (!browserInfo) return '';
if (!browserInfo.value) return '';
const { browser_name: name = '', browser_version: version = '' } =
browserInfo;
browserInfo.value;
return `${name} ${version}`;
});
@@ -33,9 +33,9 @@ const browserLanguage = computed(() =>
);
const platformName = computed(() => {
if (!browserInfo) return '';
if (!browserInfo.value) return '';
const { platform_name: name = '', platform_version: version = '' } =
browserInfo;
browserInfo.value;
return `${name} ${version}`;
});
@@ -169,7 +169,7 @@ export default {
after: messageId,
})
.then(() => {
bus.$emit(BUS_EVENTS.SCROLL_TO_MESSAGE, { messageId });
this.$emitter.emit(BUS_EVENTS.SCROLL_TO_MESSAGE, { messageId });
});
} else {
this.$store.dispatch('clearSelectedState');
@@ -271,7 +271,10 @@ export default {
},
toggleConversationModal() {
this.showConversationModal = !this.showConversationModal;
bus.$emit(BUS_EVENTS.NEW_CONVERSATION_MODAL, this.showConversationModal);
this.$emitter.emit(
BUS_EVENTS.NEW_CONVERSATION_MODAL,
this.showConversationModal
);
},
toggleDeleteModal() {
this.showDeleteModal = !this.showDeleteModal;
@@ -265,7 +265,7 @@ export default {
},
mounted() {
bus.$on(BUS_EVENTS.TOGGLE_SIDEMENU, this.toggleSidebar);
this.$emitter.on(BUS_EVENTS.TOGGLE_SIDEMENU, this.toggleSidebar);
const slug = this.$route.params.portalSlug;
if (slug) this.lastActivePortalSlug = slug;
@@ -273,7 +273,7 @@ export default {
this.fetchPortalAndItsCategories();
},
beforeDestroy() {
bus.$off(BUS_EVENTS.TOGGLE_SIDEMENU, this.toggleSidebar);
this.$emitter.off(BUS_EVENTS.TOGGLE_SIDEMENU, this.toggleSidebar);
},
updated() {
const slug = this.$route.params.portalSlug;
@@ -140,7 +140,7 @@ export default {
this.$store
.dispatch('setActiveChat', { data: selectedConversation })
.then(() => {
bus.$emit(BUS_EVENTS.SCROLL_TO_MESSAGE);
this.$emitter.emit(BUS_EVENTS.SCROLL_TO_MESSAGE);
});
},
findConversation() {
@@ -92,10 +92,10 @@ export default {
...mapGetters({ meta: 'notifications/getMeta' }),
},
mounted() {
bus.$on(CMD_SNOOZE_NOTIFICATION, this.onCmdSnoozeNotification);
this.$emitter.on(CMD_SNOOZE_NOTIFICATION, this.onCmdSnoozeNotification);
},
destroyed() {
bus.$off(CMD_SNOOZE_NOTIFICATION, this.onCmdSnoozeNotification);
this.$emitter.off(CMD_SNOOZE_NOTIFICATION, this.onCmdSnoozeNotification);
},
methods: {
openSnoozeNotificationModal() {
@@ -69,8 +69,10 @@
<script>
import { required, minLength, email } from 'vuelidate/lib/validators';
import { mapGetters } from 'vuex';
import alertMixin from 'shared/mixins/alertMixin';
export default {
mixins: [alertMixin],
props: {
onClose: {
type: Function,
@@ -117,9 +119,6 @@ export default {
},
methods: {
showAlert(message) {
bus.$emit('newToastMessage', message);
},
async addAgent() {
try {
await this.$store.dispatch('agents/create', {
@@ -83,6 +83,7 @@ import WootSubmitButton from '../../../../components/buttons/FormSubmitButton.vu
import Modal from '../../../../components/Modal.vue';
import Auth from '../../../../api/auth';
import wootConstants from 'dashboard/constants/globals';
import alertMixin from 'shared/mixins/alertMixin';
const { AVAILABILITY_STATUS_KEYS } = wootConstants;
@@ -91,6 +92,7 @@ export default {
WootSubmitButton,
Modal,
},
mixins: [alertMixin],
props: {
id: {
type: Number,
@@ -169,9 +171,6 @@ export default {
},
},
methods: {
showAlert(message) {
bus.$emit('newToastMessage', message);
},
async editAgent() {
try {
await this.$store.dispatch('agents/update', {
@@ -130,6 +130,7 @@ import globalConfigMixin from 'shared/mixins/globalConfigMixin';
import Thumbnail from '../../../../components/widgets/Thumbnail.vue';
import AddAgent from './AddAgent.vue';
import EditAgent from './EditAgent.vue';
import alertMixin from 'shared/mixins/alertMixin';
export default {
components: {
@@ -137,7 +138,7 @@ export default {
EditAgent,
Thumbnail,
},
mixins: [globalConfigMixin],
mixins: [globalConfigMixin, alertMixin],
data() {
return {
loading: {},
@@ -230,19 +231,19 @@ export default {
async deleteAgent(id) {
try {
await this.$store.dispatch('agents/delete', id);
this.showAlert(this.$t('AGENT_MGMT.DELETE.API.SUCCESS_MESSAGE'));
this.showAlertMessage(this.$t('AGENT_MGMT.DELETE.API.SUCCESS_MESSAGE'));
} catch (error) {
this.showAlert(this.$t('AGENT_MGMT.DELETE.API.ERROR_MESSAGE'));
this.showAlertMessage(this.$t('AGENT_MGMT.DELETE.API.ERROR_MESSAGE'));
}
},
// Show SnackBar
showAlert(message) {
showAlertMessage(message) {
// Reset loading, current selected agent
this.loading[this.currentAgent.id] = false;
this.currentAgent = {};
// Show message
this.agentAPI.message = message;
bus.$emit('newToastMessage', message);
this.showAlert(message);
},
},
};
@@ -132,12 +132,14 @@
import { mapGetters } from 'vuex';
import AddCanned from './AddCanned.vue';
import EditCanned from './EditCanned.vue';
import alertMixin from 'shared/mixins/alertMixin';
export default {
components: {
AddCanned,
EditCanned,
},
mixins: [alertMixin],
data() {
return {
loading: {},
@@ -187,13 +189,13 @@ export default {
});
this.sortOrder = this.sortOrder === 'asc' ? 'desc' : 'asc';
},
showAlert(message) {
showAlertMessage(message) {
// Reset loading, current selected agent
this.loading[this.selectedResponse.id] = false;
this.selectedResponse = {};
// Show message
this.cannedResponseAPI.message = message;
bus.$emit('newToastMessage', message);
this.showAlert(message);
},
// Edit Function
openAddPopup() {
@@ -230,12 +232,14 @@ export default {
this.$store
.dispatch('deleteCannedResponse', id)
.then(() => {
this.showAlert(this.$t('CANNED_MGMT.DELETE.API.SUCCESS_MESSAGE'));
this.showAlertMessage(
this.$t('CANNED_MGMT.DELETE.API.SUCCESS_MESSAGE')
);
})
.catch(error => {
const errorMessage =
error?.message || this.$t('CANNED_MGMT.DELETE.API.ERROR_MESSAGE');
this.showAlert(errorMessage);
this.showAlertMessage(errorMessage);
});
},
},
@@ -51,11 +51,13 @@ import { mapGetters } from 'vuex';
import InboxMembersAPI from '../../../../api/inboxMembers';
import router from '../../../index';
import PageHeader from '../SettingsSubPageHeader.vue';
import alertMixin from 'shared/mixins/alertMixin';
export default {
components: {
PageHeader,
},
mixins: [alertMixin],
validations: {
selectedAgents: {
@@ -98,7 +100,7 @@ export default {
},
});
} catch (error) {
bus.$emit('newToastMessage', error.message);
this.showAlert(error.message);
}
this.isCreating = false;
},
@@ -136,12 +136,13 @@ import Settings from './Settings.vue';
import adminMixin from '../../../../mixins/isAdmin';
import accountMixin from '../../../../mixins/account';
import globalConfigMixin from 'shared/mixins/globalConfigMixin';
import alertMixin from 'shared/mixins/alertMixin';
export default {
components: {
Settings,
},
mixins: [adminMixin, accountMixin, globalConfigMixin],
mixins: [adminMixin, accountMixin, globalConfigMixin, alertMixin],
data() {
return {
loading: {},
@@ -194,15 +195,9 @@ export default {
async deleteInbox({ id }) {
try {
await this.$store.dispatch('inboxes/delete', id);
bus.$emit(
'newToastMessage',
this.$t('INBOX_MGMT.DELETE.API.SUCCESS_MESSAGE')
);
this.showAlert(this.$t('INBOX_MGMT.DELETE.API.SUCCESS_MESSAGE'));
} catch (error) {
bus.$emit(
'newToastMessage',
this.$t('INBOX_MGMT.DELETE.API.ERROR_MESSAGE')
);
this.showAlert(this.$t('INBOX_MGMT.DELETE.API.ERROR_MESSAGE'));
}
},
@@ -18,8 +18,8 @@
/>
<woot-submit-button
icon="brand-twitter"
button-text="Sign in with Microsoft"
type="submit"
:button-text="$t('INBOX_MGMT.ADD.MICROSOFT.SIGN_IN')"
:loading="isRequestingAuthorization"
/>
</form>
@@ -128,7 +128,7 @@ export default {
this.$store.dispatch('agents/get');
this.fetchAllData();
bus.$on('fetch_overview_reports', () => {
this.$emitter.on('fetch_overview_reports', () => {
this.fetchAllData();
});
},
@@ -6,6 +6,7 @@ import { findPendingMessageIndex } from './helpers';
import { MESSAGE_STATUS } from 'shared/constants/messages';
import wootConstants from 'dashboard/constants/globals';
import { BUS_EVENTS } from '../../../../shared/constants/busEvents';
import { emitter } from 'shared/helpers/mitt';
const state = {
allConversations: [],
@@ -195,8 +196,8 @@ export const mutations = {
const { conversation: { unread_count: unreadCount = 0 } = {} } = message;
chat.unread_count = unreadCount;
if (selectedChatId === conversationId) {
window.bus.$emit(BUS_EVENTS.FETCH_LABEL_SUGGESTIONS);
window.bus.$emit(BUS_EVENTS.SCROLL_TO_MESSAGE);
emitter.emit(BUS_EVENTS.FETCH_LABEL_SUGGESTIONS);
emitter.emit(BUS_EVENTS.SCROLL_TO_MESSAGE);
}
}
},
@@ -218,8 +219,8 @@ export const mutations = {
};
Vue.set(allConversations, currentConversationIndex, currentConversation);
if (_state.selectedChatId === conversation.id) {
window.bus.$emit(BUS_EVENTS.FETCH_LABEL_SUGGESTIONS);
window.bus.$emit(BUS_EVENTS.SCROLL_TO_MESSAGE);
emitter.emit(BUS_EVENTS.FETCH_LABEL_SUGGESTIONS);
emitter.emit(BUS_EVENTS.SCROLL_TO_MESSAGE);
}
} else {
_state.allConversations.push(conversation);
@@ -1,6 +1,16 @@
import types from '../../../mutation-types';
import { mutations } from '../../conversations';
jest.mock('shared/helpers/mitt', () => ({
emitter: {
emit: jest.fn(),
on: jest.fn(),
off: jest.fn(),
},
}));
import { emitter } from 'shared/helpers/mitt';
describe('#mutations', () => {
describe('#EMPTY_ALL_CONVERSATION', () => {
it('empty conversations', () => {
@@ -130,7 +140,7 @@ describe('#mutations', () => {
timestamp: 1602256198,
},
]);
expect(global.bus.$emit).not.toHaveBeenCalled();
expect(emitter.emit).not.toHaveBeenCalled();
});
it('add message to the conversation and emit scrollToMessage if it does not exist in the store', () => {
@@ -158,7 +168,7 @@ describe('#mutations', () => {
timestamp: 1602256198,
},
]);
expect(global.bus.$emit).toHaveBeenCalledWith('SCROLL_TO_MESSAGE');
expect(emitter.emit).toHaveBeenCalledWith('SCROLL_TO_MESSAGE');
});
it('update message if it exist in the store', () => {
@@ -195,7 +205,7 @@ describe('#mutations', () => {
],
},
]);
expect(global.bus.$emit).not.toHaveBeenCalled();
expect(emitter.emit).not.toHaveBeenCalled();
});
});
+5 -4
View File
@@ -9,6 +9,7 @@ import {
} from '../../helper/scriptHelpers';
import { LOCAL_STORAGE_KEYS } from 'dashboard/constants/localStorage';
import { LocalStorage } from 'shared/helpers/localStorage';
import { emitter } from 'shared/helpers/mitt';
Cookies.defaults = { sameSite: 'Lax' };
@@ -18,8 +19,8 @@ export const setLoadingStatus = (state, status) => {
};
export const setUser = user => {
window.bus.$emit(CHATWOOT_SET_USER, { user });
window.bus.$emit(ANALYTICS_IDENTITY, { user });
emitter.emit(CHATWOOT_SET_USER, { user });
emitter.emit(ANALYTICS_IDENTITY, { user });
};
export const getHeaderExpiry = response =>
@@ -70,8 +71,8 @@ export const deleteIndexedDBOnLogout = async () => {
};
export const clearCookiesOnLogout = () => {
window.bus.$emit(CHATWOOT_RESET);
window.bus.$emit(ANALYTICS_RESET);
emitter.emit(CHATWOOT_RESET);
emitter.emit(ANALYTICS_RESET);
clearBrowserSessionCookies();
clearLocalStorageOnLogout();
const globalConfig = window.globalConfig || {};
+4 -1
View File
@@ -15,6 +15,8 @@ import WootUiKit from '../dashboard/components';
import App from '../dashboard/App';
import i18n from '../dashboard/i18n';
import createAxios from '../dashboard/helper/APIHelper';
import { emitter } from '../shared/helpers/mitt';
import commonHelpers, { isJSONValid } from '../dashboard/helper/commons';
import router, { initalizeRouter } from '../dashboard/routes';
import store from '../dashboard/store';
@@ -93,7 +95,8 @@ commonHelpers();
window.WootConstants = constants;
window.axios = createAxios(axios);
window.bus = new Vue();
Vue.prototype.$emitter = emitter;
initializeChatwootEvents();
initializeAnalyticsEvents();
initalizeRouter();
+2 -1
View File
@@ -4,6 +4,7 @@ import VueI18n from 'vue-i18n';
import App from '../survey/App.vue';
import i18n from '../survey/i18n';
import store from '../survey/store';
import { emitter } from 'shared/helpers/mitt';
Vue.use(VueI18n);
Vue.use(Vuelidate);
@@ -14,7 +15,7 @@ const i18nConfig = new VueI18n({
});
// Event Bus
window.bus = new Vue();
Vue.prototype.$emitter = emitter;
Vue.config.productionTip = false;
+2 -2
View File
@@ -13,7 +13,7 @@ import {
} from 'shared/helpers/Validators';
import router from '../widget/router';
import { directive as onClickaway } from 'vue-clickaway';
import { emitter } from 'shared/helpers/mitt';
import { domPurifyConfig } from '../shared/helpers/HTMLSanitizer';
const PhoneInput = () => import('../widget/components/Form/PhoneInput');
@@ -46,7 +46,7 @@ Vue.use(VueFormulate, {
},
});
// Event Bus
window.bus = new Vue();
Vue.prototype.$emitter = emitter;
Vue.config.productionTip = false;
@@ -1,5 +1,6 @@
import { createConsumer } from '@rails/actioncable';
import { BUS_EVENTS } from 'shared/constants/busEvents';
import { emitter } from 'shared/helpers/mitt';
const PRESENCE_INTERVAL = 20000;
const RECONNECT_INTERVAL = 1000;
@@ -28,7 +29,7 @@ class BaseActionCableConnector {
this.onDisconnected();
this.initReconnectTimer();
// TODO: Remove this after completing the conversation list refetching
window.bus.$emit(BUS_EVENTS.WEBSOCKET_DISCONNECT);
emitter.emit(BUS_EVENTS.WEBSOCKET_DISCONNECT);
},
}
);
+3
View File
@@ -0,0 +1,3 @@
import mitt from 'mitt';
const emitter = mitt();
export { emitter };
@@ -0,0 +1,25 @@
import { emitter } from '../mitt';
describe('emitter', () => {
it('should emit and listen to events correctly', () => {
const mockCallback = jest.fn();
// Subscribe to an event
emitter.on('event', mockCallback);
// Emit the event
emitter.emit('event', 'data');
// Expect the callback to be called with the correct data
expect(mockCallback).toHaveBeenCalledWith('data');
// Unsubscribe from the event
emitter.off('event', mockCallback);
// Emit the event again
emitter.emit('event', 'data');
// Expect the callback not to be called again
expect(mockCallback).toHaveBeenCalledTimes(1);
});
});
+3 -1
View File
@@ -1,7 +1,9 @@
import { emitter } from 'shared/helpers/mitt';
export default {
methods: {
showAlert(message, action) {
bus.$emit('newToastMessage', message, action);
emitter.emit('newToastMessage', message, action);
},
},
};
@@ -53,12 +53,14 @@ import FormInput from '../../../components/Form/Input.vue';
import SubmitButton from '../../../components/Button/SubmitButton.vue';
import { DEFAULT_REDIRECT_URL } from 'dashboard/constants/globals';
import { setNewPassword } from '../../../api/auth';
import alertMixin from 'shared/mixins/alertMixin';
export default {
components: {
FormInput,
SubmitButton,
},
mixins: [alertMixin],
props: {
resetPasswordToken: { type: String, default: '' },
redirectUrl: { type: String, default: '' },
@@ -105,10 +107,10 @@ export default {
},
},
methods: {
showAlert(message) {
showAlertMessage(message) {
// Reset loading, current selected agent
this.newPasswordAPI.showLoading = false;
bus.$emit('newToastMessage', message);
this.showAlert(message);
},
submitForm() {
this.newPasswordAPI.showLoading = true;
@@ -122,7 +124,7 @@ export default {
window.location = DEFAULT_REDIRECT_URL;
})
.catch(error => {
this.showAlert(
this.showAlertMessage(
error?.message || this.$t('SET_NEW_PASSWORD.API.ERROR_MESSAGE')
);
});
@@ -53,10 +53,11 @@ import { mapGetters } from 'vuex';
import FormInput from '../../../../components/Form/Input.vue';
import { resetPassword } from '../../../../api/auth';
import SubmitButton from '../../../../components/Button/SubmitButton.vue';
import alertMixin from 'shared/mixins/alertMixin';
export default {
components: { FormInput, SubmitButton },
mixins: [globalConfigMixin],
mixins: [globalConfigMixin, alertMixin],
data() {
return {
credentials: { email: '' },
@@ -80,10 +81,10 @@ export default {
},
},
methods: {
showAlert(message) {
showAlertMessage(message) {
// Reset loading, current selected agent
this.resetPassword.showLoading = false;
bus.$emit('newToastMessage', message);
this.showAlert(message);
},
submit() {
this.resetPassword.showLoading = true;
@@ -93,7 +94,7 @@ export default {
if (res.data && res.data.message) {
successMessage = res.data.message;
}
this.showAlert(successMessage);
this.showAlertMessage(successMessage);
})
.catch(error => {
let errorMessage = this.$t('RESET_PASSWORD.API.ERROR_MESSAGE');
+5 -4
View File
@@ -104,6 +104,7 @@ const ERROR_MESSAGES = {
'no-account-found': 'LOGIN.OAUTH.NO_ACCOUNT_FOUND',
'business-account-only': 'LOGIN.OAUTH.BUSINESS_ACCOUNTS_ONLY',
};
import alertMixin from 'shared/mixins/alertMixin';
export default {
components: {
@@ -112,7 +113,7 @@ export default {
Spinner,
SubmitButton,
},
mixins: [globalConfigMixin],
mixins: [globalConfigMixin, alertMixin],
props: {
ssoAuthToken: { type: String, default: '' },
ssoAccountId: { type: String, default: '' },
@@ -186,15 +187,15 @@ export default {
setTimeout(callback, 0);
}
},
showAlert(message) {
showAlertMessage(message) {
// Reset loading, current selected agent
this.loginApi.showLoading = false;
this.loginApi.message = message;
bus.$emit('newToastMessage', this.loginApi.message);
this.showAlert(this.loginApi.message);
},
submitLogin() {
if (this.$v.credentials.email.$invalid && !this.email) {
this.showAlert(this.$t('LOGIN.EMAIL.ERROR'));
this.showAlertMessage(this.$t('LOGIN.EMAIL.ERROR'));
return;
}
+9 -6
View File
@@ -43,6 +43,7 @@ import {
} from './constants/widgetBusEvents';
import darkModeMixin from 'widget/mixins/darkModeMixin';
import { SDK_SET_BUBBLE_VISIBILITY } from '../shared/constants/sharedFrameEvents';
import { emitter } from 'shared/helpers/mitt';
export default {
name: 'App',
@@ -157,34 +158,36 @@ export default {
}
},
registerUnreadEvents() {
bus.$on(ON_AGENT_MESSAGE_RECEIVED, () => {
emitter.on(ON_AGENT_MESSAGE_RECEIVED, () => {
const { name: routeName } = this.$route;
if ((this.isWidgetOpen || !this.isIFrame) && routeName === 'messages') {
this.$store.dispatch('conversation/setUserLastSeen');
}
this.setUnreadView();
});
bus.$on(ON_UNREAD_MESSAGE_CLICK, () => {
emitter.on(ON_UNREAD_MESSAGE_CLICK, () => {
this.replaceRoute('messages').then(() => this.unsetUnreadView());
});
},
registerCampaignEvents() {
bus.$on(ON_CAMPAIGN_MESSAGE_CLICK, () => {
emitter.on(ON_CAMPAIGN_MESSAGE_CLICK, () => {
if (this.shouldShowPreChatForm) {
this.replaceRoute('prechat-form');
} else {
this.replaceRoute('messages');
bus.$emit('execute-campaign', { campaignId: this.activeCampaign.id });
emitter.emit('execute-campaign', {
campaignId: this.activeCampaign.id,
});
}
this.unsetUnreadView();
});
bus.$on('execute-campaign', campaignDetails => {
emitter.on('execute-campaign', campaignDetails => {
const { customAttributes, campaignId } = campaignDetails;
const { websiteToken } = window.chatwootWebChannel;
this.executeCampaign({ campaignId, websiteToken, customAttributes });
this.replaceRoute('messages');
});
bus.$on('snooze-campaigns', () => {
emitter.on('snooze-campaigns', () => {
const expireBy = addHours(new Date(), 1);
this.campaignsSnoozedTill = Number(expireBy);
});
@@ -93,6 +93,7 @@ import { isASubmittedFormMessage } from 'shared/helpers/MessageTypeHelper';
import darkModeMixin from 'widget/mixins/darkModeMixin.js';
import ReplyToChip from 'widget/components/ReplyToChip.vue';
import { BUS_EVENTS } from 'shared/constants/busEvents';
import { emitter } from 'shared/helpers/mitt';
export default {
name: 'AgentMessage',
@@ -224,7 +225,7 @@ export default {
this.hasImageError = true;
},
toggleReply() {
bus.$emit(BUS_EVENTS.TOGGLE_REPLY_TO_MESSAGE, this.message);
emitter.emit(BUS_EVENTS.TOGGLE_REPLY_TO_MESSAGE, this.message);
},
},
};
+2 -1
View File
@@ -8,6 +8,7 @@
<script>
import { BUS_EVENTS } from 'shared/constants/busEvents';
import { emitter } from 'shared/helpers/mitt';
export default {
data() {
@@ -18,7 +19,7 @@ export default {
};
},
mounted() {
bus.$on(BUS_EVENTS.SHOW_ALERT, ({ message, type = 'error' }) => {
emitter.on(BUS_EVENTS.SHOW_ALERT, ({ message, type = 'error' }) => {
this.bannerMessage = message;
this.bannerType = type;
this.showBannerMessage = true;
@@ -96,7 +96,7 @@ export default {
upload.create((error, blob) => {
if (error) {
window.bus.$emit(BUS_EVENTS.SHOW_ALERT, {
this.$emitter.emit(BUS_EVENTS.SHOW_ALERT, {
message: error,
});
} else {
@@ -107,7 +107,7 @@ export default {
}
});
} else {
window.bus.$emit(BUS_EVENTS.SHOW_ALERT, {
this.$emitter.emit(BUS_EVENTS.SHOW_ALERT, {
message: this.$t('FILE_SIZE_LIMIT', {
MAXIMUM_FILE_UPLOAD_SIZE: this.fileUploadSizeLimit,
}),
@@ -130,7 +130,7 @@ export default {
...this.getLocalFileAttributes(file),
});
} else {
window.bus.$emit(BUS_EVENTS.SHOW_ALERT, {
this.$emitter.emit(BUS_EVENTS.SHOW_ALERT, {
message: this.$t('FILE_SIZE_LIMIT', {
MAXIMUM_FILE_UPLOAD_SIZE: this.fileUploadSizeLimit,
}),
@@ -147,12 +147,12 @@ export default {
if (this.hasEmail) {
try {
await sendEmailTranscript();
window.bus.$emit(BUS_EVENTS.SHOW_ALERT, {
this.$emitter.emit(BUS_EVENTS.SHOW_ALERT, {
message: this.$t('EMAIL_TRANSCRIPT.SEND_EMAIL_SUCCESS'),
type: 'success',
});
} catch (error) {
window.bus.$emit(BUS_EVENTS.SHOW_ALERT, {
this.$emitter.$emit(BUS_EVENTS.SHOW_ALERT, {
message: this.$t('EMAIL_TRANSCRIPT.SEND_EMAIL_ERROR'),
});
}
+2 -1
View File
@@ -4,6 +4,7 @@ import { ON_AGENT_MESSAGE_RECEIVED } from '../constants/widgetBusEvents';
import { IFrameHelper } from 'widget/helpers/utils';
import { shouldTriggerMessageUpdateEvent } from './IframeEventHelper';
import { CHATWOOT_ON_MESSAGE } from '../constants/sdkEvents';
import { emitter } from '../../shared/helpers/mitt';
const isMessageInActiveConversation = (getters, message) => {
const { conversation_id: conversationId } = message;
@@ -57,7 +58,7 @@ class ActionCableConnector extends BaseActionCableConnector {
this.app.$store
.dispatch('conversation/addOrUpdateMessage', data)
.then(() => window.bus.$emit(ON_AGENT_MESSAGE_RECEIVED));
.then(() => emitter.emit(ON_AGENT_MESSAGE_RECEIVED));
IFrameHelper.sendMessage({
event: 'onEvent',
-4
View File
@@ -54,10 +54,6 @@ module Linear::Queries
title
description
identifier
state {
name
color
}
}
}
}
+2 -1
View File
@@ -31,6 +31,7 @@
],
"dependencies": {
"@braid/vue-formulate": "^2.5.2",
"@chatwoot/ninja-keys": "1.2.3",
"@chatwoot/prosemirror-schema": "1.0.9",
"@chatwoot/utils": "^0.0.25",
"@hcaptcha/vue-hcaptcha": "^0.3.2",
@@ -67,7 +68,7 @@
"markdown-it": "^13.0.2",
"markdown-it-link-attributes": "^4.0.1",
"md5": "^2.3.0",
"@chatwoot/ninja-keys": "1.2.3",
"mitt": "^3.0.1",
"opus-recorder": "^8.0.5",
"postcss": "^8.4.31",
"postcss-loader": "^4.2.0",
+139 -78
View File
@@ -1112,11 +1112,6 @@
resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.18.3.tgz#39e99c7b0c4c56cef4d1eed8de9f506411c2ebc2"
integrity sha512-rL50YcEuHbbauAFAysNsJA4/f89fGTOBRNs9P81sniKnKAr4xULe5AecolcsKbi88xu0ByWYDj/S1AJ3FSFuSQ==
"@babel/parser@^7.18.4":
version "7.22.16"
resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.22.16.tgz#180aead7f247305cce6551bea2720934e2fa2c95"
integrity sha512-+gPfKv8UWeKKeJTUxe59+OobVcrYHETCsORl61EmSkmgymguYk/X5bp7GuUIXaFsc6y++v8ZxPsLSSuujqDphA==
"@babel/parser@^7.18.6", "@babel/parser@^7.18.8":
version "7.18.8"
resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.18.8.tgz#822146080ac9c62dac0823bb3489622e0bc1cbdf"
@@ -1127,6 +1122,11 @@
resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.21.4.tgz#94003fdfc520bbe2875d4ae557b43ddb6d880f17"
integrity sha512-alVJj7k7zIxqBZ7BTRhz0IqJFxW1VJbm6N8JbcYhQ186df9ZBPbZBmWSqAMXwHGsCJdYks7z/voa3ibiS5bCIw==
"@babel/parser@^7.23.5":
version "7.24.6"
resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.24.6.tgz#5e030f440c3c6c78d195528c3b688b101a365328"
integrity sha512-eNZXdfU35nJC2h24RznROuOpO94h6x8sg9ju0tT9biNtLZ2vuP8SduLqqV+/8+cebSLV9SJEAN5Z3zQbJG/M+Q==
"@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression@^7.18.6":
version "7.18.6"
resolved "https://registry.yarnpkg.com/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression/-/plugin-bugfix-safari-id-destructuring-collision-in-function-expression-7.18.6.tgz#da5b8f9a580acdfbe53494dba45ea389fb09a4d2"
@@ -6716,14 +6716,16 @@
"@vue/compiler-core" "3.3.4"
"@vue/shared" "3.3.4"
"@vue/compiler-sfc@2.7.14":
version "2.7.14"
resolved "https://registry.yarnpkg.com/@vue/compiler-sfc/-/compiler-sfc-2.7.14.tgz#3446fd2fbb670d709277fc3ffa88efc5e10284fd"
integrity sha512-aNmNHyLPsw+sVvlQFQ2/8sjNuLtK54TC6cuKnVzAY93ks4ZBrvwQSnkkIh7bsbNhum5hJBS00wSDipQ937f5DA==
"@vue/compiler-sfc@2.7.16":
version "2.7.16"
resolved "https://registry.yarnpkg.com/@vue/compiler-sfc/-/compiler-sfc-2.7.16.tgz#ff81711a0fac9c68683d8bb00b63f857de77dc83"
integrity sha512-KWhJ9k5nXuNtygPU7+t1rX6baZeqOYLEforUPjgNDBnLicfHCoi48H87Q8XyLZOrNNsmhuwKqtpDQWjEFe6Ekg==
dependencies:
"@babel/parser" "^7.18.4"
"@babel/parser" "^7.23.5"
postcss "^8.4.14"
source-map "^0.6.1"
optionalDependencies:
prettier "^1.18.2 || ^2.0.0"
"@vue/compiler-sfc@^3.2.0":
version "3.3.4"
@@ -7721,13 +7723,13 @@ atob@^2.1.2:
integrity sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg==
autoprefixer@^10.4.14:
version "10.4.16"
resolved "https://registry.yarnpkg.com/autoprefixer/-/autoprefixer-10.4.16.tgz#fad1411024d8670880bdece3970aa72e3572feb8"
integrity sha512-7vd3UC6xKp0HLfua5IjZlcXvGAGy7cBAXTg2lyQ/8WpNhd6SiZ8Be+xm3FyBSYJx5GKcpRCzBh7RH4/0dnY+uQ==
version "10.4.19"
resolved "https://registry.yarnpkg.com/autoprefixer/-/autoprefixer-10.4.19.tgz#ad25a856e82ee9d7898c59583c1afeb3fa65f89f"
integrity sha512-BaENR2+zBZ8xXhM4pUaKUxlVdxZ0EZhjvbopwnXmxRUfqDmwSpC2lAi/QXvx7NRdPCo1WKEcEF6mV64si1z4Ew==
dependencies:
browserslist "^4.21.10"
caniuse-lite "^1.0.30001538"
fraction.js "^4.3.6"
browserslist "^4.23.0"
caniuse-lite "^1.0.30001599"
fraction.js "^4.3.7"
normalize-range "^0.1.2"
picocolors "^1.0.0"
postcss-value-parser "^4.2.0"
@@ -8334,16 +8336,6 @@ browserslist@^4.0.0, browserslist@^4.12.0, browserslist@^4.14.5, browserslist@^4
escalade "^3.1.1"
node-releases "^1.1.71"
browserslist@^4.21.10, browserslist@^4.21.5:
version "4.21.10"
resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.21.10.tgz#dbbac576628c13d3b2231332cb2ec5a46e015bb0"
integrity sha512-bipEBdZfVH5/pwrvqc+Ub0kUPVfGUhlKxbvfD+z1BDnPEO/X98ruXGA1WP5ASpAFKan7Qr6j736IacbZQuAlKQ==
dependencies:
caniuse-lite "^1.0.30001517"
electron-to-chromium "^1.4.477"
node-releases "^2.0.13"
update-browserslist-db "^1.0.11"
browserslist@^4.21.3:
version "4.21.5"
resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.21.5.tgz#75c5dae60063ee641f977e00edd3cfb2fb7af6a7"
@@ -8354,6 +8346,16 @@ browserslist@^4.21.3:
node-releases "^2.0.8"
update-browserslist-db "^1.0.10"
browserslist@^4.21.5:
version "4.21.10"
resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.21.10.tgz#dbbac576628c13d3b2231332cb2ec5a46e015bb0"
integrity sha512-bipEBdZfVH5/pwrvqc+Ub0kUPVfGUhlKxbvfD+z1BDnPEO/X98ruXGA1WP5ASpAFKan7Qr6j736IacbZQuAlKQ==
dependencies:
caniuse-lite "^1.0.30001517"
electron-to-chromium "^1.4.477"
node-releases "^2.0.13"
update-browserslist-db "^1.0.11"
browserslist@^4.21.9:
version "4.21.9"
resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.21.9.tgz#e11bdd3c313d7e2a9e87e8b4b0c7872b13897635"
@@ -8364,6 +8366,16 @@ browserslist@^4.21.9:
node-releases "^2.0.12"
update-browserslist-db "^1.0.11"
browserslist@^4.23.0:
version "4.23.0"
resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.23.0.tgz#8f3acc2bbe73af7213399430890f86c63a5674ab"
integrity sha512-QW8HiM1shhT2GuzkvklfjcKDiWFXHOeFCIA/huJPwHsslwcydgk7X+z2zXpEijP98UCY7HbubZt5J2Zgvf0CaQ==
dependencies:
caniuse-lite "^1.0.30001587"
electron-to-chromium "^1.4.668"
node-releases "^2.0.14"
update-browserslist-db "^1.0.13"
bser@2.1.1:
version "2.1.1"
resolved "https://registry.yarnpkg.com/bser/-/bser-2.1.1.tgz#e6787da20ece9d07998533cfd9de6f5c38f4bc05"
@@ -8582,10 +8594,10 @@ caniuse-api@^3.0.0:
lodash.memoize "^4.1.2"
lodash.uniq "^4.5.0"
caniuse-lite@^1.0.0, caniuse-lite@^1.0.30000981, caniuse-lite@^1.0.30001109, caniuse-lite@^1.0.30001214, caniuse-lite@^1.0.30001449, caniuse-lite@^1.0.30001503, caniuse-lite@^1.0.30001517, caniuse-lite@^1.0.30001538:
version "1.0.30001616"
resolved "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001616.tgz"
integrity sha512-RHVYKov7IcdNjVHJFNY/78RdG4oGVjbayxv8u5IO74Wv7Hlq4PnJE6mo/OjFijjVFNy5ijnCt6H3IIo4t+wfEw==
caniuse-lite@^1.0.0, caniuse-lite@^1.0.30000981, caniuse-lite@^1.0.30001109, caniuse-lite@^1.0.30001214, caniuse-lite@^1.0.30001449, caniuse-lite@^1.0.30001503, caniuse-lite@^1.0.30001517, caniuse-lite@^1.0.30001587, caniuse-lite@^1.0.30001599:
version "1.0.30001624"
resolved "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001624.tgz"
integrity sha512-0dWnQG87UevOCPYaOR49CBcLBwoZLpws+k6W37nLjWUhumP1Isusj0p2u+3KhjNloRWK9OKMgjBBzPujQHw4nA==
capture-exit@^2.0.0:
version "2.0.0"
@@ -8951,9 +8963,9 @@ color-support@^1.1.2:
integrity sha512-qiBjkpbMLO/HL68y+lh4q0/O1MZFj2RX6X/KmMa3+gJD3z+WwI1ZzDHysvqHGS3mP6mznPckpXmw1nI9cJjyRg==
color2k@^2.0.2:
version "2.0.2"
resolved "https://registry.yarnpkg.com/color2k/-/color2k-2.0.2.tgz#ac2b4aea11c822a6bcb70c768b5a289f4fffcebb"
integrity sha512-kJhwH5nAwb34tmyuqq/lgjEKzlFXn1U99NlnB6Ws4qVaERcRUYeYP1cBw6BJ4vxaWStAUEef4WMr7WjOCnBt8w==
version "2.0.3"
resolved "https://registry.yarnpkg.com/color2k/-/color2k-2.0.3.tgz#a771244f6b6285541c82aa65ff0a0c624046e533"
integrity sha512-zW190nQTIoXcGCaU08DvVNFTmQhUpnJfVuAKfWqUQkflXKpaDdpaYoM0iluLS9lgJNHyBF58KKA2FBEwkD7wog==
color@^3.0.0:
version "3.1.3"
@@ -9623,11 +9635,16 @@ cssstyle@^2.3.0:
dependencies:
cssom "~0.3.6"
csstype@^3.0.2, csstype@^3.1.0:
csstype@^3.0.2:
version "3.1.2"
resolved "https://registry.yarnpkg.com/csstype/-/csstype-3.1.2.tgz#1d4bf9d572f11c14031f0436e1c10bc1f571f50b"
integrity sha512-I7K1Uu0MBPzaFKg4nI5Q7Vs2t+3gWWW648spaF+Rg7pI9ds18Ugn+lvg4SHczUdKlHI5LWBXyqfS8+DufyBsgQ==
csstype@^3.1.0:
version "3.1.3"
resolved "https://registry.yarnpkg.com/csstype/-/csstype-3.1.3.tgz#d80ff294d114fb0e6ac500fbf85b60137d7eff81"
integrity sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==
currently-unhandled@^0.4.1:
version "0.4.1"
resolved "https://registry.yarnpkg.com/currently-unhandled/-/currently-unhandled-0.4.1.tgz#988df33feab191ef799a61369dd76c17adf957ea"
@@ -9738,7 +9755,7 @@ dayjs@^1.10.4:
de-indent@^1.0.2:
version "1.0.2"
resolved "https://registry.yarnpkg.com/de-indent/-/de-indent-1.0.2.tgz#b2038e846dc33baa5796128d0804b455b8c1e21d"
integrity sha1-sgOOhG3DO6pXlhKNCAS0VbjB4h0=
integrity sha512-e/1zu3xH5MQryN2zdVaF0OrdNLUbvWxzMbi+iNA6Bky7l1RoP8a2fIbRocyHclXt/arDrrR6lL3TqFD9pMQTsg==
debug@2.6.9, debug@^2.2.0, debug@^2.3.3, debug@^2.6.9:
version "2.6.9"
@@ -10285,7 +10302,7 @@ electron-to-chromium@^1.3.719:
resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.723.tgz#52769a75635342a4db29af5f1e40bd3dad02c877"
integrity sha512-L+WXyXI7c7+G1V8ANzRsPI5giiimLAUDC6Zs1ojHHPhYXb3k/iTABFmWjivEtsWrRQymjnO66/rO2ZTABGdmWg==
electron-to-chromium@^1.4.284, electron-to-chromium@^1.4.477:
electron-to-chromium@^1.4.284:
version "1.4.526"
resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.526.tgz#1bcda5f2b8238e497c20fcdb41af5da907a770e2"
integrity sha512-tjjTMjmZAx1g6COrintLTa2/jcafYKxKoiEkdQOrVdbLaHh2wCt2nsAF8ZHweezkrP+dl/VG9T5nabcYoo0U5Q==
@@ -10295,6 +10312,11 @@ electron-to-chromium@^1.4.431:
resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.440.tgz#d3b1eeb36b717eb479a240c0406ac1fa67901762"
integrity sha512-r6dCgNpRhPwiWlxbHzZQ/d9swfPaEJGi8ekqRBwQYaR3WmA5VkqQfBWSDDjuJU1ntO+W9tHx8OHV/96Q8e0dVw==
electron-to-chromium@^1.4.477, electron-to-chromium@^1.4.668:
version "1.4.783"
resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.783.tgz#933887165b8b6025a81663d2d97cf4b85cde27b2"
integrity sha512-bT0jEz/Xz1fahQpbZ1D7LgmPYZ3iHVY39NcWWro1+hA2IvjiPeaXtfSqrQ+nXjApMvQRE2ASt1itSLRrebHMRQ==
elliptic@^6.5.3, elliptic@^6.5.4:
version "6.5.4"
resolved "https://registry.yarnpkg.com/elliptic/-/elliptic-6.5.4.tgz#da37cebd31e79a1367e941b592ed1fbebd58abbb"
@@ -10590,10 +10612,10 @@ es6-shim@^0.35.5:
resolved "https://registry.yarnpkg.com/es6-shim/-/es6-shim-0.35.8.tgz#89216f6fbf8bacba3f897c8c0e814d2a41c05fb7"
integrity sha512-Twf7I2v4/1tLoIXMT8HlqaBSS5H2wQTs2wx3MNYCI8K1R1/clXyCazrcVCPm/FuO9cyV8+leEaZOWD5C253NDg==
escalade@^3.1.1:
version "3.1.1"
resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.1.1.tgz#d8cfdc7000965c5a0174b4a82eaa5c0552742e40"
integrity sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==
escalade@^3.1.1, escalade@^3.1.2:
version "3.1.2"
resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.1.2.tgz#54076e9ab29ea5bf3d8f1ed62acffbb88272df27"
integrity sha512-ErCHMCae19vR8vQGe50xIsVomy19rg6gFu3+r3jkEO46suLMWBksvVyoGgQV+jOfl84ZSOSlmv6Gxa89PmTGmA==
escape-html@~1.0.3:
version "1.0.3"
@@ -11515,10 +11537,10 @@ forwarded@0.2.0:
resolved "https://registry.yarnpkg.com/forwarded/-/forwarded-0.2.0.tgz#2269936428aad4c15c7ebe9779a84bf0b2a81811"
integrity sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==
fraction.js@^4.3.6:
version "4.3.6"
resolved "https://registry.yarnpkg.com/fraction.js/-/fraction.js-4.3.6.tgz#e9e3acec6c9a28cf7bc36cbe35eea4ceb2c5c92d"
integrity sha512-n2aZ9tNfYDwaHhvFTkhFErqOMIb8uyzSQ+vGJBjZyanAKZVbGUQ1sngfk9FdkBw7G26O7AgNjLcecLffD1c7eg==
fraction.js@^4.3.7:
version "4.3.7"
resolved "https://registry.yarnpkg.com/fraction.js/-/fraction.js-4.3.7.tgz#06ca0085157e42fda7f9e726e79fefc4068840f7"
integrity sha512-ZsDfxO51wGAXREY55a7la9LScWpwv9RxIrYABrlvOFBlH/ShPnrtsXeuUIfXKKOVicNxQ+o8JTbJvjS4M89yew==
fragment-cache@^0.2.1:
version "0.2.1"
@@ -14929,6 +14951,11 @@ mississippi@^3.0.0:
stream-each "^1.1.0"
through2 "^2.0.0"
mitt@^3.0.1:
version "3.0.1"
resolved "https://registry.yarnpkg.com/mitt/-/mitt-3.0.1.tgz#ea36cf0cc30403601ae074c8f77b7092cdab36d1"
integrity sha512-vKivATfr97l2/QBCYAkXYDbrIWPM2IIKEl7YPhjCvKlG3kE2gm+uBo6nEXK3M5/Ffh/FLpKExzOQ3JJoJGFKBw==
mixin-deep@^1.2.0:
version "1.3.2"
resolved "https://registry.yarnpkg.com/mixin-deep/-/mixin-deep-1.3.2.tgz#1120b43dc359a785dce65b55b82e257ccf479566"
@@ -15031,11 +15058,16 @@ nan@^2.12.1:
resolved "https://registry.yarnpkg.com/nan/-/nan-2.14.2.tgz#f5376400695168f4cc694ac9393d0c9585eeea19"
integrity sha512-M2ufzIiINKCuDfBSAUr1vWQ+vuVcA9kqx8JJUsbQi6yf1uGRyb7HfpdfUr5qLXf3B/t8dPvcjhKMmlfnP47EzQ==
nanoid@^3.3.1, nanoid@^3.3.6:
nanoid@^3.3.1:
version "3.3.6"
resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.3.6.tgz#443380c856d6e9f9824267d960b4236ad583ea4c"
integrity sha512-BGcqMMJuToF7i1rt+2PWSNVnWIkGCU78jBG3RxO/bZlnZPK2Cmi2QaffxGO/2RvWi9sL+FAiRiXMgsyxQ1DIDA==
nanoid@^3.3.6, nanoid@^3.3.7:
version "3.3.7"
resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.3.7.tgz#d0c301a691bc8d54efa0a2226ccf3fe2fd656bd8"
integrity sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==
nanomatch@^1.2.9:
version "1.2.13"
resolved "https://registry.yarnpkg.com/nanomatch/-/nanomatch-1.2.13.tgz#b87a8aa4fc0de8fe6be88895b38983ff265bd119"
@@ -15170,7 +15202,12 @@ node-releases@^2.0.12:
resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-2.0.12.tgz#35627cc224a23bfb06fb3380f2b3afaaa7eb1039"
integrity sha512-QzsYKWhXTWx8h1kIvqfnC++o0pEmpRQA/aenALsL2F4pqNVr7YzcdMlDij5WBnwftRbJCNJL/O7zdKaxKPHqgQ==
node-releases@^2.0.13, node-releases@^2.0.8:
node-releases@^2.0.13, node-releases@^2.0.14:
version "2.0.14"
resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-2.0.14.tgz#2ffb053bceb8b2be8495ece1ab6ce600c4461b0b"
integrity sha512-y10wOWt8yZpqXmOgRo77WaHEmhYQYGNA6y421PKsKYWEK8aW+cqAphborZDhqfyKrbZEN92CN1X2KbafY2s7Yw==
node-releases@^2.0.8:
version "2.0.13"
resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-2.0.13.tgz#d5ed1627c23e3461e819b02e57b75e4899b1c81d"
integrity sha512-uYr7J37ae/ORWdZeQ1xxMJe3NtdmqMC/JZK+geofDrkLUApKRHPd18/TxtBOJ4A0/+uUIliorNrfYV6s1b02eQ==
@@ -15899,10 +15936,10 @@ picocolors@^0.2.1:
resolved "https://registry.yarnpkg.com/picocolors/-/picocolors-0.2.1.tgz#570670f793646851d1ba135996962abad587859f"
integrity sha512-cMlDqaLEqfSaW8Z7N5Jw+lyIW869EzT73/F5lhtY9cLGoVxSXznfgfXMO0Z5K0o0Q2TkTXq+0KFsdnSe3jDViA==
picocolors@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/picocolors/-/picocolors-1.0.0.tgz#cb5bdc74ff3f51892236eaf79d68bc44564ab81c"
integrity sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==
picocolors@^1.0.0, picocolors@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/picocolors/-/picocolors-1.0.1.tgz#a8ad579b571952f0e5d25892de5445bcfe25aaa1"
integrity sha512-anP1Z8qwhkbmu7MFP5iTt+wQKXgwzf7zTyGlcdzabySa9vd0Xt392U0rVmz9poOaBj0uHJKyyo9/upk0HrEQew==
picomatch@^2.0.4, picomatch@^2.2.1, picomatch@^2.2.3, picomatch@^2.3.0, picomatch@^2.3.1:
version "2.3.1"
@@ -16964,7 +17001,7 @@ postcss@^7.0.0, postcss@^7.0.1, postcss@^7.0.14, postcss@^7.0.17, postcss@^7.0.2
picocolors "^0.2.1"
source-map "^0.6.1"
postcss@^8.1.10, postcss@^8.4.14, postcss@^8.4.23, postcss@^8.4.31:
postcss@^8.1.10, postcss@^8.4.23:
version "8.4.31"
resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.4.31.tgz#92b451050a9f914da6755af352bdc0192508656d"
integrity sha512-PS08Iboia9mts/2ygV3eLpY5ghnUcfLV/EXTOW1E2qYxJKGGBUtNjN76FYHnMs36RmARn41bC0AZmn+rR0OVpQ==
@@ -16973,6 +17010,15 @@ postcss@^8.1.10, postcss@^8.4.14, postcss@^8.4.23, postcss@^8.4.31:
picocolors "^1.0.0"
source-map-js "^1.0.2"
postcss@^8.4.14, postcss@^8.4.31:
version "8.4.38"
resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.4.38.tgz#b387d533baf2054288e337066d81c6bee9db9e0e"
integrity sha512-Wglpdk03BSfXkHoQa3b/oulrotAkwrlLDRSOb9D0bN86FdRyE9lppSp33aHNPgBa0JKCoB+drFLZkQoRRYae5A==
dependencies:
nanoid "^3.3.7"
picocolors "^1.0.0"
source-map-js "^1.2.0"
prelude-ls@^1.2.1:
version "1.2.1"
resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.2.1.tgz#debc6489d7a6e6b0e7611888cec880337d316396"
@@ -17000,6 +17046,11 @@ prettier@^1.18.2:
resolved "https://registry.yarnpkg.com/prettier/-/prettier-1.19.1.tgz#f7d7f5ff8a9cd872a7be4ca142095956a60797cb"
integrity sha512-s7PoyDv/II1ObgQunCbB9PdLmUcBZcnWOcxDh7O0N/UwDEsHyqkW+Qh28jW+mVuCdx7gLB0BotYI1Y6uI9iyew==
"prettier@^1.18.2 || ^2.0.0":
version "2.8.8"
resolved "https://registry.yarnpkg.com/prettier/-/prettier-2.8.8.tgz#e8c5d7e98a4305ffe3de2e1fc4aca1a71c28b1da"
integrity sha512-tdN8qQGvNjw4CHbY+XXk0JgCXn9QiF21a55rBe5LJAU+kDyC4WQn4+awm2Xfk2lQMk5fKup9XgzTZtGkjBdP9Q==
prettier@^3.0.3:
version "3.0.3"
resolved "https://registry.yarnpkg.com/prettier/-/prettier-3.0.3.tgz#432a51f7ba422d1469096c0fdc28e235db8f9643"
@@ -17361,17 +17412,17 @@ pug-attrs@^3.0.0:
js-stringify "^1.0.2"
pug-runtime "^3.0.0"
pug-code-gen@^3.0.2:
version "3.0.2"
resolved "https://registry.yarnpkg.com/pug-code-gen/-/pug-code-gen-3.0.2.tgz#ad190f4943133bf186b60b80de483100e132e2ce"
integrity sha512-nJMhW16MbiGRiyR4miDTQMRWDgKplnHyeLvioEJYbk1RsPI3FuA3saEP8uwnTb2nTJEKBU90NFVWJBk4OU5qyg==
pug-code-gen@^3.0.3:
version "3.0.3"
resolved "https://registry.yarnpkg.com/pug-code-gen/-/pug-code-gen-3.0.3.tgz#58133178cb423fe1716aece1c1da392a75251520"
integrity sha512-cYQg0JW0w32Ux+XTeZnBEeuWrAY7/HNE6TWnhiHGnnRYlCgyAUPoyh9KzCMa9WhcJlJ1AtQqpEYHc+vbCzA+Aw==
dependencies:
constantinople "^4.0.1"
doctypes "^1.1.0"
js-stringify "^1.0.2"
pug-attrs "^3.0.0"
pug-error "^2.0.0"
pug-runtime "^3.0.0"
pug-error "^2.1.0"
pug-runtime "^3.0.1"
void-elements "^3.1.0"
with "^7.0.0"
@@ -17380,6 +17431,11 @@ pug-error@^2.0.0:
resolved "https://registry.yarnpkg.com/pug-error/-/pug-error-2.0.0.tgz#5c62173cb09c34de2a2ce04f17b8adfec74d8ca5"
integrity sha512-sjiUsi9M4RAGHktC1drQfCr5C5eriu24Lfbt4s+7SykztEOwVZtbFk1RRq0tzLxcMxMYTBR+zMQaG07J/btayQ==
pug-error@^2.1.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/pug-error/-/pug-error-2.1.0.tgz#17ea37b587b6443d4b8f148374ec27b54b406e55"
integrity sha512-lv7sU9e5Jk8IeUheHata6/UThZ7RK2jnaaNztxfPYUY+VxZyk/ePVaNZ/vwmH8WqGvDz3LrNYt/+gA55NDg6Pg==
pug-filters@^4.0.0:
version "4.0.0"
resolved "https://registry.yarnpkg.com/pug-filters/-/pug-filters-4.0.0.tgz#d3e49af5ba8472e9b7a66d980e707ce9d2cc9b5e"
@@ -17442,11 +17498,11 @@ pug-walk@^2.0.0:
integrity sha512-yYELe9Q5q9IQhuvqsZNwA5hfPkMJ8u92bQLIMcsMxf/VADjNtEYptU+inlufAFYcWdHlwNfZOEnOOQrZrcyJCQ==
pug@^3.0.2:
version "3.0.2"
resolved "https://registry.yarnpkg.com/pug/-/pug-3.0.2.tgz#f35c7107343454e43bc27ae0ff76c731b78ea535"
integrity sha512-bp0I/hiK1D1vChHh6EfDxtndHji55XP/ZJKwsRqrz6lRia6ZC2OZbdAymlxdVFwd1L70ebrVJw4/eZ79skrIaw==
version "3.0.3"
resolved "https://registry.yarnpkg.com/pug/-/pug-3.0.3.tgz#e18324a314cd022883b1e0372b8af3a1a99f7597"
integrity sha512-uBi6kmc9f3SZ3PXxqcHiUZLmIXgfgWooKWXcwSGwQd2Zi5Rb0bT14+8CJjJgI8AB+nndLaNgHGrcc6bPIB665g==
dependencies:
pug-code-gen "^3.0.2"
pug-code-gen "^3.0.3"
pug-filters "^4.0.0"
pug-lexer "^5.0.1"
pug-linker "^4.0.0"
@@ -18800,11 +18856,16 @@ source-list-map@^2.0.0:
resolved "https://registry.yarnpkg.com/source-list-map/-/source-list-map-2.0.1.tgz#3993bd873bfc48479cca9ea3a547835c7c154b34"
integrity sha512-qnQ7gVMxGNxsiL4lEuJwe/To8UnK7fAnmbGEEH8RpLouuKbeEm0lhbQVFIrNSuB+G7tVrAlVsZgETT5nljf+Iw==
"source-map-js@>=0.6.2 <2.0.0", source-map-js@^1.0.1, source-map-js@^1.0.2:
"source-map-js@>=0.6.2 <2.0.0", source-map-js@^1.0.1:
version "1.0.2"
resolved "https://registry.yarnpkg.com/source-map-js/-/source-map-js-1.0.2.tgz#adbc361d9c62df380125e7f161f71c826f1e490c"
integrity sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==
source-map-js@^1.0.2, source-map-js@^1.2.0:
version "1.2.0"
resolved "https://registry.yarnpkg.com/source-map-js/-/source-map-js-1.2.0.tgz#16b809c162517b5b8c3e7dcd315a2a5c2612b2af"
integrity sha512-itJW8lvSA0TXEphiRoawsCksnlf8SyvmFzIhltqAHluXd88pkCd+cXJVHTDwdCr0IzwptSm035IHQktUu1QUMg==
source-map-resolve@^0.5.0:
version "0.5.3"
resolved "https://registry.yarnpkg.com/source-map-resolve/-/source-map-resolve-0.5.3.tgz#190866bece7553e1f8f267a2ee82c606b5509a1a"
@@ -20230,13 +20291,13 @@ update-browserslist-db@^1.0.10:
escalade "^3.1.1"
picocolors "^1.0.0"
update-browserslist-db@^1.0.11:
version "1.0.11"
resolved "https://registry.yarnpkg.com/update-browserslist-db/-/update-browserslist-db-1.0.11.tgz#9a2a641ad2907ae7b3616506f4b977851db5b940"
integrity sha512-dCwEFf0/oT85M1fHBg4F0jtLwJrutGoHSQXCh7u4o2t1drG+c0a9Flnqww6XUKSfQMPpJBRjU8d4RXB09qtvaA==
update-browserslist-db@^1.0.11, update-browserslist-db@^1.0.13:
version "1.0.16"
resolved "https://registry.yarnpkg.com/update-browserslist-db/-/update-browserslist-db-1.0.16.tgz#f6d489ed90fb2f07d67784eb3f53d7891f736356"
integrity sha512-KVbTxlBYlckhF5wgfyZXTWnMn7MMZjMu9XG8bPlliUOP9ThaF4QnhP8qrjrH7DRzHfSk0oQv1wToW+iA5GajEQ==
dependencies:
escalade "^3.1.1"
picocolors "^1.0.0"
escalade "^3.1.2"
picocolors "^1.0.1"
uri-js@^4.2.2:
version "4.4.1"
@@ -20632,9 +20693,9 @@ vue-loader@^15.10.0:
vue-style-loader "^4.1.0"
vue-multiselect@~2.1.6:
version "2.1.7"
resolved "https://registry.yarnpkg.com/vue-multiselect/-/vue-multiselect-2.1.7.tgz#f27afe3d46482b94810382af7a4826219255c47d"
integrity sha512-KIegcN+Ntwg3cbkY/jhw2s/+XJUM0Lpi/LcKFYCS8PrZHcWBl2iKCVze7ZCnRj3w8H7/lUJ9v7rj9KQiNxApBw==
version "2.1.9"
resolved "https://registry.yarnpkg.com/vue-multiselect/-/vue-multiselect-2.1.9.tgz#803628d5ff6c5925320930c965bdaae8934b92b1"
integrity sha512-nGEppmzhQQT2iDz4cl+ZCX3BpeNhygK50zWFTIRS+r7K7i61uWXJWSioMuf+V/161EPQjexI8NaEBdUlF3dp+g==
vue-resize@^1.0.1:
version "1.0.1"
@@ -20665,9 +20726,9 @@ vue-template-compiler@^2.6.11:
he "^1.1.0"
vue-template-compiler@^2.7.0:
version "2.7.14"
resolved "https://registry.yarnpkg.com/vue-template-compiler/-/vue-template-compiler-2.7.14.tgz#4545b7dfb88090744c1577ae5ac3f964e61634b1"
integrity sha512-zyA5Y3ArvVG0NacJDkkzJuPQDF8RFeRlzV2vLeSnhSpieO6LK2OVbdLPi5MPPs09Ii+gMO8nY4S3iKQxBxDmWQ==
version "2.7.16"
resolved "https://registry.yarnpkg.com/vue-template-compiler/-/vue-template-compiler-2.7.16.tgz#c81b2d47753264c77ac03b9966a46637482bb03b"
integrity sha512-AYbUWAJHLGGQM7+cNTELw+KsOG9nl2CnSv467WobS5Cv9uk3wFcnr1Etsz2sEIHEZvw1U+o9mRlEO6QbZvUPGQ==
dependencies:
de-indent "^1.0.2"
he "^1.2.0"
@@ -20700,11 +20761,11 @@ vue@^2.6.12:
integrity sha512-uhmLFETqPPNyuLLbsKz6ioJ4q7AZHzD8ZVFNATNyICSZouqP2Sz0rotWQC8UNBF6VGSCs5abnKJoStA6JbCbfg==
vue@^2.7.0:
version "2.7.14"
resolved "https://registry.yarnpkg.com/vue/-/vue-2.7.14.tgz#3743dcd248fd3a34d421ae456b864a0246bafb17"
integrity sha512-b2qkFyOM0kwqWFuQmgd4o+uHGU7T+2z3T+WQp8UBjADfEv2n4FEMffzBmCKNP0IGzOEEfYjvtcC62xaSKeQDrQ==
version "2.7.16"
resolved "https://registry.yarnpkg.com/vue/-/vue-2.7.16.tgz#98c60de9def99c0e3da8dae59b304ead43b967c9"
integrity sha512-4gCtFXaAA3zYZdTp5s4Hl2sozuySsgz4jy1EnpBHNfpMa9dK1ZCG7viqBPCwXtmgc8nHqUsAu3G4gtmXkkY3Sw==
dependencies:
"@vue/compiler-sfc" "2.7.14"
"@vue/compiler-sfc" "2.7.16"
csstype "^3.1.0"
vuedraggable@^2.24.3: