Merge develop into feat/voice-channel

Resolved merge conflicts in:
- MessagesView.vue: Combined VoiceTimelineView component from voice channel feature with component list updates from develop
- actionCable.js: Merged call event handlers (incoming_call, call_status_changed) with copilot message event handler from develop
- message.rb: Combined voice call helper methods with send_update_event method from develop

All conflicts resolved while preserving functionality from both branches.
This commit is contained in:
Sojan
2025-06-20 00:02:50 -07:00
950 changed files with 17551 additions and 3819 deletions
@@ -389,7 +389,7 @@ const shouldRenderMessage = computed(() => {
function openContextMenu(e) {
const shouldSkipContextMenu =
e.target?.classList.contains('skip-context-menu') ||
e.target?.tagName.toLowerCase() === 'a';
['a', 'img'].includes(e.target?.tagName.toLowerCase());
if (shouldSkipContextMenu || getSelection().toString()) {
return;
}
@@ -14,7 +14,8 @@ const fromEmail = computed(() => {
});
const toEmail = computed(() => {
return contentAttributes.value?.email?.to ?? [];
const { toEmails, email } = contentAttributes.value;
return email?.to ?? toEmails ?? [];
});
const ccEmail = computed(() => {
@@ -4,9 +4,11 @@ import BaseBubble from './Base.vue';
import { useI18n } from 'vue-i18n';
import { CONTENT_TYPES } from '../constants.js';
import { useMessageContext } from '../provider.js';
import { useInbox } from 'dashboard/composables/useInbox';
const { content, contentAttributes, contentType } = useMessageContext();
const { t } = useI18n();
const { isAWebWidgetInbox } = useInbox();
const formValues = computed(() => {
if (contentType.value === CONTENT_TYPES.FORM) {
@@ -56,7 +58,7 @@ const formValues = computed(() => {
<dd>{{ item.title }}</dd>
</template>
</dl>
<div v-else class="my-2 font-medium">
<div v-else-if="isAWebWidgetInbox" class="my-2 font-medium">
{{ t('CONVERSATION.NO_RESPONSE') }}
</div>
</BaseBubble>
@@ -120,49 +120,58 @@ const downloadAudio = async () => {
</audio>
<div
v-bind="$attrs"
class="rounded-xl w-full gap-1 p-1.5 bg-n-alpha-white flex items-center border border-n-container shadow-[0px_2px_8px_0px_rgba(94,94,94,0.06)]"
class="rounded-xl w-full gap-2 p-1.5 bg-n-alpha-white flex flex-col items-center border border-n-container shadow-[0px_2px_8px_0px_rgba(94,94,94,0.06)]"
>
<button class="p-0 border-0 size-8" @click="playOrPause">
<Icon
v-if="isPlaying"
class="size-8"
icon="i-teenyicons-pause-small-solid"
/>
<Icon v-else class="size-8" icon="i-teenyicons-play-small-solid" />
</button>
<div class="tabular-nums text-xs">
{{ formatTime(currentTime) }} / {{ formatTime(duration) }}
<div class="flex gap-1 w-full flex-1 items-center justify-start">
<button class="p-0 border-0 size-8" @click="playOrPause">
<Icon
v-if="isPlaying"
class="size-8"
icon="i-teenyicons-pause-small-solid"
/>
<Icon v-else class="size-8" icon="i-teenyicons-play-small-solid" />
</button>
<div class="tabular-nums text-xs">
{{ formatTime(currentTime) }} / {{ formatTime(duration) }}
</div>
<div class="flex-1 items-center flex px-2">
<input
type="range"
min="0"
:max="duration"
:value="currentTime"
class="w-full h-1 bg-n-slate-12/40 rounded-lg appearance-none cursor-pointer accent-current"
@input="seek"
/>
</div>
<button
class="border-0 w-10 h-6 grid place-content-center bg-n-alpha-2 hover:bg-alpha-3 rounded-2xl"
@click="changePlaybackSpeed"
>
<span class="text-xs text-n-slate-11 font-medium">
{{ playbackSpeedLabel }}
</span>
</button>
<button
class="p-0 border-0 size-8 grid place-content-center"
@click="toggleMute"
>
<Icon v-if="isMuted" class="size-4" icon="i-lucide-volume-off" />
<Icon v-else class="size-4" icon="i-lucide-volume-2" />
</button>
<button
class="p-0 border-0 size-8 grid place-content-center"
@click="downloadAudio"
>
<Icon class="size-4" icon="i-lucide-download" />
</button>
</div>
<div class="flex-1 items-center flex px-2">
<input
type="range"
min="0"
:max="duration"
:value="currentTime"
class="w-full h-1 bg-n-slate-12/40 rounded-lg appearance-none cursor-pointer accent-current"
@input="seek"
/>
<div
v-if="attachment.transcribedText"
class="text-n-slate-12 p-3 text-sm bg-n-alpha-1 rounded-lg w-full break-words"
>
{{ attachment.transcribedText }}
</div>
<button
class="border-0 w-10 h-6 grid place-content-center bg-n-alpha-2 hover:bg-alpha-3 rounded-2xl"
@click="changePlaybackSpeed"
>
<span class="text-xs text-n-slate-11 font-medium">
{{ playbackSpeedLabel }}
</span>
</button>
<button
class="p-0 border-0 size-8 grid place-content-center"
@click="toggleMute"
>
<Icon v-if="isMuted" class="size-4" icon="i-lucide-volume-off" />
<Icon v-else class="size-4" icon="i-lucide-volume-2" />
</button>
<button
class="p-0 border-0 size-8 grid place-content-center"
@click="downloadAudio"
>
<Icon class="size-4" icon="i-lucide-download" />
</button>
</div>
</template>