Merge branch 'develop' into chore/vuelidate-v2-migration

This commit is contained in:
Pranav
2024-07-25 16:29:38 -07:00
committed by GitHub
25 changed files with 347 additions and 178 deletions
@@ -1,6 +1,10 @@
table {
@apply border-spacing-0 text-sm w-full;
}
.woot-table {
thead {
th {
@apply font-semibold tracking-[1px] text-left px-2.5 uppercase text-slate-900 dark:text-slate-200;
@@ -16,9 +20,7 @@ table {
@apply p-2.5 text-slate-700 dark:text-slate-100;
}
}
}
.woot-table {
tr {
.show-if-hover {
transition: opacity 0.2s $swift-ease-out-function;
@@ -1,34 +1,40 @@
<script setup>
import router from '../../routes/index';
const props = defineProps({
backUrl: {
type: [String, Object],
default: '',
},
buttonLabel: {
type: String,
default: '',
},
compact: {
type: Boolean,
default: false,
},
});
const goBack = () => {
if (props.backUrl !== '') {
router.push(props.backUrl);
} else {
router.go(-1);
}
};
const buttonStyleClass = props.compact
? 'text-sm text-slate-600 dark:text-slate-300'
: 'text-base text-woot-500 dark:text-woot-500';
</script>
<template>
<button
class="header-section flex items-center text-base font-normal mr-4 ml-2 p-0 cursor-pointer text-woot-500 dark:text-woot-500"
class="flex items-center font-normal p-0 cursor-pointer"
:class="buttonStyleClass"
@click.capture="goBack"
>
<fluent-icon icon="chevron-left" />
<fluent-icon icon="chevron-left" class="-ml-1" />
{{ buttonLabel || $t('GENERAL_SETTINGS.BACK') }}
</button>
</template>
<script>
import router from '../../routes/index';
export default {
props: {
backUrl: {
type: [String, Object],
default: '',
},
buttonLabel: {
type: String,
default: '',
},
},
methods: {
goBack() {
if (this.backUrl !== '') {
router.push(this.backUrl);
} else {
router.go(-1);
}
},
},
};
</script>
@@ -1,4 +1,20 @@
const FEATURE_HELP_URLS = {
channel_email: 'https://chwt.app/hc/email',
channel_facebook: 'https://chwt.app/hc/fb',
help_center: 'https://chwt.app/hc/help-center',
agent_bots: 'https://chwt.app/hc/agent-bots',
team_management: 'https://chwt.app/hc/teams',
labels: 'https://chwt.app/hc/labels',
custom_attributes: 'https://chwt.app/hc/custom-attributes',
canned_responses: 'https://chwt.app/hc/canned',
integrations: 'https://chwt.app/hc/integrations',
campaigns: 'https://chwt.app/hc/campaigns',
reports: 'https://chwt.app/hc/reports',
message_reply_to: 'https://chwt.app/hc/reply-to',
sla: 'https://chwt.app/hc/sla',
dashboard_apps: 'https://chwt.app/hc/dashboard-apps',
};
export function getHelpUrlForFeature(featureName) {
const { helpUrls } = window.chatwootConfig;
return helpUrls[featureName];
return FEATURE_HELP_URLS[featureName];
}
@@ -172,6 +172,7 @@
"HEADER_BTN_TXT": "Add a new dashboard app",
"SIDEBAR_TXT": "<p><b>Dashboard Apps</b></p><p>Dashboard Apps allow organizations to embed an application inside the Chatwoot dashboard to provide the context for customer support agents. This feature allows you to create an application independently and embed that inside the dashboard to provide user information, their orders, or their previous payment history.</p><p>When you embed your application using the dashboard in Chatwoot, your application will get the context of the conversation and contact as a window event. Implement a listener for the message event on your page to receive the context.</p><p>To add a new dashboard app, click on the button 'Add a new dashboard app'.</p>",
"DESCRIPTION": "Dashboard Apps allow organizations to embed an application inside the dashboard to provide the context for customer support agents. This feature allows you to create an application independently and embed that to provide user information, their orders, or their previous payment history.",
"LEARN_MORE": "Learn more about Dashboard Apps",
"LIST": {
"404": "There are no dashboard apps configured on this account yet",
"LOADING": "Fetching dashboard apps...",
@@ -10,6 +10,7 @@
v-if="showBackButton"
:button-label="backButtonLabel"
:back-url="backUrl"
class="ml-2 mr-4"
/>
<fluent-icon
v-if="icon"
@@ -9,7 +9,7 @@ defineProps({
<template>
<div
class="flex flex-col w-full h-full m-0 px-8 lg:px-16 py-8 overflow-auto bg-white dark:bg-slate-900"
class="flex flex-col w-full h-full m-0 p-6 sm:py-8 lg:px-16 overflow-auto bg-white dark:bg-slate-900 font-inter"
>
<div class="flex items-start w-full max-w-6xl mx-auto">
<keep-alive v-if="keepAlive">
@@ -1,6 +1,7 @@
<script setup>
import CustomBrandPolicyWrapper from 'dashboard/components/CustomBrandPolicyWrapper.vue';
import { getHelpUrlForFeature } from '../../../../helper/featureHelper';
import BackButton from '../../../../components/widgets/BackButton.vue';
const props = defineProps({
title: {
type: String,
@@ -22,6 +23,10 @@ const props = defineProps({
type: String,
default: '',
},
backButtonLabel: {
type: String,
default: '',
},
});
const helpURL = getHelpUrlForFeature(props.featureName);
@@ -33,7 +38,12 @@ const openInNewTab = url => {
</script>
<template>
<div class="flex flex-col items-start w-full gap-3 pt-4">
<div class="flex flex-col items-start w-full gap-2 pt-4">
<BackButton
v-if="backButtonLabel"
compact
:button-label="backButtonLabel"
/>
<div class="flex items-center justify-between w-full gap-4">
<div class="flex items-center gap-3">
<div
@@ -64,7 +74,7 @@ const openInNewTab = url => {
</div>
<div class="flex flex-col gap-3 text-slate-600 dark:text-slate-300 w-full">
<p
class="mb-0 text-base font-normal line-clamp-5 sm:line-clamp-none max-w-3xl"
class="mb-0 text-base font-normal line-clamp-5 sm:line-clamp-none max-w-3xl tracking-[-0.1px]"
>
<slot name="description">{{ description }}</slot>
</p>
@@ -74,7 +84,7 @@ const openInNewTab = url => {
:href="helpURL"
target="_blank"
rel="noopener noreferrer"
class="sm:inline-flex hidden tracking-[-0.6%] gap-1 w-fit items-center text-woot-500 dark:text-woot-500 text-sm font-medium tracking=[-0.6%] hover:underline"
class="sm:inline-flex hidden gap-1 w-fit items-center text-woot-500 dark:text-woot-500 text-sm font-medium hover:underline"
>
{{ linkText }}
<fluent-icon
@@ -86,14 +96,16 @@ const openInNewTab = url => {
</a>
</CustomBrandPolicyWrapper>
</div>
<div class="flex items-start justify-start w-full gap-3 sm:hidden">
<div
class="flex items-start justify-start w-full gap-3 sm:hidden flex-wrap"
>
<slot name="actions" />
<CustomBrandPolicyWrapper :show-on-custom-branded-instance="false">
<woot-button
v-if="helpURL && linkText"
color-scheme="secondary"
icon="arrow-outwards"
class="flex-row-reverse rounded-xl min-w-0 !bg-slate-50 !text-slate-900 dark:!text-white dark:!bg-slate-800"
class="flex-row-reverse rounded-md min-w-0 !bg-slate-50 !text-slate-900 dark:!text-white dark:!bg-slate-800"
@click="openInNewTab(helpURL)"
>
{{ linkText }}
@@ -1,12 +1,26 @@
<script setup>
defineProps({
app: {
type: Object,
default: () => ({}),
},
});
defineEmits(['edit', 'delete']);
</script>
<template>
<tr>
<td class="w-40 max-w-[10rem] truncate" :title="app.title">
<tr class="py-1 max-w-full">
<td
class="py-4 pr-4 text-sm w-40 max-w-[10rem] truncate"
:title="app.title"
>
{{ app.title }}
</td>
<td class="max-w-xs truncate" :title="app.content[0].url">
<td class="py-4 pr-4 text-sm max-w-lg truncate" :title="app.content[0].url">
{{ app.content[0].url }}
</td>
<td class="flex justify-end gap-1">
<td class="py-4 pr-4 text-sm flex gap-2 sm:pr-0">
<woot-button
v-tooltip.top="
$t('INTEGRATION_SETTINGS.DASHBOARD_APPS.LIST.EDIT_TOOLTIP')
@@ -32,30 +46,3 @@
</td>
</tr>
</template>
<script>
export default {
loading: {
type: Boolean,
default: false,
},
props: {
app: {
type: Object,
default: () => ({}),
},
},
};
</script>
<style lang="scss" scoped>
.dashboard-app-label-url {
@apply relative w-full;
&:before {
@apply invisible content-['&nbsp'];
}
span {
@apply absolute left-0 right-0;
}
}
</style>
@@ -1,95 +1,14 @@
<template>
<div class="flex-1 p-4 overflow-auto">
<woot-button
color-scheme="success"
class-names="button--fixed-top"
icon="add-circle"
@click="openCreatePopup"
>
{{ $t('INTEGRATION_SETTINGS.DASHBOARD_APPS.HEADER_BTN_TXT') }}
</woot-button>
<div class="flex flex-row gap-4">
<div class="w-full lg:w-3/5">
<p
v-if="!uiFlags.isFetching && !records.length"
class="flex flex-col items-center justify-center h-full"
>
{{ $t('INTEGRATION_SETTINGS.DASHBOARD_APPS.LIST.404') }}
</p>
<woot-loading-state
v-if="uiFlags.isFetching"
:message="$t('INTEGRATION_SETTINGS.DASHBOARD_APPS.LIST.LOADING')"
/>
<table v-if="!uiFlags.isFetching && records.length" class="woot-table">
<thead>
<th
v-for="thHeader in $t(
'INTEGRATION_SETTINGS.DASHBOARD_APPS.LIST.TABLE_HEADER'
)"
:key="thHeader"
>
{{ thHeader }}
</th>
</thead>
<tbody>
<dashboard-apps-row
v-for="(dashboardAppItem, index) in records"
:key="dashboardAppItem.id"
:index="index"
:app="dashboardAppItem"
@edit="editApp"
@delete="openDeletePopup"
/>
</tbody>
</table>
</div>
<div class="hidden w-1/3 lg:block">
<span
v-dompurify-html="
useInstallationName(
$t('INTEGRATION_SETTINGS.DASHBOARD_APPS.SIDEBAR_TXT'),
globalConfig.installationName
)
"
/>
</div>
</div>
<dashboard-app-modal
v-if="showDashboardAppPopup"
:show="showDashboardAppPopup"
:mode="mode"
:selected-app-data="selectedApp"
@close="toggleDashboardAppPopup"
/>
<woot-delete-modal
:show.sync="showDeleteConfirmationPopup"
:on-close="closeDeletePopup"
:on-confirm="confirmDeletion"
:title="$t('INTEGRATION_SETTINGS.DASHBOARD_APPS.DELETE.TITLE')"
:message="
$t('INTEGRATION_SETTINGS.DASHBOARD_APPS.DELETE.MESSAGE', {
appName: selectedApp.title,
})
"
:confirm-text="
$t('INTEGRATION_SETTINGS.DASHBOARD_APPS.DELETE.CONFIRM_YES')
"
:reject-text="$t('INTEGRATION_SETTINGS.DASHBOARD_APPS.DELETE.CONFIRM_NO')"
/>
</div>
</template>
<script>
import { mapGetters } from 'vuex';
import { useAlert } from 'dashboard/composables';
import DashboardAppModal from './DashboardAppModal.vue';
import DashboardAppsRow from './DashboardAppsRow.vue';
import globalConfigMixin from 'shared/mixins/globalConfigMixin';
import BaseSettingsHeader from '../../components/BaseSettingsHeader.vue';
export default {
components: {
BaseSettingsHeader,
DashboardAppModal,
DashboardAppsRow,
},
@@ -156,3 +75,87 @@ export default {
},
};
</script>
<template>
<div class="flex-1 overflow-auto flex gap-8 flex-col">
<BaseSettingsHeader
:title="$t('INTEGRATION_SETTINGS.DASHBOARD_APPS.TITLE')"
:description="$t('INTEGRATION_SETTINGS.DASHBOARD_APPS.DESCRIPTION')"
:link-text="$t('INTEGRATION_SETTINGS.DASHBOARD_APPS.LEARN_MORE')"
feature-name="dashboard_apps"
:back-button-label="$t('INTEGRATION_SETTINGS.HEADER')"
>
<template #actions>
<woot-button
class="button nice rounded-md"
icon="add-circle"
@click="openCreatePopup"
>
{{ $t('INTEGRATION_SETTINGS.DASHBOARD_APPS.HEADER_BTN_TXT') }}
</woot-button>
</template>
</BaseSettingsHeader>
<div class="w-full text-slate-700 dark:text-slate-200 overflow-x-auto">
<p
v-if="!uiFlags.isFetching && !records.length"
class="flex flex-col items-center justify-center h-full"
>
{{ $t('INTEGRATION_SETTINGS.DASHBOARD_APPS.LIST.404') }}
</p>
<woot-loading-state
v-if="uiFlags.isFetching"
:message="$t('INTEGRATION_SETTINGS.DASHBOARD_APPS.LIST.LOADING')"
/>
<table
v-if="!uiFlags.isFetching && records.length"
class="min-w-full divide-y divide-slate-75 dark:divide-slate-700"
>
<thead>
<th
v-for="thHeader in $t(
'INTEGRATION_SETTINGS.DASHBOARD_APPS.LIST.TABLE_HEADER'
)"
:key="thHeader"
class="py-4 pr-4 text-left font-semibold text-slate-700 dark:text-slate-300"
>
{{ thHeader }}
</th>
</thead>
<tbody class="divide-y divide-slate-50 dark:divide-slate-800">
<dashboard-apps-row
v-for="(dashboardAppItem, index) in records"
:key="dashboardAppItem.id"
:index="index"
:app="dashboardAppItem"
@edit="editApp"
@delete="openDeletePopup"
/>
</tbody>
</table>
</div>
<dashboard-app-modal
v-if="showDashboardAppPopup"
:show="showDashboardAppPopup"
:mode="mode"
:selected-app-data="selectedApp"
@close="toggleDashboardAppPopup"
/>
<woot-delete-modal
:show.sync="showDeleteConfirmationPopup"
:on-close="closeDeletePopup"
:on-confirm="confirmDeletion"
:title="$t('INTEGRATION_SETTINGS.DASHBOARD_APPS.DELETE.TITLE')"
:message="
$t('INTEGRATION_SETTINGS.DASHBOARD_APPS.DELETE.MESSAGE', {
appName: selectedApp.title,
})
"
:confirm-text="
$t('INTEGRATION_SETTINGS.DASHBOARD_APPS.DELETE.CONFIRM_YES')
"
:reject-text="$t('INTEGRATION_SETTINGS.DASHBOARD_APPS.DELETE.CONFIRM_NO')"
/>
</div>
</template>
@@ -33,7 +33,7 @@ onMounted(() => {
/>
</template>
<template #body>
<div class="flex-grow flex-shrink overflow-auto font-inter">
<div class="flex-grow flex-shrink overflow-auto">
<div class="grid grid-cols-1 md:grid-cols-2 xl:grid-cols-3 gap-4">
<integration-item
v-for="item in integrationList"
@@ -22,9 +22,16 @@ export default {
permissions: ['administrator'],
},
},
{
path: 'dashboard_apps',
component: DashboardApps,
name: 'settings_integrations_dashboard_apps',
meta: {
permissions: ['administrator'],
},
},
],
},
{
path: frontendURL('accounts/:accountId/settings/integrations'),
component: SettingsContent,
@@ -50,14 +57,6 @@ export default {
permissions: ['administrator'],
},
},
{
path: 'dashboard_apps',
component: DashboardApps,
name: 'settings_integrations_dashboard_apps',
meta: {
permissions: ['administrator'],
},
},
{
path: 'slack',
name: 'settings_integrations_slack',