Skip to content

Commit

Permalink
#2019 - Share app logs instead of downloading on mobile (#2026)
Browse files Browse the repository at this point in the history
* update the namings here and there / add check for web-share availability

* add share functionality to the app-logs page

* work on CRs
  • Loading branch information
SebinSong authored May 31, 2024
1 parent 6360d27 commit b454a38
Show file tree
Hide file tree
Showing 2 changed files with 82 additions and 31 deletions.
43 changes: 27 additions & 16 deletions frontend/model/captureLogs.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import sbp from '@sbp/sbp'
import { CAPTURED_LOGS, SET_APP_LOGS_FILTER } from '~/frontend/utils/events.js'
import CircularList from '~/shared/CircularList.js'
import { L } from '@common/common.js'

/*
- giConsole/[username]/entries - the stored log entries.
Expand Down Expand Up @@ -123,24 +124,34 @@ function clearLogs () {
}

// Util to download all stored logs so far.
function downloadLogs (elLink: Object): void {
const filename = 'gi_logs.json'
function downloadOrShareLogs (actionType: 'share' | 'download', elLink?: HTMLAnchorElement): any {
const filename = 'gi_logs.json.txt'
const mimeType = 'text/plain'

const file = new Blob([JSON.stringify({
const blob = new Blob([JSON.stringify({
// Add instructions in case the user opens the file.
_instructions: 'GROUP INCOME - Application Logs - Attach this file when reporting an issue: https://github.com/okTurtles/group-income/issues',
ua: navigator.userAgent,
logs: getLogger().entries.toArray()
}, undefined, 2)], { type: 'application/json' })

const url = URL.createObjectURL(file)
elLink.href = url
elLink.download = filename
elLink.click()
setTimeout(() => {
elLink.href = '#'
URL.revokeObjectURL(url)
}, 0)
}, undefined, 2)], { type: mimeType })

if (actionType === 'download') {
if (!elLink) { return }

const url = URL.createObjectURL(blob)
elLink.href = url
elLink.download = filename
elLink.click()
setTimeout(() => {
elLink.href = '#'
URL.revokeObjectURL(url)
}, 0)
} else {
return window.navigator.share({
files: [new File([blob], filename, { type: blob.type })],
title: L('Application Logs')
})
}
}

function getLogger (): Object {
Expand Down Expand Up @@ -174,9 +185,9 @@ function setAppLogsFilter (filter: Array<string>) {
window.addEventListener('beforeunload', event => sbp('appLogs/save'))

sbp('sbp/selectors/register', {
'appLogs/download' (elLink) { downloadLogs(elLink) },
'appLogs/downloadOrShare': downloadOrShareLogs,
'appLogs/get' () { return getLogger()?.entries?.toArray() ?? [] },
'appLogs/save' () { getLogger()?.save() },
'appLogs/pauseCapture' ({ wipeOut }) { captureLogsPause({ wipeOut }) },
'appLogs/startCapture' (identityContractID) { captureLogsStart(identityContractID) }
'appLogs/pauseCapture': captureLogsPause,
'appLogs/startCapture': captureLogsStart
})
70 changes: 55 additions & 15 deletions frontend/views/containers/user-settings/AppLogs.vue
Original file line number Diff line number Diff line change
Expand Up @@ -25,33 +25,48 @@
input.input(type='checkbox' name='filter' v-model='form.filter' value='log')
i18n Log

button.is-small.c-download(@click='downloadLogs')
i.icon-download.is-prefix.c-icon
i18n.hide-touch Download
i18n.hide-desktop Share
button-submit.is-small.c-download(@click='downloadOrShareLogs')
template(v-if='ephemeral.useWebShare')
i.icon-share-alt.is-prefix
i18n Share
template(v-else)
i.icon-download.is-prefix
i18n Download

a(ref='linkDownload' hidden)

banner-scoped.c-err-banner(ref='errBanner')

textarea.textarea.c-logs(ref='textarea' rows='12' readonly)
| {{ prettyLogs }}

i18n.link(tag='button' @click='openTroubleshooting') Troubleshooting

</template>

<script>
import sbp from '@sbp/sbp'
import { mapMutations } from 'vuex'
import { CAPTURED_LOGS } from '@utils/events.js'
import safeLinkTag from '@view-utils/safeLinkTag.js'
import { L, LError } from '@common/common.js'
import BannerScoped from '@components/banners/BannerScoped.vue'
import ButtonSubmit from '@components/ButtonSubmit.vue'
export default ({
name: 'AppLogs',
components: {
BannerScoped,
ButtonSubmit
},
data () {
return {
form: {
filter: this.$store.state.settings.appLogsFilter
},
ephemeral: {
logs: []
logs: [],
useWebShare: false
}
}
},
Expand All @@ -61,8 +76,13 @@ export default ({
// Log entries in chronological order (oldest to most recent).
this.ephemeral.logs = sbp('appLogs/get')
},
mounted () {
window.addEventListener('resize', this.checkWebShareAvailable)
this.checkWebShareAvailable()
},
beforeDestroy () {
sbp('okTurtles.events/off', CAPTURED_LOGS)
window.removeEventListener('resize', this.checkWebShareAvailable)
},
watch: {
'form.filter' (filter) {
Expand Down Expand Up @@ -108,8 +128,28 @@ export default ({
}
})
},
downloadLogs () {
sbp('appLogs/download', this.$refs.linkDownload)
async downloadOrShareLogs () {
const actionType = this.ephemeral.useWebShare ? 'share' : 'download'
const isDownload = actionType === 'download'
try {
await sbp('appLogs/downloadOrShare',
actionType,
isDownload ? this.$refs.linkDownload : undefined
)
} catch (err) {
const errorDisplay = isDownload
? L('Failed to download the app logs. {reportError}', LError(err))
: L('Failed to share the app logs. {reportError}', LError(err))
console.error(`AppLogs.vue downloadOrShareLogs() '${actionType}' action error:`, err)
this.$refs.errBanner.danger(errorDisplay)
}
},
checkWebShareAvailable () {
this.ephemeral.useWebShare = Boolean(navigator.share) &&
window.matchMedia('(hover: none) and (pointer: coarse)').matches &&
window.matchMedia('screen and (max-width: 1199px)').matches
}
}
}: Object)
Expand Down Expand Up @@ -153,14 +193,6 @@ export default ({
.c-download {
flex-grow: 1;
@include touch {
.c-icon {
&::before {
content: "\f1e0"; // .icon-share-alt
}
}
}
}
.c-filters,
Expand All @@ -174,4 +206,12 @@ export default ({
font-size: $size_5;
white-space: pre;
}
.c-err-banner {
margin-bottom: 1.5rem;
::v-deep .c-banner {
margin-top: 0;
}
}
</style>

0 comments on commit b454a38

Please sign in to comment.