diff --git a/src/api/subscriber.js b/src/api/subscriber.js index 713448d3..d29ae39c 100644 --- a/src/api/subscriber.js +++ b/src/api/subscriber.js @@ -7,6 +7,7 @@ import { import { getList, get, + getAsBlob, patchAdd, patchReplace, patchRemove, @@ -14,9 +15,11 @@ import { patchAddFull } from './common' + import { assignNumbers } from './user' + export function getPreferences (id) { return new Promise((resolve, reject) => { Vue.http.get('api/subscriberpreferences/' + id).then((result) => { @@ -616,3 +619,9 @@ export async function getSubscriberRegistrations (options) { }) return list } + +export async function getRecordingStream (fileId) { + return await getAsBlob({ + path: 'api/callrecordingfiles/' + fileId + }) +} diff --git a/src/pages/CscPageCallRecording.vue b/src/pages/CscPageCallRecording.vue index c4a63ca8..4c958fb9 100644 --- a/src/pages/CscPageCallRecording.vue +++ b/src/pages/CscPageCallRecording.vue @@ -86,16 +86,6 @@ :icon="isRowExpanded(props.row.id) ? 'expand_less' : 'expand_more'" @click="updateCollapseArray(props.row.id)" /> - {{ col.value }} - + + @@ -170,13 +169,14 @@ import { mapGetters } from 'vuex' import { mapWaitingActions } from 'vue-wait' import { saveAs } from 'file-saver' import { showGlobalError, showToast } from 'src/helpers/ui' -import CscConfirmationDialog from 'components/CscConfirmationDialog' +import CscAudioPlayer from 'components/CscAudioPlayer' import CscPageSticky from 'components/CscPageSticky' import CscCallRecordingFilters from 'components/pages/CallRecording/CscCallRecordingFilters' +import CscRemoveDialog from 'components/CscRemoveDialog' export default { name: 'CscCallBlocking', components: { - CscConfirmationDialog, + CscAudioPlayer, CscPageSticky, CscCallRecordingFilters }, @@ -272,7 +272,8 @@ export default { fetchRecordings: 'csc-call-recordings', fetchStreams: 'csc-call-recordings', deleteRecording: 'csc-call-recordings', - downloadRecording: 'csc-call-recordings' + downloadRecording: 'csc-call-recordings', + playStreamFile: 'csc-call-recordings' }), async fetchPaginatedRecordings (props) { const { page, rowsPerPage, sortBy, descending } = props.pagination @@ -301,7 +302,14 @@ export default { this.showFilters = false }, confirmRowDeletion (rowId) { - this.$refs['confirmDelete-' + rowId].open() + this.$q.dialog({ + component: CscRemoveDialog, + parent: this, + title: this.$t('Delete recording'), + message: this.$t('You are about to delete recording #{id}', { id: rowId }) + }).onOk(() => { + this.deleteRecord(rowId) + }) }, async deleteRecord (rowId) { try { @@ -319,12 +327,17 @@ export default { const rowStatus = this.rowStatus.filter(row => row.id === id)[0] || null return rowStatus && rowStatus.expanded }, - updateCollapseArray (id) { + async updateCollapseArray (id) { const recording = this.recordings.filter(rec => rec.id === id)[0] const rowStatus = this.rowStatus.filter(row => row.id === id)[0] rowStatus.expanded = !rowStatus.expanded if (rowStatus.expanded && recording.files.length === 0) { - this.fetchStreams(id) + this.$wait.start('loading-stream-' + id) + try { + await this.fetchStreams(id) + } finally { + this.$wait.end('loading-stream-' + id) + } } }, async saveFile (fileId) { @@ -348,4 +361,12 @@ export default { font-size 15px .table-td-no-padding padding 0px !important // needed to override .q-table td +.table-td-action-cont + min-width 140px + .player-btns + bottom 9px + left 8px + .download-btn + height 30px + diff --git a/src/store/call-recordings.js b/src/store/call-recordings.js index 04009426..350e842b 100644 --- a/src/store/call-recordings.js +++ b/src/store/call-recordings.js @@ -1,5 +1,5 @@ import Vue from 'vue' -import { getRecordings, getRecordingStreams, downloadRecordingStream } from '../api/subscriber' +import { getRecordings, getRecordingStreams, downloadRecordingStream, getRecordingStream } from '../api/subscriber' export default { namespaced: true, state: { @@ -15,6 +15,11 @@ export default { }, mutations: { callRecordings (state, res) { + (state.recordings || []).forEach(r => { + (r?.files || []).forEach(s => { + if (s.url) URL.revokeObjectURL(s.url) + }) + }) state.recordings = res }, callRecordingStreams (state, data) { @@ -33,6 +38,10 @@ export default { }, async fetchStreams (context, recId) { const streams = await getRecordingStreams(recId) + await Promise.all(streams.map(async stream => { + const blob = await getRecordingStream(stream.id) + stream.url = blob + })) context.commit('callRecordingStreams', { recId: recId, streams: streams