feat: Generate SSO URL in Chatwoot, move Captain to primary tab (#9871)

- Generate SSO URL in Chatwoot, move Captain to the primary tab

Co-authored-by: Pranav <pranavrajs@gmail.com>
This commit is contained in:
Sojan Jose
2024-08-01 19:22:34 -07:00
committed by GitHub
parent 17a6df10a0
commit 829bb842fd
16 changed files with 237 additions and 12 deletions

View File

@@ -32,6 +32,10 @@ class IntegrationsAPI extends ApiClient {
deleteHook(hookId) {
return axios.delete(`${this.baseUrl()}/integrations/hooks/${hookId}`);
}
fetchCaptainURL() {
return axios.get(`${this.baseUrl()}/integrations/captain/sso_url`);
}
}
export default new IntegrationsAPI();

View File

@@ -17,6 +17,14 @@ const primaryMenuItems = accountId => [
toState: frontendURL(`accounts/${accountId}/dashboard`),
toStateName: 'home',
},
{
icon: 'captain',
key: 'captain',
label: 'CAPTAIN',
featureFlag: FEATURE_FLAGS.CAPTAIN,
toState: frontendURL(`accounts/${accountId}/captain`),
toStateName: 'captain',
},
{
icon: 'book-contacts',
key: 'contacts',

View File

@@ -31,4 +31,5 @@ export const FEATURE_FLAGS = {
INBOUND_EMAILS: 'inbound_emails',
IP_LOOKUP: 'ip_lookup',
LINEAR: 'linear_integration',
CAPTAIN: 'captain_integration',
};

View File

@@ -4,6 +4,12 @@
"DESCRIPTION": "Chatwoot integrates with multiple tools and services to improve your team's efficiency. Explore the list below to configure your favorite apps.",
"LEARN_MORE": "Learn more about integrations",
"LOADING": "Fetching integrations",
"CAPTAIN": {
"DISABLED": "Captain is not enabled on your account.",
"CLICK_HERE_TO_CONFIGURE": "Click here to configure",
"LOADING_CONSOLE": "Loading Captain Console...",
"FAILED_TO_LOAD_CONSOLE": "Failed to load Captain Console. Please refresh and try again."
},
"WEBHOOK": {
"SUBSCRIBED_EVENTS": "Subscribed Events",
"FORM": {

View File

@@ -145,7 +145,11 @@
},
"AVAILABILITY": {
"LABEL": "Availability",
"STATUSES_LIST": ["Online", "Busy", "Offline"],
"STATUSES_LIST": [
"Online",
"Busy",
"Offline"
],
"SET_AVAILABILITY_SUCCESS": "Availability has been set successfully",
"SET_AVAILABILITY_ERROR": "Couldn't set availability, please try again"
},
@@ -235,6 +239,7 @@
"REPORTS": "Reports",
"SETTINGS": "Settings",
"CONTACTS": "Contacts",
"CAPTAIN": "Captain",
"HOME": "Home",
"AGENTS": "Agents",
"AGENT_BOTS": "Bots",

View File

@@ -0,0 +1,75 @@
<script setup>
import { computed, onMounted, ref, watch } from 'vue';
import { useStoreGetters } from 'dashboard/composables/store';
import integrations from '../../api/integrations';
import Spinner from 'shared/components/Spinner.vue';
const isLoading = ref(true);
const captainURL = ref('');
const hasError = ref(false);
const loadCaptainFrame = async integration => {
if (!integration || !integration.enabled) {
return;
}
try {
isLoading.value = true;
const { data } = await integrations.fetchCaptainURL();
captainURL.value = data.sso_url;
} catch (error) {
hasError.value = true;
} finally {
isLoading.value = false;
}
};
const getters = useStoreGetters();
const captainIntegration = computed(() =>
getters['integrations/getIntegration'].value('captain', null)
);
onMounted(() => loadCaptainFrame(captainIntegration.value));
watch(captainIntegration, updatedIntegration =>
loadCaptainFrame(updatedIntegration)
);
</script>
<template>
<div
class="flex-1 overflow-auto flex gap-8 flex-col font-inter text-slate-900 dark:text-slate-500"
>
<div class="flex-1 flex items-center justify-center">
<div v-if="!captainIntegration">
{{ $t('INTEGRATION_SETTINGS.CAPTAIN.DISABLED') }}
</div>
<div
v-else-if="!captainIntegration.enabled"
class="flex-1 flex flex-col gap-2 items-center justify-center"
>
<div>{{ $t('INTEGRATION_SETTINGS.CAPTAIN.DISABLED') }}</div>
<router-link :to="{ name: 'settings_applications' }">
<woot-button class="clear link">
{{ $t('INTEGRATION_SETTINGS.CAPTAIN.CLICK_HERE_TO_CONFIGURE') }}
</woot-button>
</router-link>
</div>
<div
v-else-if="isLoading"
class="flex-1 flex items-center justify-center"
>
<Spinner color-scheme="primary" />
<span>{{ $t('INTEGRATION_SETTINGS.CAPTAIN.LOADING_CONSOLE') }}</span>
</div>
<div v-else-if="!isLoading && hasError">
{{ $t('INTEGRATION_SETTINGS.CAPTAIN.FAILED_TO_LOAD_CONSOLE') }}
</div>
<iframe
v-else-if="!isLoading && captainURL"
:src="captainURL"
class="w-full min-h-[800px] h-full"
/>
</div>
</div>
</template>

View File

@@ -8,6 +8,7 @@ import { frontendURL } from '../../helper/URLHelper';
import helpcenterRoutes from './helpcenter/helpcenter.routes';
const AppContainer = () => import('./Dashboard.vue');
const Captain = () => import('./Captain.vue');
const Suspended = () => import('./suspended/Index.vue');
export default {
@@ -17,6 +18,14 @@ export default {
path: frontendURL('accounts/:account_id'),
component: AppContainer,
children: [
{
path: frontendURL('accounts/:accountId/captain'),
name: 'captain',
component: Captain,
meta: {
permissions: ['administrator', 'agent'],
},
},
...inboxRoutes,
...conversation.routes,
...settings.routes,

View File

@@ -24,12 +24,14 @@ export const getters = {
getAppIntegrations($state) {
return $state.records;
},
getIntegration: $state => integrationId => {
const [integration] = $state.records.filter(
record => record.id === integrationId
);
return integration || {};
},
getIntegration:
$state =>
(integrationId, defaultValue = {}) => {
const [integration] = $state.records.filter(
record => record.id === integrationId
);
return integration || defaultValue;
},
getUIFlags($state) {
return $state.uiFlags;
},