mirror of
				https://github.com/lingble/chatwoot.git
				synced 2025-10-31 02:57:57 +00:00 
			
		
		
		
	 280bc58963
			
		
	
	280bc58963
	
	
	
		
			
			# Pull Request Template ### Changes includes * Update send message and add note button <img width="151" alt="image" src="https://github.com/user-attachments/assets/646d1d22-07be-4f2f-9090-6642556aa761" /> <img width="151" alt="image" src="https://github.com/user-attachments/assets/b5651420-c48b-4932-aff9-911788b9eabc" /> <img width="165" alt="image" src="https://github.com/user-attachments/assets/f1ace171-2115-4eba-9055-e568d1b73c5e" /> <img width="165" alt="image" src="https://github.com/user-attachments/assets/0c818461-ccdb-46ab-b7d3-3917e4ee4e74" /> <img width="165" alt="image" src="https://github.com/user-attachments/assets/eef1545b-1bed-47a1-8b83-ed5d5da3f24f" /> <img width="165" alt="image" src="https://github.com/user-attachments/assets/429de6e6-1263-4216-9222-4eaece95da81" /> <img width="165" alt="image" src="https://github.com/user-attachments/assets/59a69867-4da1-4695-b88c-329142a693a8" /> <img width="165" alt="image" src="https://github.com/user-attachments/assets/7114745c-836f-4c5a-b5d6-e200e1343a73" /> * Remove Unused component `AnnouncementPopup.vue` * Updated button for custom attributes in conversation sidebar. <img width="225" alt="image" src="https://github.com/user-attachments/assets/a71f6c31-aca9-4e1b-bf63-6b9d5ed183c8" /> <img width="310" alt="image" src="https://github.com/user-attachments/assets/8d847e1b-4a13-4108-a487-ce3d36257afa" /> * Update button in custom snooze modal buttons <img width="207" alt="image" src="https://github.com/user-attachments/assets/78315ce6-9734-467b-a4d3-e753d3eca384" /> * Update modal component close button <img width="80" alt="image" src="https://github.com/user-attachments/assets/643e9ef0-b781-47ce-a66b-a9ee4760c952" /> * Update AI assistant modal and AICTA modal <img width="319" alt="image" src="https://github.com/user-attachments/assets/8d0986ec-ec7a-4abb-9327-f73df8b4d942" /> <img width="565" alt="image" src="https://github.com/user-attachments/assets/1e02ddd1-7f51-4d8a-bb57-558b9a50c938" /> * Update remove attachment button <img width="301" alt="image" src="https://github.com/user-attachments/assets/90c93eee-0b4d-4839-9db5-edc4b023df4b" /> * Update the conversation header buttons <img width="256" alt="image" src="https://github.com/user-attachments/assets/abac5d7e-dd83-40ae-b548-76bbafaa2231" /> * Update the retry button in old message bubbles. --------- Co-authored-by: Pranav <pranav@chatwoot.com>
		
			
				
	
	
		
			289 lines
		
	
	
		
			6.9 KiB
		
	
	
	
		
			Vue
		
	
	
	
	
	
			
		
		
	
	
			289 lines
		
	
	
		
			6.9 KiB
		
	
	
	
		
			Vue
		
	
	
	
	
	
| <script>
 | |
| import AutomationActionTeamMessageInput from './AutomationActionTeamMessageInput.vue';
 | |
| import AutomationActionFileInput from './AutomationFileInput.vue';
 | |
| import WootMessageEditor from 'dashboard/components/widgets/WootWriter/Editor.vue';
 | |
| import NextButton from 'dashboard/components-next/button/Button.vue';
 | |
| 
 | |
| export default {
 | |
|   components: {
 | |
|     AutomationActionTeamMessageInput,
 | |
|     AutomationActionFileInput,
 | |
|     WootMessageEditor,
 | |
|     NextButton,
 | |
|   },
 | |
|   props: {
 | |
|     modelValue: {
 | |
|       type: Object,
 | |
|       default: () => null,
 | |
|     },
 | |
|     actionTypes: {
 | |
|       type: Array,
 | |
|       default: () => [],
 | |
|     },
 | |
|     dropdownValues: {
 | |
|       type: Array,
 | |
|       default: () => [],
 | |
|     },
 | |
|     errorMessage: {
 | |
|       type: String,
 | |
|       default: '',
 | |
|     },
 | |
|     showActionInput: {
 | |
|       type: Boolean,
 | |
|       default: true,
 | |
|     },
 | |
|     initialFileName: {
 | |
|       type: String,
 | |
|       default: '',
 | |
|     },
 | |
|     isMacro: {
 | |
|       type: Boolean,
 | |
|       default: false,
 | |
|     },
 | |
|   },
 | |
|   emits: ['update:modelValue', 'input', 'removeAction', 'resetAction'],
 | |
|   computed: {
 | |
|     action_name: {
 | |
|       get() {
 | |
|         if (!this.modelValue) return null;
 | |
|         return this.modelValue.action_name;
 | |
|       },
 | |
|       set(value) {
 | |
|         const payload = this.modelValue || {};
 | |
|         this.$emit('update:modelValue', { ...payload, action_name: value });
 | |
|         this.$emit('input', { ...payload, action_name: value });
 | |
|       },
 | |
|     },
 | |
|     action_params: {
 | |
|       get() {
 | |
|         if (!this.modelValue) return null;
 | |
|         return this.modelValue.action_params;
 | |
|       },
 | |
|       set(value) {
 | |
|         const payload = this.modelValue || {};
 | |
|         this.$emit('update:modelValue', { ...payload, action_params: value });
 | |
|         this.$emit('input', { ...payload, action_params: value });
 | |
|       },
 | |
|     },
 | |
|     inputType() {
 | |
|       return this.actionTypes.find(action => action.key === this.action_name)
 | |
|         .inputType;
 | |
|     },
 | |
|     actionInputStyles() {
 | |
|       return {
 | |
|         'has-error': this.errorMessage,
 | |
|         'is-a-macro': this.isMacro,
 | |
|       };
 | |
|     },
 | |
|     castMessageVmodel: {
 | |
|       get() {
 | |
|         if (Array.isArray(this.action_params)) {
 | |
|           return this.action_params[0];
 | |
|         }
 | |
|         return this.action_params;
 | |
|       },
 | |
|       set(value) {
 | |
|         this.action_params = value;
 | |
|       },
 | |
|     },
 | |
|   },
 | |
|   methods: {
 | |
|     removeAction() {
 | |
|       this.$emit('removeAction');
 | |
|     },
 | |
|     resetAction() {
 | |
|       this.$emit('resetAction');
 | |
|     },
 | |
|   },
 | |
| };
 | |
| </script>
 | |
| 
 | |
| <template>
 | |
|   <div class="filter" :class="actionInputStyles">
 | |
|     <div class="filter-inputs">
 | |
|       <select
 | |
|         v-model="action_name"
 | |
|         class="action__question"
 | |
|         :class="{ 'full-width': !showActionInput }"
 | |
|         @change="resetAction()"
 | |
|       >
 | |
|         <option
 | |
|           v-for="attribute in actionTypes"
 | |
|           :key="attribute.key"
 | |
|           :value="attribute.key"
 | |
|         >
 | |
|           {{ attribute.label }}
 | |
|         </option>
 | |
|       </select>
 | |
|       <div v-if="showActionInput" class="filter__answer--wrap">
 | |
|         <div v-if="inputType" class="w-full">
 | |
|           <div
 | |
|             v-if="inputType === 'search_select'"
 | |
|             class="multiselect-wrap--small"
 | |
|           >
 | |
|             <multiselect
 | |
|               v-model="action_params"
 | |
|               track-by="id"
 | |
|               label="name"
 | |
|               :placeholder="$t('FORMS.MULTISELECT.SELECT')"
 | |
|               selected-label
 | |
|               :select-label="$t('FORMS.MULTISELECT.ENTER_TO_SELECT')"
 | |
|               deselect-label=""
 | |
|               :max-height="160"
 | |
|               :options="dropdownValues"
 | |
|               :allow-empty="false"
 | |
|               :option-height="104"
 | |
|             />
 | |
|           </div>
 | |
|           <div
 | |
|             v-else-if="inputType === 'multi_select'"
 | |
|             class="multiselect-wrap--small"
 | |
|           >
 | |
|             <multiselect
 | |
|               v-model="action_params"
 | |
|               track-by="id"
 | |
|               label="name"
 | |
|               :placeholder="$t('FORMS.MULTISELECT.SELECT')"
 | |
|               multiple
 | |
|               selected-label
 | |
|               :select-label="$t('FORMS.MULTISELECT.ENTER_TO_SELECT')"
 | |
|               deselect-label=""
 | |
|               :max-height="160"
 | |
|               :options="dropdownValues"
 | |
|               :allow-empty="false"
 | |
|               :option-height="104"
 | |
|             />
 | |
|           </div>
 | |
|           <input
 | |
|             v-else-if="inputType === 'email'"
 | |
|             v-model="action_params"
 | |
|             type="email"
 | |
|             class="answer--text-input"
 | |
|             :placeholder="$t('AUTOMATION.ACTION.EMAIL_INPUT_PLACEHOLDER')"
 | |
|           />
 | |
|           <input
 | |
|             v-else-if="inputType === 'url'"
 | |
|             v-model="action_params"
 | |
|             type="url"
 | |
|             class="answer--text-input"
 | |
|             :placeholder="$t('AUTOMATION.ACTION.URL_INPUT_PLACEHOLDER')"
 | |
|           />
 | |
|           <AutomationActionFileInput
 | |
|             v-if="inputType === 'attachment'"
 | |
|             v-model="action_params"
 | |
|             :initial-file-name="initialFileName"
 | |
|           />
 | |
|         </div>
 | |
|       </div>
 | |
|       <NextButton
 | |
|         v-if="!isMacro"
 | |
|         icon="i-lucide-x"
 | |
|         slate
 | |
|         ghost
 | |
|         class="flex-shrink-0"
 | |
|         @click="removeAction"
 | |
|       />
 | |
|     </div>
 | |
|     <AutomationActionTeamMessageInput
 | |
|       v-if="inputType === 'team_message'"
 | |
|       v-model="action_params"
 | |
|       :teams="dropdownValues"
 | |
|     />
 | |
|     <WootMessageEditor
 | |
|       v-if="inputType === 'textarea'"
 | |
|       v-model="castMessageVmodel"
 | |
|       rows="4"
 | |
|       enable-variables
 | |
|       :placeholder="$t('AUTOMATION.ACTION.TEAM_MESSAGE_INPUT_PLACEHOLDER')"
 | |
|       class="action-message"
 | |
|     />
 | |
|     <p v-if="errorMessage" class="filter-error">
 | |
|       {{ errorMessage }}
 | |
|     </p>
 | |
|   </div>
 | |
| </template>
 | |
| 
 | |
| <style lang="scss" scoped>
 | |
| .filter {
 | |
|   @apply bg-n-background p-2 border border-solid border-n-strong dark:border-n-strong rounded-lg mb-2;
 | |
| 
 | |
|   &.is-a-macro {
 | |
|     @apply mb-0 bg-n-background dark:bg-n-solid-1 p-0 border-0 rounded-none;
 | |
|   }
 | |
| }
 | |
| 
 | |
| .no-margin-bottom {
 | |
|   @apply mb-0;
 | |
| }
 | |
| 
 | |
| .filter.has-error {
 | |
|   @apply bg-n-ruby-8/20 border-n-ruby-5 dark:border-n-ruby-5;
 | |
| 
 | |
|   &.is-a-macro {
 | |
|     @apply bg-transparent;
 | |
|   }
 | |
| }
 | |
| 
 | |
| .filter-inputs {
 | |
|   @apply flex gap-1;
 | |
| }
 | |
| 
 | |
| .filter-error {
 | |
|   @apply text-n-ruby-9 dark:text-n-ruby-9 block my-1 mx-0;
 | |
| }
 | |
| 
 | |
| .action__question,
 | |
| .filter__operator {
 | |
|   @apply mb-0 mr-1;
 | |
| }
 | |
| 
 | |
| .action__question {
 | |
|   @apply max-w-[50%];
 | |
| }
 | |
| 
 | |
| .action__question.full-width {
 | |
|   @apply max-w-full;
 | |
| }
 | |
| 
 | |
| .filter__answer--wrap {
 | |
|   @apply max-w-[50%] flex-grow mr-1 flex w-full items-center justify-start;
 | |
| 
 | |
|   input {
 | |
|     @apply mb-0;
 | |
|   }
 | |
| }
 | |
| .filter__answer {
 | |
|   &.answer--text-input {
 | |
|     @apply mb-0;
 | |
|   }
 | |
| }
 | |
| 
 | |
| .filter__join-operator-wrap {
 | |
|   @apply relative z-20 m-0;
 | |
| }
 | |
| 
 | |
| .filter__join-operator {
 | |
|   @apply flex items-center justify-center relative my-2.5 mx-0;
 | |
| 
 | |
|   .operator__line {
 | |
|     @apply absolute w-full border-b border-solid border-slate-75 dark:border-slate-600;
 | |
|   }
 | |
| 
 | |
|   .operator__select {
 | |
|     margin-bottom: var(--space-zero) !important;
 | |
|     @apply relative w-auto;
 | |
|   }
 | |
| }
 | |
| 
 | |
| .multiselect {
 | |
|   @apply mb-0;
 | |
| }
 | |
| .action-message {
 | |
|   @apply mt-2 mx-0 mb-0;
 | |
| }
 | |
| // Prosemirror does not have a native way of hiding the menu bar, hence
 | |
| ::v-deep .ProseMirror-menubar {
 | |
|   @apply hidden;
 | |
| }
 | |
| </style>
 |