mirror of
				https://github.com/lingble/chatwoot.git
				synced 2025-11-04 13:07:55 +00:00 
			
		
		
		
	feat: Display Account context in the UI (#4069)
This commit is contained in:
		@@ -27,7 +27,9 @@ class DashboardController < ActionController::Base
 | 
				
			|||||||
      'ANALYTICS_TOKEN',
 | 
					      'ANALYTICS_TOKEN',
 | 
				
			||||||
      'ANALYTICS_HOST',
 | 
					      'ANALYTICS_HOST',
 | 
				
			||||||
      'DIRECT_UPLOADS_ENABLED',
 | 
					      'DIRECT_UPLOADS_ENABLED',
 | 
				
			||||||
      'HCAPTCHA_SITE_KEY'
 | 
					      'HCAPTCHA_SITE_KEY',
 | 
				
			||||||
 | 
					      'LOGOUT_REDIRECT_LINK',
 | 
				
			||||||
 | 
					      'DISABLE_USER_PROFILE_UPDATE'
 | 
				
			||||||
    ).merge(app_config)
 | 
					    ).merge(app_config)
 | 
				
			||||||
  end
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -54,3 +54,9 @@
 | 
				
			|||||||
.text-y-800 {
 | 
					.text-y-800 {
 | 
				
			||||||
  color: var(--y-800);
 | 
					  color: var(--y-800);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.text-ellipsis {
 | 
				
			||||||
 | 
					  overflow: hidden;
 | 
				
			||||||
 | 
					  text-overflow: ellipsis;
 | 
				
			||||||
 | 
					  white-space: nowrap;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -0,0 +1,36 @@
 | 
				
			|||||||
 | 
					<template>
 | 
				
			||||||
 | 
					  <div v-if="showShowCurrentAccountContext" class="account-context--group">
 | 
				
			||||||
 | 
					    {{ $t('SIDEBAR.CURRENTLY_VIEWING_ACCOUNT') }}
 | 
				
			||||||
 | 
					    <p class="account-context--name text-ellipsis">
 | 
				
			||||||
 | 
					      {{ account.name }}
 | 
				
			||||||
 | 
					    </p>
 | 
				
			||||||
 | 
					  </div>
 | 
				
			||||||
 | 
					</template>
 | 
				
			||||||
 | 
					<script>
 | 
				
			||||||
 | 
					import { mapGetters } from 'vuex';
 | 
				
			||||||
 | 
					export default {
 | 
				
			||||||
 | 
					  computed: {
 | 
				
			||||||
 | 
					    ...mapGetters({
 | 
				
			||||||
 | 
					      account: 'getCurrentAccount',
 | 
				
			||||||
 | 
					      userAccounts: 'getUserAccounts',
 | 
				
			||||||
 | 
					    }),
 | 
				
			||||||
 | 
					    showShowCurrentAccountContext() {
 | 
				
			||||||
 | 
					      return this.userAccounts.length > 1 && this.account.name;
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					</script>
 | 
				
			||||||
 | 
					<style scoped lang="scss">
 | 
				
			||||||
 | 
					.account-context--group {
 | 
				
			||||||
 | 
					  border-radius: var(--border-radius-normal);
 | 
				
			||||||
 | 
					  border: 1px solid var(--color-border);
 | 
				
			||||||
 | 
					  font-size: var(--font-size-mini);
 | 
				
			||||||
 | 
					  padding: var(--space-small);
 | 
				
			||||||
 | 
					  margin-bottom: var(--space-small);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  .account-context--name {
 | 
				
			||||||
 | 
					    font-weight: var(--font-weight-medium);
 | 
				
			||||||
 | 
					    margin-bottom: 0;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					</style>
 | 
				
			||||||
@@ -1,5 +1,6 @@
 | 
				
			|||||||
<template>
 | 
					<template>
 | 
				
			||||||
  <div v-if="hasSecondaryMenu" class="main-nav secondary-menu">
 | 
					  <div v-if="hasSecondaryMenu" class="main-nav secondary-menu">
 | 
				
			||||||
 | 
					    <account-context />
 | 
				
			||||||
    <transition-group name="menu-list" tag="ul" class="menu vertical">
 | 
					    <transition-group name="menu-list" tag="ul" class="menu vertical">
 | 
				
			||||||
      <secondary-nav-item
 | 
					      <secondary-nav-item
 | 
				
			||||||
        v-for="menuItem in accessibleMenuItems"
 | 
					        v-for="menuItem in accessibleMenuItems"
 | 
				
			||||||
@@ -18,9 +19,11 @@
 | 
				
			|||||||
<script>
 | 
					<script>
 | 
				
			||||||
import { frontendURL } from '../../../helper/URLHelper';
 | 
					import { frontendURL } from '../../../helper/URLHelper';
 | 
				
			||||||
import SecondaryNavItem from './SecondaryNavItem.vue';
 | 
					import SecondaryNavItem from './SecondaryNavItem.vue';
 | 
				
			||||||
 | 
					import AccountContext from './AccountContext.vue';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export default {
 | 
					export default {
 | 
				
			||||||
  components: {
 | 
					  components: {
 | 
				
			||||||
 | 
					    AccountContext,
 | 
				
			||||||
    SecondaryNavItem,
 | 
					    SecondaryNavItem,
 | 
				
			||||||
  },
 | 
					  },
 | 
				
			||||||
  props: {
 | 
					  props: {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -65,7 +65,7 @@
 | 
				
			|||||||
        </div>
 | 
					        </div>
 | 
				
			||||||
        <div class="features-item">
 | 
					        <div class="features-item">
 | 
				
			||||||
          <h2 class="block-title">
 | 
					          <h2 class="block-title">
 | 
				
			||||||
            <span class="emoji">🏷</span>{{ $t('ONBOARDING.LABELS.TITLE') }}
 | 
					            <span class="emoji">🔖</span>{{ $t('ONBOARDING.LABELS.TITLE') }}
 | 
				
			||||||
          </h2>
 | 
					          </h2>
 | 
				
			||||||
          <p class="intro-body">
 | 
					          <p class="intro-body">
 | 
				
			||||||
            {{ $t('ONBOARDING.LABELS.DESCRIPTION') }}
 | 
					            {{ $t('ONBOARDING.LABELS.DESCRIPTION') }}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -142,6 +142,7 @@
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
  },
 | 
					  },
 | 
				
			||||||
  "SIDEBAR": {
 | 
					  "SIDEBAR": {
 | 
				
			||||||
 | 
					    "CURRENTLY_VIEWING_ACCOUNT": "Currently viewing:",
 | 
				
			||||||
    "CONVERSATIONS": "Conversations",
 | 
					    "CONVERSATIONS": "Conversations",
 | 
				
			||||||
    "ALL_CONVERSATIONS": "All Conversations",
 | 
					    "ALL_CONVERSATIONS": "All Conversations",
 | 
				
			||||||
    "MENTIONED_CONVERSATIONS": "Mentions",
 | 
					    "MENTIONED_CONVERSATIONS": "Mentions",
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -48,7 +48,10 @@
 | 
				
			|||||||
              @input="$v.displayName.$touch"
 | 
					              @input="$v.displayName.$touch"
 | 
				
			||||||
            />
 | 
					            />
 | 
				
			||||||
          </label>
 | 
					          </label>
 | 
				
			||||||
          <label :class="{ error: $v.email.$error }">
 | 
					          <label
 | 
				
			||||||
 | 
					            v-if="!globalConfig.disableUserProfileUpdate"
 | 
				
			||||||
 | 
					            :class="{ error: $v.email.$error }"
 | 
				
			||||||
 | 
					          >
 | 
				
			||||||
            {{ $t('PROFILE_SETTINGS.FORM.EMAIL.LABEL') }}
 | 
					            {{ $t('PROFILE_SETTINGS.FORM.EMAIL.LABEL') }}
 | 
				
			||||||
            <input
 | 
					            <input
 | 
				
			||||||
              v-model.trim="email"
 | 
					              v-model.trim="email"
 | 
				
			||||||
@@ -67,7 +70,7 @@
 | 
				
			|||||||
      </div>
 | 
					      </div>
 | 
				
			||||||
    </form>
 | 
					    </form>
 | 
				
			||||||
    <message-signature />
 | 
					    <message-signature />
 | 
				
			||||||
    <change-password />
 | 
					    <change-password v-if="!globalConfig.disableUserProfileUpdate" />
 | 
				
			||||||
    <notification-settings />
 | 
					    <notification-settings />
 | 
				
			||||||
    <div class="profile--settings--row row">
 | 
					    <div class="profile--settings--row row">
 | 
				
			||||||
      <div class="columns small-3">
 | 
					      <div class="columns small-3">
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -50,7 +50,7 @@
 | 
				
			|||||||
          </div>
 | 
					          </div>
 | 
				
			||||||
        </form>
 | 
					        </form>
 | 
				
			||||||
        <div class="column text-center sigin__footer">
 | 
					        <div class="column text-center sigin__footer">
 | 
				
			||||||
          <p>
 | 
					          <p v-if="!globalConfig.disableUserProfileUpdate">
 | 
				
			||||||
            <router-link to="auth/reset/password">
 | 
					            <router-link to="auth/reset/password">
 | 
				
			||||||
              {{ $t('LOGIN.FORGOT_PASSWORD') }}
 | 
					              {{ $t('LOGIN.FORGOT_PASSWORD') }}
 | 
				
			||||||
            </router-link>
 | 
					            </router-link>
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -71,6 +71,19 @@ export const getters = {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    return messageSignature || '';
 | 
					    return messageSignature || '';
 | 
				
			||||||
  },
 | 
					  },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  getCurrentAccount(_state) {
 | 
				
			||||||
 | 
					    const { accounts = [] } = _state.currentUser;
 | 
				
			||||||
 | 
					    const [currentAccount = {}] = accounts.filter(
 | 
				
			||||||
 | 
					      account => account.id === _state.currentAccountId
 | 
				
			||||||
 | 
					    );
 | 
				
			||||||
 | 
					    return currentAccount || {};
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  getUserAccounts(_state) {
 | 
				
			||||||
 | 
					    const { accounts = [] } = _state.currentUser;
 | 
				
			||||||
 | 
					    return accounts;
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// actions
 | 
					// actions
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -53,4 +53,60 @@ describe('#getters', () => {
 | 
				
			|||||||
      ).toEqual('');
 | 
					      ).toEqual('');
 | 
				
			||||||
    });
 | 
					    });
 | 
				
			||||||
  });
 | 
					  });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  describe('#getCurrentAccount', () => {
 | 
				
			||||||
 | 
					    it('returns correct values', () => {
 | 
				
			||||||
 | 
					      expect(
 | 
				
			||||||
 | 
					        getters.getCurrentAccount({
 | 
				
			||||||
 | 
					          currentUser: {},
 | 
				
			||||||
 | 
					          currentAccountId: 1,
 | 
				
			||||||
 | 
					        })
 | 
				
			||||||
 | 
					      ).toEqual({});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      expect(
 | 
				
			||||||
 | 
					        getters.getCurrentAccount({
 | 
				
			||||||
 | 
					          currentUser: {
 | 
				
			||||||
 | 
					            accounts: [
 | 
				
			||||||
 | 
					              {
 | 
				
			||||||
 | 
					                name: 'Chatwoot',
 | 
				
			||||||
 | 
					                id: 1,
 | 
				
			||||||
 | 
					              },
 | 
				
			||||||
 | 
					            ],
 | 
				
			||||||
 | 
					          },
 | 
				
			||||||
 | 
					          currentAccountId: 1,
 | 
				
			||||||
 | 
					        })
 | 
				
			||||||
 | 
					      ).toEqual({
 | 
				
			||||||
 | 
					        name: 'Chatwoot',
 | 
				
			||||||
 | 
					        id: 1,
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					  });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  describe('#getUserAccounts', () => {
 | 
				
			||||||
 | 
					    it('returns correct values', () => {
 | 
				
			||||||
 | 
					      expect(
 | 
				
			||||||
 | 
					        getters.getUserAccounts({
 | 
				
			||||||
 | 
					          currentUser: {},
 | 
				
			||||||
 | 
					        })
 | 
				
			||||||
 | 
					      ).toEqual([]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      expect(
 | 
				
			||||||
 | 
					        getters.getUserAccounts({
 | 
				
			||||||
 | 
					          currentUser: {
 | 
				
			||||||
 | 
					            accounts: [
 | 
				
			||||||
 | 
					              {
 | 
				
			||||||
 | 
					                name: 'Chatwoot',
 | 
				
			||||||
 | 
					                id: 1,
 | 
				
			||||||
 | 
					              },
 | 
				
			||||||
 | 
					            ],
 | 
				
			||||||
 | 
					          },
 | 
				
			||||||
 | 
					        })
 | 
				
			||||||
 | 
					      ).toEqual([
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					          name: 'Chatwoot',
 | 
				
			||||||
 | 
					          id: 1,
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					      ]);
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					  });
 | 
				
			||||||
});
 | 
					});
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -44,5 +44,9 @@ export const clearCookiesOnLogout = () => {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
  Cookies.remove('auth_data');
 | 
					  Cookies.remove('auth_data');
 | 
				
			||||||
  Cookies.remove('user');
 | 
					  Cookies.remove('user');
 | 
				
			||||||
  window.location = frontendURL('login');
 | 
					
 | 
				
			||||||
 | 
					  const globalConfig = window.globalConfig || {};
 | 
				
			||||||
 | 
					  const logoutRedirectLink =
 | 
				
			||||||
 | 
					    globalConfig.LOGOUT_REDIRECT_LINK || frontendURL('login');
 | 
				
			||||||
 | 
					  window.location = logoutRedirectLink;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -14,6 +14,7 @@ const {
 | 
				
			|||||||
  PRIVACY_URL: privacyURL,
 | 
					  PRIVACY_URL: privacyURL,
 | 
				
			||||||
  TERMS_URL: termsURL,
 | 
					  TERMS_URL: termsURL,
 | 
				
			||||||
  WIDGET_BRAND_URL: widgetBrandURL,
 | 
					  WIDGET_BRAND_URL: widgetBrandURL,
 | 
				
			||||||
 | 
					  DISABLE_USER_PROFILE_UPDATE: disableUserProfileUpdate,
 | 
				
			||||||
} = window.globalConfig || {};
 | 
					} = window.globalConfig || {};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const state = {
 | 
					const state = {
 | 
				
			||||||
@@ -24,6 +25,7 @@ const state = {
 | 
				
			|||||||
  chatwootInboxToken,
 | 
					  chatwootInboxToken,
 | 
				
			||||||
  createNewAccountFromDashboard,
 | 
					  createNewAccountFromDashboard,
 | 
				
			||||||
  directUploadsEnabled: directUploadsEnabled === 'true',
 | 
					  directUploadsEnabled: directUploadsEnabled === 'true',
 | 
				
			||||||
 | 
					  disableUserProfileUpdate: disableUserProfileUpdate === 'true',
 | 
				
			||||||
  displayManifest,
 | 
					  displayManifest,
 | 
				
			||||||
  hCaptchaSiteKey,
 | 
					  hCaptchaSiteKey,
 | 
				
			||||||
  installationName,
 | 
					  installationName,
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -53,3 +53,9 @@
 | 
				
			|||||||
- name: HCAPTCHA_SERVER_KEY
 | 
					- name: HCAPTCHA_SERVER_KEY
 | 
				
			||||||
  value:
 | 
					  value:
 | 
				
			||||||
  locked: false
 | 
					  locked: false
 | 
				
			||||||
 | 
					- name: LOGOUT_REDIRECT_LINK
 | 
				
			||||||
 | 
					  value: /app/login
 | 
				
			||||||
 | 
					  locked: false
 | 
				
			||||||
 | 
					- name: DISABLE_USER_PROFILE_UPDATE
 | 
				
			||||||
 | 
					  value: false
 | 
				
			||||||
 | 
					  locked: false
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user