mirror of
https://github.com/lingble/chatwoot.git
synced 2025-11-01 19:48:08 +00:00
Fixes https://github.com/chatwoot/chatwoot/issues/9600 **Summary** - Added manual WhatsApp templates sync functionality accessible via UI - Added refresh button in both inbox settings and template picker modal - Enhanced template picker to always show for WhatsApp Cloud channels (even when empty) **Preview** <img width="1456" height="798" alt="CleanShot 2025-07-22 at 14 15 28@2x" src="https://github.com/user-attachments/assets/8a04ff26-61fa-42ee-a1b8-5e06433ae6e0" /> <img width="2376" height="1574" alt="CleanShot 2025-07-22 at 14 19 24@2x" src="https://github.com/user-attachments/assets/1c772034-04ff-484d-88dd-ca8123e93065" /> --------- Co-authored-by: iamsivin <iamsivin@gmail.com>
99 lines
2.4 KiB
Vue
99 lines
2.4 KiB
Vue
<script setup>
|
|
import { computed } from 'vue';
|
|
import 'highlight.js/styles/default.css';
|
|
import 'highlight.js/lib/common';
|
|
import NextButton from 'dashboard/components-next/button/Button.vue';
|
|
import { copyTextToClipboard } from 'shared/helpers/clipboard';
|
|
import { useAlert } from 'dashboard/composables';
|
|
import { useI18n } from 'vue-i18n';
|
|
|
|
const props = defineProps({
|
|
script: {
|
|
type: String,
|
|
default: '',
|
|
},
|
|
lang: {
|
|
type: String,
|
|
default: 'javascript',
|
|
},
|
|
enableCodePen: {
|
|
type: Boolean,
|
|
default: false,
|
|
},
|
|
codepenTitle: {
|
|
type: String,
|
|
default: 'Chatwoot Codepen',
|
|
},
|
|
});
|
|
|
|
const { t } = useI18n();
|
|
|
|
const scrubbedScript = computed(() => {
|
|
// remove trailing and leading extra lines and not spaces
|
|
const scrubbed = props.script.replace(/^\s*[\r\n]/gm, '');
|
|
const lines = scrubbed.split('\n');
|
|
|
|
// remove extra indentations
|
|
const minIndent = lines.reduce((min, line) => {
|
|
if (line.trim().length === 0) return min;
|
|
const indent = line.match(/^\s*/)[0].length;
|
|
return Math.min(min, indent);
|
|
}, Infinity);
|
|
|
|
return lines.map(line => line.slice(minIndent)).join('\n');
|
|
});
|
|
|
|
const codepenScriptValue = computed(() => {
|
|
const lang = props.lang === 'javascript' ? 'js' : props.lang;
|
|
return JSON.stringify({
|
|
title: props.codepenTitle,
|
|
private: true,
|
|
[lang]: scrubbedScript.value,
|
|
});
|
|
});
|
|
|
|
const onCopy = async e => {
|
|
e.preventDefault();
|
|
await copyTextToClipboard(scrubbedScript.value);
|
|
useAlert(t('COMPONENTS.CODE.COPY_SUCCESSFUL'));
|
|
};
|
|
</script>
|
|
|
|
<template>
|
|
<div class="relative text-left">
|
|
<div
|
|
class="top-1.5 absolute ltr:right-1.5 rtl:left-1.5 flex items-center gap-1"
|
|
>
|
|
<form
|
|
v-if="enableCodePen"
|
|
class="flex items-center"
|
|
action="https://codepen.io/pen/define"
|
|
method="POST"
|
|
target="_blank"
|
|
>
|
|
<input type="hidden" name="data" :value="codepenScriptValue" />
|
|
<NextButton
|
|
slate
|
|
xs
|
|
type="submit"
|
|
faded
|
|
:label="t('COMPONENTS.CODE.CODEPEN')"
|
|
/>
|
|
</form>
|
|
<NextButton
|
|
slate
|
|
xs
|
|
faded
|
|
:label="t('COMPONENTS.CODE.BUTTON_TEXT')"
|
|
@click="onCopy"
|
|
/>
|
|
</div>
|
|
<highlightjs
|
|
v-if="script"
|
|
:language="lang"
|
|
:code="scrubbedScript"
|
|
class="[&_code]:ltr:!pr-16 [&_code]:rtl:!pl-16 [&_code]:truncate [&_code]:text-start"
|
|
/>
|
|
</div>
|
|
</template>
|