Chore: Use installation config in frontend (#847)

* Use installation config in widget
* Add configuration for installation in UI
* Add config for mailer

Co-authored-by: Sojan <sojan@pepalo.com>
This commit is contained in:
Pranav Raj S 2020-05-12 01:31:40 +05:30 committed by GitHub
parent c74b5c21d7
commit f819bc0f33
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
22 changed files with 264 additions and 49 deletions

View file

@ -2,7 +2,7 @@
<aside class="sidebar animated shrink columns">
<div class="logo">
<router-link :to="dashboardPath" replace>
<img src="~dashboard/assets/images/woot-logo.svg" alt="Woot-logo" />
<img :src="globalConfig.logo" :alt="globalConfig.installationName" />
</router-link>
</div>
@ -104,10 +104,11 @@ export default {
},
computed: {
...mapGetters({
daysLeft: 'getTrialLeft',
subscriptionData: 'getSubscription',
inboxes: 'inboxes/getInboxes',
currentUser: 'getCurrentUser',
daysLeft: 'getTrialLeft',
globalConfig: 'globalConfig/get',
inboxes: 'inboxes/getInboxes',
subscriptionData: 'getSubscription',
}),
accessibleMenuItems() {
// get all keys in menuGroup

View file

@ -27,11 +27,17 @@
<script>
/* eslint no-console: 0 */
import globalConfigMixin from 'shared/mixins/globalConfigMixin';
export default {
mixins: [globalConfigMixin],
props: {
isFullwidth: Boolean,
items: {
type: Array,
default: () => [],
},
},
computed: {
classObject() {
return 'full-width';
@ -39,9 +45,6 @@ export default {
activeIndex() {
return this.items.findIndex(i => i.route === this.$route.name);
},
items() {
return this.$t('INBOX_MGMT.CREATE_FLOW');
},
},
methods: {
isActive(item) {

View file

@ -2,8 +2,8 @@
<div class="medium-10 column signup">
<div class="text-center medium-12 signup--hero">
<img
src="~dashboard/assets/images/woot-logo.svg"
alt="Woot-logo"
:src="globalConfig.logo"
:alt="globalConfig.installationName"
class="hero--logo"
/>
<h2 class="hero--title">
@ -58,13 +58,18 @@
button-class="large expanded"
>
</woot-submit-button>
<p class="accept--terms" v-html="$t('REGISTER.TERMS_ACCEPT')"></p>
<p class="accept--terms" v-html="termsLink"></p>
</div>
</form>
<div class="column text-center sigin--footer">
<span>Already have an account?</span>
<router-link to="/app/login">
{{ $t('LOGIN.TITLE') }}
{{
useInstallationName(
$t('LOGIN.TITLE'),
globalConfig.installationName
)
}}
</router-link>
</div>
</div>
@ -77,12 +82,13 @@
import { required, minLength, email } from 'vuelidate/lib/validators';
import Auth from '../../api/auth';
import { mapGetters } from 'vuex';
import globalConfigMixin from 'shared/mixins/globalConfigMixin';
export default {
mixins: [globalConfigMixin],
data() {
return {
// We need to initialize the component with any
// properties that will be used in it
credentials: {
name: '',
email: '',
@ -106,6 +112,19 @@ export default {
},
},
},
computed: {
...mapGetters({
globalConfig: 'globalConfig/get',
}),
termsLink() {
return this.$t('REGISTER.TERMS_ACCEPT')
.replace('https://www.chatwoot.com/terms', this.globalConfig.termsURL)
.replace(
'https://www.chatwoot.com/privacy-policy',
this.globalConfig.privacyURL
);
},
},
methods: {
showAlert(message) {
// Reset loading, current selected agent

View file

@ -74,7 +74,14 @@
</div>
</div>
<div class="small-4 columns">
<span v-html="$t('AGENT_MGMT.SIDEBAR_TXT')"></span>
<span
v-html="
useInstallationName(
$t('AGENT_MGMT.SIDEBAR_TXT'),
globalConfig.installationName
)
"
/>
</div>
</div>
<!-- Add Agent -->
@ -108,8 +115,8 @@
/* global bus */
import { mapGetters } from 'vuex';
import globalConfigMixin from 'shared/mixins/globalConfigMixin';
import Thumbnail from '../../../../components/widgets/Thumbnail';
import AddAgent from './AddAgent';
import EditAgent from './EditAgent';
import DeleteAgent from './DeleteAgent';
@ -121,6 +128,7 @@ export default {
DeleteAgent,
Thumbnail,
},
mixins: [globalConfigMixin],
data() {
return {
loading: {},
@ -138,6 +146,7 @@ export default {
agentList: 'agents/getAgents',
uiFlags: 'agents/getUIFlags',
currentUserId: 'getCurrentUserID',
globalConfig: 'globalConfig/get',
}),
deleteConfirmText() {
return `${this.$t('AGENT_MGMT.DELETE.CONFIRM.YES')} ${

View file

@ -1,6 +1,33 @@
<template>
<div class="row content-box full-height">
<woot-wizard class="small-3 columns"></woot-wizard>
<woot-wizard
class="small-3 columns"
:global-config="globalConfig"
:items="items"
/>
<router-view></router-view>
</div>
</template>
<script>
import { mapGetters } from 'vuex';
import globalConfigMixin from 'shared/mixins/globalConfigMixin';
export default {
mixins: [globalConfigMixin],
computed: {
...mapGetters({
globalConfig: 'globalConfig/get',
}),
items() {
return this.$t('INBOX_MGMT.CREATE_FLOW').map(item => ({
...item,
body: this.useInstallationName(
item.body,
this.globalConfig.installationName
),
}));
},
},
};
</script>

View file

@ -77,7 +77,14 @@
</div>
<div class="small-4 columns">
<span v-html="$t('INBOX_MGMT.SIDEBAR_TXT')"></span>
<span
v-html="
useInstallationName(
$t('INBOX_MGMT.SIDEBAR_TXT'),
globalConfig.installationName
)
"
/>
</div>
</div>
<settings
@ -107,13 +114,14 @@ import DeleteInbox from './DeleteInbox';
import adminMixin from '../../../../mixins/isAdmin';
import auth from '../../../../api/auth';
import accountMixin from '../../../../mixins/account';
import globalConfigMixin from 'shared/mixins/globalConfigMixin';
export default {
components: {
Settings,
DeleteInbox,
},
mixins: [adminMixin, accountMixin],
mixins: [adminMixin, accountMixin, globalConfigMixin],
data() {
return {
loading: {},
@ -125,6 +133,7 @@ export default {
computed: {
...mapGetters({
inboxesList: 'inboxes/getInboxes',
globalConfig: 'globalConfig/get',
}),
// Delete Modal
deleteConfirmText() {

View file

@ -7,7 +7,14 @@
alt="Facebook-logo"
/>
</a>
<p>{{ $t('INBOX_MGMT.ADD.FB.HELP') }}</p>
<p>
{{
useInstallationName(
$t('INBOX_MGMT.ADD.FB.HELP'),
globalConfig.installationName
)
}}
</p>
</div>
<div v-else>
<loading-state
@ -18,7 +25,12 @@
<div class="medium-12 columns">
<page-header
:header-title="$t('INBOX_MGMT.ADD.DETAILS.TITLE')"
:header-content="$t('INBOX_MGMT.ADD.DETAILS.DESC')"
:header-content="
useInstallationName(
$t('INBOX_MGMT.ADD.DETAILS.DESC'),
globalConfig.installationName
)
"
/>
</div>
<div class="medium-7 columns">
@ -72,13 +84,14 @@ import { mapGetters } from 'vuex';
import ChannelApi from '../../../../../api/channels';
import PageHeader from '../../SettingsSubPageHeader';
import router from '../../../../index';
import globalConfigMixin from 'shared/mixins/globalConfigMixin';
export default {
components: {
LoadingState,
PageHeader,
},
mixins: [globalConfigMixin],
data() {
return {
isCreating: false,
@ -114,6 +127,7 @@ export default {
},
...mapGetters({
currentUser: 'getCurrentUser',
globalConfig: 'globalConfig/get',
}),
accountId() {
return this.currentUser.account_id;

View file

@ -13,7 +13,12 @@
{{ $t('INTEGRATION_SETTINGS.WEBHOOK.TITLE') }}
</h3>
<p class="integration--description">
{{ $t('INTEGRATION_SETTINGS.WEBHOOK.INTEGRATION_TXT') }}
{{
useInstallationName(
$t('INTEGRATION_SETTINGS.WEBHOOK.INTEGRATION_TXT'),
globalConfig.installationName
)
}}
</p>
</div>
<div class="small-2 column button-wrap">
@ -33,20 +38,20 @@
</div>
</div>
</div>
<!-- <div class="small-4 columns help-wrap">
<span v-html="$t('INTEGRATION_SETTINGS.SIDEBAR_TXT')"></span>
</div> -->
</div>
</div>
</template>
<script>
import { mapGetters } from 'vuex';
import { frontendURL } from '../../../../helper/URLHelper';
import globalConfigMixin from 'shared/mixins/globalConfigMixin';
export default {
mixins: [globalConfigMixin],
computed: {
...mapGetters({
currentUser: 'getCurrentUser',
globalConfig: 'globalConfig/get',
}),
accountId() {
return this.currentUser.account_id;

View file

@ -55,7 +55,14 @@
</div>
<div class="small-4 columns">
<span v-html="$t('INTEGRATION_SETTINGS.WEBHOOK.SIDEBAR_TXT')"></span>
<span
v-html="
useInstallationName(
$t('INTEGRATION_SETTINGS.WEBHOOK.SIDEBAR_TXT'),
globalConfig.installationName
)
"
/>
</div>
</div>
@ -79,12 +86,14 @@
import { mapGetters } from 'vuex';
import NewWebhook from './New';
import DeleteWebhook from './Delete';
import globalConfigMixin from 'shared/mixins/globalConfigMixin';
export default {
components: {
NewWebhook,
DeleteWebhook,
},
mixins: [globalConfigMixin],
data() {
return {
loading: {},
@ -97,6 +106,7 @@ export default {
...mapGetters({
records: 'webhooks/getWebhooks',
uiFlags: 'webhooks/getUIFlags',
globalConfig: 'globalConfig/get',
}),
},
mounted() {

View file

@ -2,19 +2,20 @@
<div class="medium-12 column login">
<div class="text-center medium-12 login__hero align-self-top">
<img
src="~dashboard/assets/images/woot-logo.svg"
alt="Woot-logo"
:src="globalConfig.logo"
:alt="globalConfig.installationName"
class="hero__logo"
/>
<h2 class="hero__title">
{{ $t('LOGIN.TITLE') }}
{{
useInstallationName($t('LOGIN.TITLE'), globalConfig.installationName)
}}
</h2>
</div>
<div class="row align-center">
<div class="small-12 medium-4 column">
<form class="login-box column align-self-top" @submit.prevent="login()">
<div class="column log-in-form">
<!-- <h4 class="text-center">{{$t('LOGIN.TITLE')}}</h4> -->
<label :class="{ error: $v.credentials.email.$error }">
{{ $t('LOGIN.EMAIL.LABEL') }}
<input
@ -68,14 +69,15 @@
/* global bus */
import { required, email } from 'vuelidate/lib/validators';
import globalConfigMixin from 'shared/mixins/globalConfigMixin';
import WootSubmitButton from '../../components/buttons/FormSubmitButton';
// import router from '../../routes';
import { mapGetters } from 'vuex';
export default {
components: {
WootSubmitButton,
},
mixins: [globalConfigMixin],
data() {
return {
// We need to initialize the component with any
@ -102,6 +104,11 @@ export default {
},
},
},
computed: {
...mapGetters({
globalConfig: 'globalConfig/get',
}),
},
methods: {
showAlert(message) {
// Reset loading, current selected agent

View file

@ -1,6 +1,7 @@
import Vue from 'vue';
import Vuex from 'vuex';
import accounts from './modules/accounts';
import agents from './modules/agents';
import auth from './modules/auth';
import billing from './modules/billing';
@ -10,15 +11,15 @@ import contactConversations from './modules/contactConversations';
import contacts from './modules/contacts';
import conversationLabels from './modules/conversationLabels';
import conversationMetadata from './modules/conversationMetadata';
import conversationTypingStatus from './modules/conversationTypingStatus';
import conversationPage from './modules/conversationPage';
import conversations from './modules/conversations';
import conversationTypingStatus from './modules/conversationTypingStatus';
import globalConfig from 'shared/store/globalConfig';
import inboxes from './modules/inboxes';
import inboxMembers from './modules/inboxMembers';
import reports from './modules/reports';
import userNotificationSettings from './modules/userNotificationSettings';
import webhooks from './modules/webhooks';
import accounts from './modules/accounts';
Vue.use(Vuex);
export default new Vuex.Store({
@ -36,6 +37,7 @@ export default new Vuex.Store({
conversationPage,
conversations,
conversationTypingStatus,
globalConfig,
inboxes,
inboxMembers,
reports,

View file

@ -0,0 +1,7 @@
export default {
methods: {
useInstallationName(str = '', installationName) {
return str.replace(/Chatwoot/g, installationName);
},
},
};

View file

@ -0,0 +1,33 @@
const {
LOGO_THUMBNAIL: logoThumbnail,
LOGO: logo,
INSTALLATION_NAME: installationName,
WIDGET_BRAND_URL: widgetBrandURL,
TERMS_URL: termsURL,
PRIVACY_URL: privacyURL,
} = window.globalConfig;
const state = {
logoThumbnail,
logo,
installationName,
widgetBrandURL,
termsURL,
privacyURL,
};
export const getters = {
get: $state => $state,
};
export const actions = {};
export const mutations = {};
export default {
namespaced: true,
state,
getters,
actions,
mutations,
};

View file

@ -1,15 +1,34 @@
<template>
<a
class="branding"
href="https://www.chatwoot.com?utm_source=widget_branding"
:href="`${globalConfig.widgetBrandURL}?utm_source=widget_branding`"
rel="noreferrer noopener nofollow"
target="_blank"
>
<img src="~widget/assets/images/logo.svg" alt="ChatwootLogo" />
<span>{{ $t('POWERED_BY') }}</span>
<img
:alt="globalConfig.installationName"
:src="globalConfig.logoThumbnail"
/>
<span>
{{ useInstallationName($t('POWERED_BY'), globalConfig.installationName) }}
</span>
</a>
</template>
<script>
import { mapGetters } from 'vuex';
import globalConfigMixin from 'shared/mixins/globalConfigMixin';
export default {
mixins: [globalConfigMixin],
computed: {
...mapGetters({
globalConfig: 'globalConfig/get',
}),
},
};
</script>
<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped lang="scss">
@import '~widget/assets/scss/variables.scss';

View file

@ -7,6 +7,7 @@ import conversation from 'widget/store/modules/conversation';
import conversationAttributes from 'widget/store/modules/conversationAttributes';
import conversationLabels from 'widget/store/modules/conversationLabels';
import events from 'widget/store/modules/events';
import globalConfig from 'shared/store/globalConfig';
import message from 'widget/store/modules/message';
Vue.use(Vuex);
@ -20,6 +21,7 @@ export default new Vuex.Store({
conversationAttributes,
conversationLabels,
events,
globalConfig,
message,
},
});

View file

@ -5,6 +5,11 @@ class ApplicationMailer < ActionMailer::Base
# helpers
helper :frontend_urls
helper do
def global_config
@global_config ||= GlobalConfig.get('INSTALLATION_NAME', 'BRAND_URL')
end
end
def smtp_config_set_or_development?
ENV.fetch('SMTP_ADDRESS', nil).present? || Rails.env.development?

View file

@ -85,8 +85,8 @@
<tr style="font-family: 'Helvetica Neue',Helvetica,Arial,sans-serif; box-sizing: border-box; font-size: 14px; margin: 0;">
<td class="content-block" style="font-family: 'Helvetica Neue',Helvetica,Arial,sans-serif; box-sizing: border-box; font-size: 14px; vertical-align: top; margin: 0; padding: 0 0 20px;" valign="top">
&mdash; Team Chatwoot <br/>
<a href="https://www.chatwoot.com" style="font-family: 'Helvetica Neue',Helvetica,Arial,sans-serif; box-sizing: border-box; font-size: 12px; vertical-align: top; color: #999; text-align: center; margin: 0; padding: 0 0 20px;" align="center" valign="top">https://www.chatwoot.com</a>
&mdash; Team <%= global_config['INSTALLATION_NAME'] %> <br/>
<a href="<%= global_config['BRAND_URL'] %>" style="font-family: 'Helvetica Neue',Helvetica,Arial,sans-serif; box-sizing: border-box; font-size: 12px; vertical-align: top; color: #999; text-align: center; margin: 0; padding: 0 0 20px;" align="center" valign="top"><%= global_config['BRAND_URL'] %></a>
</td>
</tr>
</table>
@ -96,9 +96,11 @@
<div class="footer" style="font-family: 'Helvetica Neue',Helvetica,Arial,sans-serif; box-sizing: border-box; font-size: 14px; width: 100%; clear: both; color: #999; margin: 0; padding: 20px;">
<table width="100%" style="font-family: 'Helvetica Neue',Helvetica,Arial,sans-serif; box-sizing: border-box; font-size: 14px; margin: 0;">
<tr style="font-family: 'Helvetica Neue',Helvetica,Arial,sans-serif; box-sizing: border-box; font-size: 14px; margin: 0;">
<% if global_config['INSTALLATION_NAME'] == 'Chatwoot' %>
<td class="aligncenter content-block" style="font-family: 'Helvetica Neue',Helvetica,Arial,sans-serif; box-sizing: border-box; font-size: 12px; vertical-align: top; color: #999; text-align: center; margin: 0; padding: 0 0 20px;" align="center" valign="top">
Follow <a href="http://twitter.com/chatwootapp" style="font-family: 'Helvetica Neue',Helvetica,Arial,sans-serif; box-sizing: border-box; font-size: 12px; color: #999; text-decoration: underline; margin: 0;">@chatwootapp</a> on Twitter.
</td>
<% end %>
</tr>
</table>
</div>

View file

@ -22,13 +22,6 @@
<link rel="icon" type="image/png" sizes="16x16" href="/favicon-16x16.png">
<link rel="manifest" href="/manifest.json">
<%= csrf_meta_tags %>
<%= javascript_pack_tag 'application' %>
<%= stylesheet_pack_tag 'application' %>
</head>
<body>
<div id="app"></div>
<noscript id="noscript">This app works best with JavaScript enabled.</noscript>
<%= yield %>
<script>
window.chatwootConfig = {
hostURL: '<%= ENV.fetch('FRONTEND_URL', '') %>',
@ -40,6 +33,14 @@
<% end %>
enabledLanguages: <%= available_locales_with_name.to_json.html_safe %>
}
window.globalConfig = <%= raw GlobalConfig.get('LOGO', 'INSTALLATION_NAME', 'WIDGET_BRAND_URL', 'TERMS_URL', 'PRIVACY_URL').to_json %>
</script>
<%= javascript_pack_tag 'application' %>
<%= stylesheet_pack_tag 'application' %>
</head>
<body>
<div id="app"></div>
<noscript id="noscript">This app works best with JavaScript enabled.</noscript>
<%= yield %>
</body>
</html>

View file

@ -23,6 +23,7 @@
}
window.chatwootPubsubToken = '<%= @contact.pubsub_token %>'
window.authToken = '<%= @token %>'
window.globalConfig = <%= raw GlobalConfig.get('LOGO_THUMBNAIL', 'INSTALLATION_NAME', 'WIDGET_BRAND_URL').to_json %>
</script>
<%= javascript_pack_tag 'widget' %>
<%= stylesheet_pack_tag 'widget' %>

View file

@ -1,2 +1,14 @@
- name: SHOW_WIDGET_HEADER
value: true
- name: LOGO_THUMBNAIL
value: '/brand-assets/logo_thumbnail.svg'
- name: LOGO
value: '/brand-assets/logo.svg'
- name: INSTALLATION_NAME
value: 'Chatwoot'
- name: BRAND_URL
value: 'https://www.chatwoot.com'
- name: WIDGET_BRAND_URL
value: 'https://www.chatwoot.com'
- name: TERMS_URL
value: 'https://www.chatwoot.com/terms-of-service'
- name: PRIVACY_URL
value: 'https://www.chatwoot.com/privacy-policy'

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 12 KiB

View file

@ -0,0 +1,12 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg width="512px" height="512px" viewBox="0 0 512 512" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<!-- Generator: Sketch 59.1 (86144) - https://sketch.com -->
<title>woot-log</title>
<desc>Created with Sketch.</desc>
<g id="Logo" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<g id="woot-log" fill-rule="nonzero">
<circle id="Oval" fill="#47A7F6" cx="256" cy="256" r="256"></circle>
<path d="M362.807947,368.807947 L244.122956,368.807947 C178.699407,368.807947 125.456954,315.561812 125.456954,250.12177 C125.456954,184.703089 178.699407,131.456954 244.124143,131.456954 C309.565494,131.456954 362.807947,184.703089 362.807947,250.12177 L362.807947,368.807947 Z" id="Fill-1" stroke="#FFFFFF" stroke-width="6" fill="#FFFFFF"></path>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 916 B