Compare commits
16
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f601e3b6c7 | ||
|
|
cb4c179f92 | ||
|
|
b2f28b925a | ||
|
|
19a2d5efc0 | ||
|
|
7e8f115b03 | ||
|
|
84b00bf71d | ||
|
|
54dd236311 | ||
|
|
bd04d31e62 | ||
|
|
0602babaa0 | ||
|
|
8c54d7f794 | ||
|
|
bd88bfb0fe | ||
|
|
83100b8f60 | ||
|
|
0f26351fd3 | ||
|
|
6d053e5816 | ||
|
|
bbb8e57fee | ||
|
|
5eac95732b |
+1
-1
@@ -1 +1 @@
|
||||
3.9.0
|
||||
3.13.0
|
||||
|
||||
+1
-1
@@ -1 +1 @@
|
||||
2.8.0
|
||||
3.0.0
|
||||
|
||||
@@ -44,15 +44,18 @@ export default {
|
||||
<template>
|
||||
<div class="flex flex-col">
|
||||
<woot-modal-header :header-title="$t('CONVERSATION.CUSTOM_SNOOZE.TITLE')" />
|
||||
<form class="modal-content" @submit.prevent="chooseTime">
|
||||
<form
|
||||
class="modal-content w-full pt-2 px-5 pb-6"
|
||||
@submit.prevent="chooseTime"
|
||||
>
|
||||
<DatePicker
|
||||
v-model:value="snoozeTime"
|
||||
type="datetime"
|
||||
inline
|
||||
input-class="mx-input reset-base"
|
||||
:lang="lang"
|
||||
:disabled-date="disabledDate"
|
||||
:disabled-time="disabledTime"
|
||||
:popup-style="{ width: '100%' }"
|
||||
/>
|
||||
<div class="flex flex-row justify-end w-full gap-2 px-0 py-2">
|
||||
<woot-button variant="clear" @click.prevent="onClose">
|
||||
@@ -65,9 +68,3 @@ export default {
|
||||
</form>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.modal-content {
|
||||
@apply pt-2 px-5 pb-6;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<script setup>
|
||||
import { shallowRef, computed, onMounted } from 'vue';
|
||||
import emojiGroups from 'shared/components/emoji/emojisGroup.json';
|
||||
import emojiGroups from 'shared/components/emoji/emojisGroup';
|
||||
import MentionBox from '../mentions/MentionBox.vue';
|
||||
|
||||
const props = defineProps({
|
||||
|
||||
+8
-22
@@ -79,35 +79,21 @@ const onShowLabels = e => {
|
||||
'invisible absolute': !showAllLabels && index > labelPosition,
|
||||
}"
|
||||
/>
|
||||
<woot-button
|
||||
<button
|
||||
v-if="showExpandLabelButton"
|
||||
:title="
|
||||
showAllLabels
|
||||
? $t('CONVERSATION.CARD.HIDE_LABELS')
|
||||
: $t('CONVERSATION.CARD.SHOW_LABELS')
|
||||
"
|
||||
class="sticky right-0 flex-shrink-0 mr-6 show-more--button rtl:rotate-180"
|
||||
color-scheme="secondary"
|
||||
variant="hollow"
|
||||
:icon="showAllLabels ? 'chevron-left' : 'chevron-right'"
|
||||
size="tiny"
|
||||
class="h-5 py-0 px-1 flex-shrink-0 mr-6 ml-0 rtl:ml-6 rtl:mr-0 rtl:rotate-180 text-slate-700 dark:text-slate-200 hover:border-slate-300 border-slate-100 dark:border-slate-700"
|
||||
@click="onShowLabels"
|
||||
/>
|
||||
>
|
||||
<fluent-icon
|
||||
:icon="showAllLabels ? 'chevron-left' : 'chevron-right'"
|
||||
size="12"
|
||||
/>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.show-more--button {
|
||||
@apply h-5;
|
||||
&.secondary:focus {
|
||||
@apply text-slate-700 dark:text-slate-200 border-slate-300 dark:border-slate-700;
|
||||
}
|
||||
}
|
||||
|
||||
.labels-wrap {
|
||||
.secondary {
|
||||
@apply border border-solid border-slate-100 dark:border-slate-700;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -8,7 +8,7 @@ import {
|
||||
|
||||
export default {
|
||||
props: {
|
||||
value: {
|
||||
modelValue: {
|
||||
type: [String, Number],
|
||||
default: '',
|
||||
},
|
||||
@@ -29,7 +29,7 @@ export default {
|
||||
default: false,
|
||||
},
|
||||
},
|
||||
emits: ['blur', 'input', 'setCode'],
|
||||
emits: ['blur', 'setCode', 'update:modelValue'],
|
||||
data() {
|
||||
return {
|
||||
selectedIndex: -1,
|
||||
@@ -37,7 +37,7 @@ export default {
|
||||
searchCountry: '',
|
||||
activeCountryCode: getActiveCountryCode(),
|
||||
activeDialCode: getActiveDialCode(),
|
||||
phoneNumber: this.value,
|
||||
phoneNumber: this.modelValue,
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
@@ -76,12 +76,12 @@ export default {
|
||||
},
|
||||
},
|
||||
watch: {
|
||||
value() {
|
||||
const number = parsePhoneNumber(this.value);
|
||||
modelValue() {
|
||||
const number = parsePhoneNumber(this.modelValue);
|
||||
if (number) {
|
||||
this.activeCountryCode = number.country;
|
||||
this.activeDialCode = `+${number.countryCallingCode}`;
|
||||
this.phoneNumber = this.value.replace(
|
||||
this.phoneNumber = this.modelValue.replace(
|
||||
`+${number.countryCallingCode}`,
|
||||
''
|
||||
);
|
||||
@@ -103,7 +103,8 @@ export default {
|
||||
},
|
||||
onChange(e) {
|
||||
this.phoneNumber = e.target.value;
|
||||
this.$emit('input', e.target.value, this.activeDialCode);
|
||||
this.$emit('update:modelValue', e.target.value);
|
||||
this.$emit('setCode', this.activeDialCode);
|
||||
},
|
||||
onBlur(e) {
|
||||
this.$emit('blur', e.target.value);
|
||||
|
||||
@@ -201,9 +201,6 @@ export default {
|
||||
}
|
||||
return contactObject;
|
||||
},
|
||||
onPhoneNumberInputChange(value, code) {
|
||||
this.activeDialCode = code;
|
||||
},
|
||||
setPhoneCode(code) {
|
||||
if (this.phoneNumber !== '' && this.parsePhoneNumber) {
|
||||
const dialCode = this.parsePhoneNumber.countryCallingCode;
|
||||
@@ -336,7 +333,6 @@ export default {
|
||||
:value="phoneNumber"
|
||||
:error="isPhoneNumberNotValid"
|
||||
:placeholder="$t('CONTACT_FORM.FORM.PHONE_NUMBER.PLACEHOLDER')"
|
||||
@input="onPhoneNumberInputChange"
|
||||
@blur="v$.phoneNumber.$touch"
|
||||
@set-code="setPhoneCode"
|
||||
/>
|
||||
|
||||
@@ -35,13 +35,19 @@ const fetchAuditLogs = page => {
|
||||
};
|
||||
|
||||
const generateLogText = auditLogItem => {
|
||||
const translationPayload = generateTranslationPayload(
|
||||
auditLogItem,
|
||||
agentList.value
|
||||
);
|
||||
const payload = generateTranslationPayload(auditLogItem, agentList.value);
|
||||
const translationKey = generateLogActionKey(auditLogItem);
|
||||
|
||||
return t(translationKey, translationPayload);
|
||||
const joinIfArray = value => {
|
||||
return Array.isArray(value) ? value.join(', ') : value;
|
||||
};
|
||||
|
||||
const mergedPayload = {
|
||||
...payload,
|
||||
attributes: joinIfArray(payload.attributes),
|
||||
values: joinIfArray(payload.values),
|
||||
};
|
||||
return t(translationKey, mergedPayload);
|
||||
};
|
||||
|
||||
const onPageChange = page => {
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
<script>
|
||||
import emojis from './emojisGroup.json';
|
||||
import emojis from './emojisGroup';
|
||||
import FluentIcon from 'shared/components/FluentIcon/Index.vue';
|
||||
import WootButton from 'dashboard/components/ui/WootButton.vue';
|
||||
const SEARCH_KEY = 'Search';
|
||||
|
||||
export default {
|
||||
components: { FluentIcon },
|
||||
components: { FluentIcon, WootButton },
|
||||
props: {
|
||||
onClick: {
|
||||
type: Function,
|
||||
@@ -97,7 +98,7 @@ export default {
|
||||
class="emoji-search--input focus:box-shadow-blue dark:focus:box-shadow-dark !mb-0 !h-8 !text-sm"
|
||||
:placeholder="$t('EMOJI.PLACEHOLDER')"
|
||||
/>
|
||||
<woot-button
|
||||
<WootButton
|
||||
v-if="showRemoveButton"
|
||||
size="small"
|
||||
variant="smooth"
|
||||
@@ -106,7 +107,7 @@ export default {
|
||||
@click="onClick('')"
|
||||
>
|
||||
{{ $t('EMOJI.REMOVE') }}
|
||||
</woot-button>
|
||||
</WootButton>
|
||||
</div>
|
||||
<div v-if="hasNoSearch" ref="emojiItem" class="emoji-item">
|
||||
<h5 class="emoji-category--title">
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -29,7 +29,7 @@ export default {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
value: {
|
||||
modelValue: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
@@ -42,10 +42,10 @@ export default {
|
||||
default: '',
|
||||
},
|
||||
},
|
||||
emits: ['input'],
|
||||
emits: ['update:modelValue'],
|
||||
methods: {
|
||||
onInput(e) {
|
||||
this.$emit('input', e.target.value);
|
||||
this.$emit('update:modelValue', e.target.value);
|
||||
},
|
||||
},
|
||||
};
|
||||
@@ -61,11 +61,11 @@ export default {
|
||||
>
|
||||
<select
|
||||
:id="id"
|
||||
:selected="value"
|
||||
:selected="modelValue"
|
||||
:name="name"
|
||||
:class="{
|
||||
'text-ash-400': !value,
|
||||
'text-ash-900': value,
|
||||
'text-ash-400': !modelValue,
|
||||
'text-ash-900': modelValue,
|
||||
'pl-9': icon,
|
||||
}"
|
||||
class="block w-full px-3 py-2 pr-6 mb-0 border-0 shadow-sm outline-none appearance-none rounded-xl select-caret ring-ash-200 ring-1 ring-inset placeholder:text-ash-900 focus:ring-2 focus:ring-inset focus:ring-primary-500 sm:text-sm sm:leading-6"
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
<script>
|
||||
import { defineAsyncComponent } from 'vue';
|
||||
import { mapGetters } from 'vuex';
|
||||
|
||||
import ChatAttachmentButton from 'widget/components/ChatAttachment.vue';
|
||||
@@ -8,10 +7,7 @@ import configMixin from '../mixins/configMixin';
|
||||
import FluentIcon from 'shared/components/FluentIcon/Index.vue';
|
||||
import ResizableTextArea from 'shared/components/ResizableTextArea.vue';
|
||||
import { useDarkMode } from 'widget/composables/useDarkMode';
|
||||
|
||||
const EmojiInput = defineAsyncComponent(
|
||||
() => import('shared/components/emoji/EmojiInput.vue')
|
||||
);
|
||||
import EmojiInput from 'shared/components/emoji/EmojiInput.vue';
|
||||
|
||||
export default {
|
||||
name: 'ChatInputWrap',
|
||||
@@ -162,9 +158,10 @@ export default {
|
||||
/>
|
||||
<button
|
||||
v-if="hasEmojiPickerEnabled"
|
||||
type="button"
|
||||
class="flex items-center justify-center icon-button"
|
||||
:aria-label="$t('EMOJI.ARIA_LABEL')"
|
||||
@click="toggleEmojiPicker"
|
||||
@click.prevent="toggleEmojiPicker"
|
||||
>
|
||||
<FluentIcon icon="emoji" :class="emojiIconColor" />
|
||||
</button>
|
||||
|
||||
@@ -36,7 +36,6 @@ export default createRouter({
|
||||
{
|
||||
path: '/article',
|
||||
name: 'article-viewer',
|
||||
props: true,
|
||||
component: () => import('./views/ArticleViewer.vue'),
|
||||
},
|
||||
],
|
||||
|
||||
@@ -6,17 +6,11 @@ export default {
|
||||
components: {
|
||||
IframeLoader,
|
||||
},
|
||||
props: {
|
||||
link: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="bg-white h-full">
|
||||
<IframeLoader :url="link" />
|
||||
<IframeLoader :url="$route.query.link" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -79,7 +79,7 @@ export default {
|
||||
}
|
||||
this.$router.push({
|
||||
name: 'article-viewer',
|
||||
params: { link: linkToOpen },
|
||||
query: { link: linkToOpen },
|
||||
});
|
||||
},
|
||||
viewAllArticles() {
|
||||
|
||||
@@ -25,13 +25,14 @@ class Line::IncomingMessageService
|
||||
next unless message_created? event
|
||||
|
||||
attach_files event['message']
|
||||
@message.save!
|
||||
end
|
||||
end
|
||||
|
||||
def message_created?(event)
|
||||
return unless event_type_message?(event)
|
||||
|
||||
@message = @conversation.messages.create!(
|
||||
@message = @conversation.messages.build(
|
||||
content: message_content(event),
|
||||
account_id: @inbox.account_id,
|
||||
content_type: message_content_type(event),
|
||||
@@ -90,7 +91,6 @@ class Line::IncomingMessageService
|
||||
content_type: response.content_type
|
||||
}
|
||||
)
|
||||
@message.save!
|
||||
end
|
||||
|
||||
def event_type_message?(event)
|
||||
|
||||
@@ -19,7 +19,7 @@ fi
|
||||
# option --output/-o requires 1 argument
|
||||
LONGOPTS=console,debug,help,install,Install:,logs:,restart,ssl,upgrade,webserver,version
|
||||
OPTIONS=cdhiI:l:rsuwv
|
||||
CWCTL_VERSION="2.8.0"
|
||||
CWCTL_VERSION="3.0.0"
|
||||
pg_pass=$(head /dev/urandom | tr -dc A-Za-z0-9 | head -c 15 ; echo '')
|
||||
CHATWOOT_HUB_URL="https://hub.2.chatwoot.com/events"
|
||||
|
||||
@@ -173,8 +173,6 @@ EOF
|
||||
function install_dependencies() {
|
||||
apt update && apt upgrade -y
|
||||
apt install -y curl
|
||||
curl -sS https://dl.yarnpkg.com/debian/pubkey.gpg | apt-key add -
|
||||
echo "deb https://dl.yarnpkg.com/debian/ stable main" | tee /etc/apt/sources.list.d/yarn.list
|
||||
curl -fsSL https://packages.redis.io/gpg | sudo gpg --dearmor -o /usr/share/keyrings/redis-archive-keyring.gpg
|
||||
echo "deb [signed-by=/usr/share/keyrings/redis-archive-keyring.gpg] https://packages.redis.io/deb $(lsb_release -cs) main" | sudo tee /etc/apt/sources.list.d/redis.list
|
||||
mkdir -p /etc/apt/keyrings
|
||||
@@ -189,9 +187,10 @@ function install_dependencies() {
|
||||
libxml2-dev libxslt1-dev file g++ gcc autoconf build-essential \
|
||||
libssl-dev libyaml-dev libreadline-dev gnupg2 \
|
||||
postgresql-client redis-tools \
|
||||
nodejs yarn patch ruby-dev zlib1g-dev liblzma-dev \
|
||||
nodejs patch ruby-dev zlib1g-dev liblzma-dev \
|
||||
libgmp-dev libncurses5-dev libffi-dev libgdbm6 libgdbm-dev sudo \
|
||||
libvips python3-pip
|
||||
npm install -g pnpm
|
||||
}
|
||||
|
||||
##############################################################################
|
||||
@@ -343,7 +342,7 @@ function setup_chatwoot() {
|
||||
cd chatwoot
|
||||
git checkout "$BRANCH"
|
||||
bundle
|
||||
yarn
|
||||
pnpm i
|
||||
|
||||
cp .env.example .env
|
||||
sed -i -e "/SECRET_KEY_BASE/ s/=.*/=$secret/" .env
|
||||
@@ -354,7 +353,7 @@ function setup_chatwoot() {
|
||||
sed -i -e '/RAILS_ENV/ s/=.*/=$RAILS_ENV/' .env
|
||||
echo -en "\nINSTALLATION_ENV=linux_script" >> ".env"
|
||||
|
||||
rake assets:precompile RAILS_ENV=production NODE_OPTIONS=--openssl-legacy-provider
|
||||
rake assets:precompile RAILS_ENV=production NODE_OPTIONS="--max-old-space-size=4096 --openssl-legacy-provider"
|
||||
EOF
|
||||
}
|
||||
|
||||
@@ -793,6 +792,27 @@ function upgrade_node() {
|
||||
|
||||
}
|
||||
|
||||
##############################################################################
|
||||
# Install pnpm - this replaces yarn starting from Chatwoot 4.0
|
||||
# Globals:
|
||||
# None
|
||||
# Arguments:
|
||||
# None
|
||||
# Outputs:
|
||||
# None
|
||||
##############################################################################
|
||||
function get_pnpm() {
|
||||
# if pnpm is already installed, return
|
||||
if command -v pnpm &> /dev/null; then
|
||||
return
|
||||
fi
|
||||
npm install -g pnpm
|
||||
sudo -i -u chatwoot << "EOF"
|
||||
cd chatwoot
|
||||
rm -rf node_modules
|
||||
EOF
|
||||
}
|
||||
|
||||
##############################################################################
|
||||
# Upgrade an existing installation to latest stable version(-u/--upgrade)
|
||||
# Globals:
|
||||
@@ -810,6 +830,7 @@ function upgrade() {
|
||||
upgrade_prereq
|
||||
upgrade_redis
|
||||
upgrade_node
|
||||
get_pnpm
|
||||
sudo -i -u chatwoot << "EOF"
|
||||
|
||||
# Navigate to the Chatwoot directory
|
||||
@@ -826,10 +847,10 @@ function upgrade() {
|
||||
|
||||
# Update dependencies
|
||||
bundle
|
||||
yarn
|
||||
pnpm -i
|
||||
|
||||
# Recompile the assets
|
||||
rake assets:precompile RAILS_ENV=production NODE_OPTIONS=--openssl-legacy-provider
|
||||
rake assets:precompile RAILS_ENV=production NODE_OPTIONS="--max-old-space-size=4096 --openssl-legacy-provider"
|
||||
|
||||
# Migrate the database schema
|
||||
RAILS_ENV=production POSTGRES_STATEMENT_TIMEOUT=600s bundle exec rake db:migrate
|
||||
|
||||
+19
-4
@@ -26,11 +26,22 @@ RUN apk update && apk add --no-cache \
|
||||
postgresql-dev \
|
||||
postgresql-client \
|
||||
nodejs=20.15.1-r0 \
|
||||
yarn \
|
||||
git \
|
||||
&& mkdir -p /var/app \
|
||||
&& gem install bundler
|
||||
|
||||
# Install pnpm and configure environment
|
||||
RUN wget -qO- https://get.pnpm.io/install.sh | ENV="$HOME/.shrc" SHELL="$(which sh)" sh - \
|
||||
&& echo 'export PNPM_HOME="/root/.local/share/pnpm"' >> /root/.shrc \
|
||||
&& echo 'export PATH="$PNPM_HOME:$PATH"' >> /root/.shrc \
|
||||
&& export PNPM_HOME="/root/.local/share/pnpm" \
|
||||
&& export PATH="$PNPM_HOME:$PATH" \
|
||||
&& pnpm --version
|
||||
|
||||
# Persist the environment variables in Docker
|
||||
ENV PNPM_HOME="/root/.local/share/pnpm"
|
||||
ENV PATH="$PNPM_HOME:$PATH"
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
COPY Gemfile Gemfile.lock ./
|
||||
@@ -48,8 +59,8 @@ RUN if [ "$RAILS_ENV" = "production" ]; then \
|
||||
else bundle install -j 4 -r 3; \
|
||||
fi
|
||||
|
||||
COPY package.json yarn.lock ./
|
||||
RUN yarn install
|
||||
COPY package.json pnpm-lock.yaml ./
|
||||
RUN pnpm i
|
||||
|
||||
COPY . /app
|
||||
|
||||
@@ -104,7 +115,11 @@ RUN apk update && apk add --no-cache \
|
||||
&& gem install bundler
|
||||
|
||||
RUN if [ "$RAILS_ENV" != "production" ]; then \
|
||||
apk add --no-cache nodejs-current yarn; \
|
||||
apk add --no-cache nodejs-current; \
|
||||
# Install pnpm and configure environment
|
||||
wget -qO- https://get.pnpm.io/install.sh | ENV="$HOME/.shrc" SHELL="$(which sh)" sh - \
|
||||
&& source /root/.shrc \
|
||||
&& pnpm --version; \
|
||||
fi
|
||||
|
||||
COPY --from=pre-builder /gems/ /gems/
|
||||
|
||||
Reference in New Issue
Block a user