mirror of
https://github.com/lingble/chatwoot.git
synced 2025-11-01 03:27:52 +00:00
Fixes https://linear.app/chatwoot/issue/CW-4150/support-for-multiple-issues-linking-in-linear This PR significantly improves the Linear integration user experience by relocating the Linear integration from the conversation header to the contact panel and adding support for multiple issue linking per conversation. ### Key Changes - **Relocated Linear integration**: Moved from conversation header to contact panel for better organization and accessibility - **Multi-issue support**: Added ability to link/create multiple Linear issues for a single conversation - **Integration CTA**: Added a dedicated call-to-action section for users who haven't connected their Linear account yet - **UI/UX improvements**: Enhanced design consistency and user flow <details> <summary>Screenshots</summary> #### Multiple Issues Support  #### Integration CTA  --------- Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> Co-authored-by: Sivin Varghese <64252451+iamsivin@users.noreply.github.com> Co-authored-by: iamsivin <iamsivin@gmail.com> Co-authored-by: Pranav <pranav@chatwoot.com> Co-authored-by: Pranav <pranavrajs@gmail.com>
153 lines
5.4 KiB
JavaScript
153 lines
5.4 KiB
JavaScript
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: 'contact_notes' },
|
|
{ name: 'previous_conversation' },
|
|
{ name: 'conversation_participants' },
|
|
{ name: 'linear_issues' },
|
|
{ name: 'shopify_orders' },
|
|
]);
|
|
|
|
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),
|
|
};
|
|
}
|