mirror of
				https://github.com/lingble/chatwoot.git
				synced 2025-11-04 04:57:51 +00:00 
			
		
		
		
	Remove the `user.permissions` field and resolve the permissions directly from the accounts array in the user. This change ensures that the cache or previous values from the last active account don't affect the permissions. In this PR: - Remove user.permissions usage, replace it with getUserPermissions method. - Remove json.permissions from user.json.jbuilder
		
			
				
	
	
		
			269 lines
		
	
	
		
			7.6 KiB
		
	
	
	
		
			Vue
		
	
	
	
	
	
			
		
		
	
	
			269 lines
		
	
	
		
			7.6 KiB
		
	
	
	
		
			Vue
		
	
	
	
	
	
<script>
 | 
						|
import { frontendURL } from '../../../helper/URLHelper';
 | 
						|
import SecondaryNavItem from './SecondaryNavItem.vue';
 | 
						|
import AccountContext from './AccountContext.vue';
 | 
						|
import { mapGetters } from 'vuex';
 | 
						|
import { FEATURE_FLAGS } from '../../../featureFlags';
 | 
						|
import {
 | 
						|
  getUserPermissions,
 | 
						|
  hasPermissions,
 | 
						|
} from '../../../helper/permissionsHelper';
 | 
						|
import { routesWithPermissions } from '../../../routes';
 | 
						|
 | 
						|
export default {
 | 
						|
  components: {
 | 
						|
    AccountContext,
 | 
						|
    SecondaryNavItem,
 | 
						|
  },
 | 
						|
  props: {
 | 
						|
    accountId: {
 | 
						|
      type: Number,
 | 
						|
      default: 0,
 | 
						|
    },
 | 
						|
    labels: {
 | 
						|
      type: Array,
 | 
						|
      default: () => [],
 | 
						|
    },
 | 
						|
    inboxes: {
 | 
						|
      type: Array,
 | 
						|
      default: () => [],
 | 
						|
    },
 | 
						|
    teams: {
 | 
						|
      type: Array,
 | 
						|
      default: () => [],
 | 
						|
    },
 | 
						|
    customViews: {
 | 
						|
      type: Array,
 | 
						|
      default: () => [],
 | 
						|
    },
 | 
						|
    menuConfig: {
 | 
						|
      type: Object,
 | 
						|
      default: () => {},
 | 
						|
    },
 | 
						|
    currentUser: {
 | 
						|
      type: Object,
 | 
						|
      default: () => {},
 | 
						|
    },
 | 
						|
    isOnChatwootCloud: {
 | 
						|
      type: Boolean,
 | 
						|
      default: false,
 | 
						|
    },
 | 
						|
  },
 | 
						|
  computed: {
 | 
						|
    ...mapGetters({
 | 
						|
      isFeatureEnabledonAccount: 'accounts/isFeatureEnabledonAccount',
 | 
						|
    }),
 | 
						|
    hasSecondaryMenu() {
 | 
						|
      return this.menuConfig.menuItems && this.menuConfig.menuItems.length;
 | 
						|
    },
 | 
						|
    contactCustomViews() {
 | 
						|
      return this.customViews.filter(view => view.filter_type === 'contact');
 | 
						|
    },
 | 
						|
    accessibleMenuItems() {
 | 
						|
      const menuItemsFilteredByPermissions = this.menuConfig.menuItems.filter(
 | 
						|
        menuItem => {
 | 
						|
          const userPermissions = getUserPermissions(
 | 
						|
            this.currentUser,
 | 
						|
            this.accountId
 | 
						|
          );
 | 
						|
          return hasPermissions(
 | 
						|
            routesWithPermissions[menuItem.toStateName],
 | 
						|
            userPermissions
 | 
						|
          );
 | 
						|
        }
 | 
						|
      );
 | 
						|
      return menuItemsFilteredByPermissions.filter(item => {
 | 
						|
        if (item.showOnlyOnCloud) {
 | 
						|
          return this.isOnChatwootCloud;
 | 
						|
        }
 | 
						|
        return true;
 | 
						|
      });
 | 
						|
    },
 | 
						|
    inboxSection() {
 | 
						|
      return {
 | 
						|
        icon: 'folder',
 | 
						|
        label: 'INBOXES',
 | 
						|
        hasSubMenu: true,
 | 
						|
        newLink: this.showNewLink(FEATURE_FLAGS.INBOX_MANAGEMENT),
 | 
						|
        newLinkTag: 'NEW_INBOX',
 | 
						|
        key: 'inbox',
 | 
						|
        toState: frontendURL(`accounts/${this.accountId}/settings/inboxes/new`),
 | 
						|
        toStateName: 'settings_inbox_new',
 | 
						|
        newLinkRouteName: 'settings_inbox_new',
 | 
						|
        children: this.inboxes
 | 
						|
          .map(inbox => ({
 | 
						|
            id: inbox.id,
 | 
						|
            label: inbox.name,
 | 
						|
            truncateLabel: true,
 | 
						|
            toState: frontendURL(
 | 
						|
              `accounts/${this.accountId}/inbox/${inbox.id}`
 | 
						|
            ),
 | 
						|
            type: inbox.channel_type,
 | 
						|
            phoneNumber: inbox.phone_number,
 | 
						|
            reauthorizationRequired: inbox.reauthorization_required,
 | 
						|
          }))
 | 
						|
          .sort((a, b) =>
 | 
						|
            a.label.toLowerCase() > b.label.toLowerCase() ? 1 : -1
 | 
						|
          ),
 | 
						|
      };
 | 
						|
    },
 | 
						|
    labelSection() {
 | 
						|
      return {
 | 
						|
        icon: 'number-symbol',
 | 
						|
        label: 'LABELS',
 | 
						|
        hasSubMenu: true,
 | 
						|
        newLink: this.showNewLink(FEATURE_FLAGS.TEAM_MANAGEMENT),
 | 
						|
        newLinkTag: 'NEW_LABEL',
 | 
						|
        key: 'label',
 | 
						|
        toState: frontendURL(`accounts/${this.accountId}/settings/labels`),
 | 
						|
        toStateName: 'labels_list',
 | 
						|
        showModalForNewItem: true,
 | 
						|
        modalName: 'AddLabel',
 | 
						|
        dataTestid: 'sidebar-new-label-button',
 | 
						|
        children: this.labels.map(label => ({
 | 
						|
          id: label.id,
 | 
						|
          label: label.title,
 | 
						|
          color: label.color,
 | 
						|
          truncateLabel: true,
 | 
						|
          toState: frontendURL(
 | 
						|
            `accounts/${this.accountId}/label/${label.title}`
 | 
						|
          ),
 | 
						|
        })),
 | 
						|
      };
 | 
						|
    },
 | 
						|
    contactLabelSection() {
 | 
						|
      return {
 | 
						|
        icon: 'number-symbol',
 | 
						|
        label: 'TAGGED_WITH',
 | 
						|
        hasSubMenu: true,
 | 
						|
        key: 'label',
 | 
						|
        newLink: this.showNewLink(FEATURE_FLAGS.TEAM_MANAGEMENT),
 | 
						|
        newLinkTag: 'NEW_LABEL',
 | 
						|
        toState: frontendURL(`accounts/${this.accountId}/settings/labels`),
 | 
						|
        toStateName: 'labels_list',
 | 
						|
        showModalForNewItem: true,
 | 
						|
        modalName: 'AddLabel',
 | 
						|
        children: this.labels.map(label => ({
 | 
						|
          id: label.id,
 | 
						|
          label: label.title,
 | 
						|
          color: label.color,
 | 
						|
          truncateLabel: true,
 | 
						|
          toState: frontendURL(
 | 
						|
            `accounts/${this.accountId}/labels/${label.title}/contacts`
 | 
						|
          ),
 | 
						|
        })),
 | 
						|
      };
 | 
						|
    },
 | 
						|
    teamSection() {
 | 
						|
      return {
 | 
						|
        icon: 'people-team',
 | 
						|
        label: 'TEAMS',
 | 
						|
        hasSubMenu: true,
 | 
						|
        newLink: this.showNewLink(FEATURE_FLAGS.TEAM_MANAGEMENT),
 | 
						|
        newLinkTag: 'NEW_TEAM',
 | 
						|
        key: 'team',
 | 
						|
        toState: frontendURL(`accounts/${this.accountId}/settings/teams/new`),
 | 
						|
        toStateName: 'settings_teams_new',
 | 
						|
        newLinkRouteName: 'settings_teams_new',
 | 
						|
        children: this.teams.map(team => ({
 | 
						|
          id: team.id,
 | 
						|
          label: team.name,
 | 
						|
          truncateLabel: true,
 | 
						|
          toState: frontendURL(`accounts/${this.accountId}/team/${team.id}`),
 | 
						|
        })),
 | 
						|
      };
 | 
						|
    },
 | 
						|
    foldersSection() {
 | 
						|
      return {
 | 
						|
        icon: 'folder',
 | 
						|
        label: 'CUSTOM_VIEWS_FOLDER',
 | 
						|
        hasSubMenu: true,
 | 
						|
        key: 'custom_view',
 | 
						|
        children: this.customViews
 | 
						|
          .filter(view => view.filter_type === 'conversation')
 | 
						|
          .map(view => ({
 | 
						|
            id: view.id,
 | 
						|
            label: view.name,
 | 
						|
            truncateLabel: true,
 | 
						|
            toState: frontendURL(
 | 
						|
              `accounts/${this.accountId}/custom_view/${view.id}`
 | 
						|
            ),
 | 
						|
          })),
 | 
						|
      };
 | 
						|
    },
 | 
						|
    contactSegmentsSection() {
 | 
						|
      return {
 | 
						|
        icon: 'folder',
 | 
						|
        label: 'CUSTOM_VIEWS_SEGMENTS',
 | 
						|
        hasSubMenu: true,
 | 
						|
        key: 'custom_view',
 | 
						|
        children: this.customViews
 | 
						|
          .filter(view => view.filter_type === 'contact')
 | 
						|
          .map(view => ({
 | 
						|
            id: view.id,
 | 
						|
            label: view.name,
 | 
						|
            truncateLabel: true,
 | 
						|
            toState: frontendURL(
 | 
						|
              `accounts/${this.accountId}/contacts/custom_view/${view.id}`
 | 
						|
            ),
 | 
						|
          })),
 | 
						|
      };
 | 
						|
    },
 | 
						|
    additionalSecondaryMenuItems() {
 | 
						|
      let conversationMenuItems = [this.inboxSection, this.labelSection];
 | 
						|
      let contactMenuItems = [this.contactLabelSection];
 | 
						|
      if (this.teams.length) {
 | 
						|
        conversationMenuItems = [this.teamSection, ...conversationMenuItems];
 | 
						|
      }
 | 
						|
      if (this.customViews.length) {
 | 
						|
        conversationMenuItems = [this.foldersSection, ...conversationMenuItems];
 | 
						|
      }
 | 
						|
      if (this.contactCustomViews.length) {
 | 
						|
        contactMenuItems = [this.contactSegmentsSection, ...contactMenuItems];
 | 
						|
      }
 | 
						|
      return {
 | 
						|
        conversations: conversationMenuItems,
 | 
						|
        contacts: contactMenuItems,
 | 
						|
      };
 | 
						|
    },
 | 
						|
  },
 | 
						|
  methods: {
 | 
						|
    showAddLabelPopup() {
 | 
						|
      this.$emit('addLabel');
 | 
						|
    },
 | 
						|
    toggleAccountModal() {
 | 
						|
      this.$emit('toggleAccounts');
 | 
						|
    },
 | 
						|
    showNewLink(featureFlag) {
 | 
						|
      return this.isFeatureEnabledonAccount(this.accountId, featureFlag);
 | 
						|
    },
 | 
						|
  },
 | 
						|
};
 | 
						|
</script>
 | 
						|
 | 
						|
<template>
 | 
						|
  <div
 | 
						|
    v-if="hasSecondaryMenu"
 | 
						|
    class="flex flex-col w-48 h-full px-2 pb-8 overflow-auto text-sm bg-white border-r dark:bg-slate-900 dark:border-slate-800/50 rtl:border-r-0 rtl:border-l border-slate-50"
 | 
						|
  >
 | 
						|
    <AccountContext @toggleAccounts="toggleAccountModal" />
 | 
						|
    <transition-group
 | 
						|
      name="menu-list"
 | 
						|
      tag="ul"
 | 
						|
      class="pt-2 mb-0 ml-0 list-none"
 | 
						|
    >
 | 
						|
      <SecondaryNavItem
 | 
						|
        v-for="menuItem in accessibleMenuItems"
 | 
						|
        :key="menuItem.toState"
 | 
						|
        :menu-item="menuItem"
 | 
						|
      />
 | 
						|
      <SecondaryNavItem
 | 
						|
        v-for="menuItem in additionalSecondaryMenuItems[menuConfig.parentNav]"
 | 
						|
        :key="menuItem.key"
 | 
						|
        :menu-item="menuItem"
 | 
						|
        @addLabel="showAddLabelPopup"
 | 
						|
      />
 | 
						|
    </transition-group>
 | 
						|
  </div>
 | 
						|
</template>
 |