Compare commits

...
Author SHA1 Message Date
Shivam Mishra f601e3b6c7 feat: don't async load picker 2024-10-04 19:12:48 +05:30
Shivam Mishra cb4c179f92 chore: add console.log 2024-10-04 19:04:45 +05:30
Shivam Mishra b2f28b925a fix: use woot button 2024-10-04 18:54:39 +05:30
Shivam Mishra 19a2d5efc0 fix: emoji group 2024-10-04 18:52:35 +05:30
Shivam Mishra 7e8f115b03 feat: fetch emojis from js instead of json 2024-10-04 18:47:32 +05:30
Shivam Mishra 84b00bf71d feat: add prevent 2024-10-04 18:43:19 +05:30
Shivam Mishra 54dd236311 fix: typo 2024-10-04 18:32:05 +05:30
Shivam Mishra bd04d31e62 chore: remove console.log 2024-10-04 18:31:13 +05:30
Shivam Mishra 0602babaa0 fix: route link article viewer 2024-10-04 18:30:25 +05:30
Vishnu NarayananandGitHub 8c54d7f794 feat: support vite build for linux installations(cwctl) (#10231)
- Switch to `pnpm` from `yarn`

Changelog
----
- add support for `pnpm` `vite` build for chatwoot 4.0
- for new installations, install pnpm and vite
- for existing installations, remove `node_modules` and install `pnpm`

Note: `yarn` is not removed when upgrading existing installations. If
you want to rollback to an older version of Chatwoot(pre 4.0),

```
sudo -i -u chatwoot
cd chatwoot
git checkout <tag> # tag is the version of chatwoot you want to rollback to
rm -rf node_modules # remove deps installed via pnpm

# Update dependencies
bundle
yarn

# Recompile the assets
rake assets:precompile RAILS_ENV=production

# Migrate the database schema
RAILS_ENV=production bundle exec rake db:migrate
exit
```
2024-10-04 16:50:44 +05:30
Shivam MishraandGitHub bd88bfb0fe fix: emits for FormSelect and PhoneInput component (#10226) 2024-10-04 15:09:42 +05:30
Vishnu NarayananandGitHub 83100b8f60 feat: support vite build for docker based installations (#10225)
- Switch to `pnpm` from `yarn` for docker builds
2024-10-04 14:20:56 +05:30
PranavandGitHub 0f26351fd3 fix: Update card labels button with a new one to fix the CSS issue (#10222) 2024-10-04 00:00:35 -07:00
Sojan JoseandGitHub 6d053e5816 chore: Move line attachment creation to a single db commit (#10194)
Similar to the work we did with the legacy code of other channels like Twilio, we need to move the message creation and attachment creation to be under a single db commit for the line channel. Otherwise, the emitted webhook events for message creation will miss the attachment payload.


Ref: https://github.com/orgs/chatwoot/discussions/7546#discussioncomment-10814495
Ref: https://github.com/chatwoot/chatwoot/pull/10167
2024-10-03 22:13:41 -07:00
Shivam MishraandGitHub bbb8e57fee fix: Update the styles for the datepicker in custom snooze modal (#10207) 2024-10-03 22:06:51 -07:00
Shivam MishraandGitHub 5eac95732b fix: Update translation payload for audit logs (#10217)
Vue i18n would automatically merge arrays previously, it does not do so now. This PR fixes it by cleaning up the payload before passing it for translation
2024-10-03 22:04:26 -07:00
19 changed files with 9392 additions and 9379 deletions
+1 -1
View File
@@ -1 +1 @@
3.9.0
3.13.0
+1 -1
View File
@@ -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({
@@ -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
+6 -6
View File
@@ -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>
-1
View File
@@ -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>
+1 -1
View File
@@ -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)
+29 -8
View File
@@ -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
View File
@@ -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/