Skip to content

Commit

Permalink
feat(#117): refactor task list item, fix not be able to stop JFR reco…
Browse files Browse the repository at this point in the history
…rding
  • Loading branch information
lukashornych committed Oct 7, 2024
1 parent e2b34fb commit c3a27e9
Show file tree
Hide file tree
Showing 15 changed files with 465 additions and 256 deletions.
7 changes: 5 additions & 2 deletions src/modules/backup-viewer/components/BackupViewer.vue
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,7 @@ loadBackupFiles().then(() => {
})
let canReloadBackupFiles: boolean = true
let reloadBackupFilesTimeoutId: number | undefined = undefined
async function reloadBackupFiles(manual: boolean = false): Promise<void> {
if (!canReloadBackupFiles && !manual) {
return
Expand All @@ -94,13 +95,13 @@ async function reloadBackupFiles(manual: boolean = false): Promise<void> {
const loaded: boolean = await loadBackupFiles()
if (loaded) {
canReloadBackupFiles = true
setTimeout(reloadBackupFiles, 2000)
reloadBackupFilesTimeoutId = setTimeout(reloadBackupFiles, 2000)

Check failure on line 98 in src/modules/backup-viewer/components/BackupViewer.vue

View workflow job for this annotation

GitHub Actions / Build

Type 'Timeout' is not assignable to type 'number'.
} else {
// we don't want to spam user server is down, user needs to refresh manually
canReloadBackupFiles = false
}
}
setTimeout(reloadBackupFiles, 2000)
reloadBackupFilesTimeoutId = setTimeout(reloadBackupFiles, 2000)

Check failure on line 104 in src/modules/backup-viewer/components/BackupViewer.vue

View workflow job for this annotation

GitHub Actions / Build

Type 'Timeout' is not assignable to type 'number'.
function reloadBackups(): void {
reloadBackupFiles(true)
Expand Down Expand Up @@ -138,6 +139,8 @@ async function downloadBackup(file: ServerFile){
))
}
}
onUnmounted(() => clearInterval(reloadBackupFilesTimeoutId))
</script>

<template>
Expand Down
12 changes: 6 additions & 6 deletions src/modules/connection/model/task/TaskStatus.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ export class TaskStatus {
readonly traits: Immutable.Set<TaskTrait>

private _cancelRequested: boolean = false
private _elapsed?: Duration = undefined
private _duration?: Duration = undefined

constructor(taskType: string,
taskName: string,
Expand Down Expand Up @@ -69,20 +69,20 @@ export class TaskStatus {
}
}

get elapsed(): Duration | undefined {
if (this._elapsed == undefined || this.finished == undefined) {
get duration(): Duration | undefined {
if (this._duration == undefined || this.finished == undefined) {
if (this.started == undefined) {
this._elapsed = undefined
this._duration = undefined
} else {
const startTime: number = Number(this.started.timestamp!.seconds) * 1000
const endTime: number = this.finished != null
? Number(this.finished.timestamp!.seconds) * 1000
: DateTime.now().toMillis()

const duration: number = endTime - startTime
this._elapsed = Duration.fromMillis(duration)
this._duration = Duration.fromMillis(duration)
}
}
return this._elapsed
return this._duration
}
}
11 changes: 7 additions & 4 deletions src/modules/i18n/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -1021,7 +1021,7 @@
"downloadFileResult": "Download result",
"textResult": "Result",
"exception": "Exception",
"cancel": "Manually cancel task"
"cancel": "Forcefully cancel task"
},
"progress": {
"indeterminate": "running..."
Expand All @@ -1044,8 +1044,8 @@
"notStarted": "<task hasn't yet been started>",
"notFinished": "<task hasn't yet been finished>"
},
"elapsed": {
"label": "Time elapsed",
"duration": {
"label": "Duration",
"notStarted": "<task hasn't yet been started>"
},
"progress": "Progress",
Expand Down Expand Up @@ -1077,7 +1077,10 @@
"startRecording": "Start recording"
},
"tasks": {
"title": "Running recordings"
"title": "Running recordings",
"button": {
"stopRecording": "Stop recording"
}
},
"list": {
"title": "Finished recordings"
Expand Down
24 changes: 12 additions & 12 deletions src/modules/jfr-viewer/components/JfrViewer.vue
Original file line number Diff line number Diff line change
@@ -1,17 +1,13 @@
<script setup lang="ts">
import { List } from 'immutable'
import { useI18n } from 'vue-i18n'
import { computed, ref } from 'vue'
import { computed, onUnmounted, ref } from 'vue'
import { TabComponentEvents } from '@/modules/workspace/tab/model/TabComponentEvents'
import { TabComponentProps } from '@/modules/workspace/tab/model/TabComponentProps'
import { VoidTabData } from '@/modules/workspace/tab/model/void/VoidTabData'
import { JfrViewerTabParams } from '@/modules/jfr-viewer/model/JfrViewerTabParams'
import {
JfrViewerService,
useJfrViewerService,
} from '@/modules/jfr-viewer/service/JfrViewerService'
import { JfrViewerService, useJfrViewerService } from '@/modules/jfr-viewer/service/JfrViewerService'
import { VBtn, VIcon, VList } from 'vuetify/components'
import { onUnmounted } from 'vue'
import { ServerFile } from '@/modules/connection/model/server-file/ServerFile'
import { Toaster, useToaster } from '@/modules/notification/service/Toaster'
import VTabToolbar from '@/modules/base/component/VTabToolbar.vue'
Expand All @@ -23,7 +19,7 @@ import { PaginatedList } from '@/modules/connection/model/PaginatedList'
import { jfrRecorderTaskName } from '@/modules/jfr-viewer/model/JfrRecorderTask'
import TaskList from '@/modules/task-viewer/components/TaskList.vue'
const shownTaskStates: TaskState[] = [TaskState.Running, TaskState.Queued]
const shownTaskStates: TaskState[] = [TaskState.Running, TaskState.Queued, TaskState.Failed]
const shownTaskTypes: string[] = [jfrRecorderTaskName]
const jfrViewerService: JfrViewerService = useJfrViewerService()
Expand Down Expand Up @@ -117,13 +113,17 @@ async function downloadRecording(file: ServerFile) {
hideable-pagination
@update:active-jobs-present="runningRecordingsPresent = $event"
>
<template #cancel-action="{ taskStatus }">
<template #item-append-action-buttons="{ task }">
<VBtn
icon="mdi-stop-circle-outline"
density="compact"
variant="flat"
v-if="task.state === TaskState.Running"
icon
@click="showEndRecordingDialog = true"
/>
>
<VIcon>mdi-stop-circle-outline</VIcon>
<VTooltip activator="parent">
{{ t('jfrViewer.tasks.button.stopRecording') }}
</VTooltip>
</VBtn>
</template>
</TaskList>

Expand Down
76 changes: 76 additions & 0 deletions src/modules/task-viewer/components/CancelTaskButton.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
<script setup lang="ts">
import { computed, ref } from 'vue'
import { TaskTrait } from '@/modules/connection/model/task/TaskTrait'
import { TaskStatus } from '@/modules/connection/model/task/TaskStatus'
import { TaskViewerService, useTaskViewerService } from '@/modules/task-viewer/services/TaskViewerService'
import { Toaster, useToaster } from '@/modules/notification/service/Toaster'
import { useI18n } from 'vue-i18n'
import { Connection } from '@/modules/connection/model/Connection'
const taskViewerService: TaskViewerService = useTaskViewerService()
const toaster: Toaster = useToaster()
const { t } = useI18n()
const props = defineProps<{
connection: Connection
task: TaskStatus
}>()
const cancelling = ref<boolean>(false)
const canBeCancelled = computed<boolean>(() => {
return (
props.task.traits.contains(TaskTrait.CanBeCancelled) ||
props.task.traits.contains(TaskTrait.NeedsToBeStopped)
) &&
!props.task.isCancelRequested
})
async function cancelTask(): Promise<void> {
cancelling.value = true
try {
const cancelled = await taskViewerService.cancelTask(props.connection, props.task.taskId)
if (cancelled) {
toaster.success(t(
'taskViewer.tasksVisualizer.notification.taskCancelled',
{ taskName: props.task.taskName }
))
} else {
toaster.info(t(
'taskViewer.tasksVisualizer.notification.taskNotCancelled',
{ taskName: props.task.taskName }
))
}
// visualize the cancel until the next full reload
props.task.cancelRequested()
} catch (e: any) {
toaster.error(t(
'taskViewer.tasksVisualizer.notification.couldNotCancelTask',
{
taskName: props.task.taskName,
reason: e.message
}
))
}
cancelling.value = false
}
</script>

<template>
<VBtn
v-if="canBeCancelled"
icon
:loading="cancelling"
@click="cancelTask"
>
<VIcon>mdi-close</VIcon>

<VTooltip activator="parent">
{{ t('taskViewer.tasksVisualizer.task.button.cancel') }}
</VTooltip>
</VBtn>
</template>

<style lang="scss" scoped>
</style>
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
<script setup lang="ts">
import { FileTaskResult } from '@/modules/connection/model/task/FileTaskResult'
import VDownloadServerFileButton from '@/modules/connection/component/VDownloadServerFileButton.vue'
import { TaskStatus } from '@/modules/connection/model/task/TaskStatus'
import { Toaster, useToaster } from '@/modules/notification/service/Toaster'
import { useI18n } from 'vue-i18n'
import { Connection } from '@/modules/connection/model/Connection'
const toaster: Toaster = useToaster()
const { t } = useI18n()
const props = defineProps<{
connection: Connection
task: TaskStatus
}>()
function onCouldNotDownloadResultFile(e: Error): void {
toaster.error(t(
'taskViewer.tasksVisualizer.task.notification.couldNotDownloadResultFile',
{
taskName: props.task.taskName,
reason: e.message
}
))
}
</script>

<template>
<VDownloadServerFileButton

:connection="connection"
:file="(task.result as FileTaskResult).value"
@error="onCouldNotDownloadResultFile($event)"
>
{{ t('taskViewer.tasksVisualizer.task.button.downloadFileResult') }}
</VDownloadServerFileButton>
</template>

<style lang="scss" scoped>
</style>
41 changes: 41 additions & 0 deletions src/modules/task-viewer/components/ShowTaskDetailButton.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
<script setup lang="ts">
import TaskDetailDialog from '@/modules/task-viewer/components/TaskDetailDialog.vue'
import { ref } from 'vue'
import { TaskStatus } from '@/modules/connection/model/task/TaskStatus'
import { useI18n } from 'vue-i18n'
const { t } = useI18n()
const props = defineProps<{
task: TaskStatus
}>()
const showDetailsDialog = ref<boolean>(false)
</script>

<template>
<TaskDetailDialog
v-model="showDetailsDialog"
:task="task"
>
<template #activator="{ props }">
<VBtn
icon
v-bind="props"
@click="showDetailsDialog = true"
>
<VIcon>mdi-information-outline</VIcon>

<VTooltip activator="parent">
{{ t('taskViewer.tasksVisualizer.task.button.details') }}
</VTooltip>
</VBtn>
</template>
</TaskDetailDialog>
</template>

<style lang="scss" scoped>
</style>
42 changes: 42 additions & 0 deletions src/modules/task-viewer/components/ShowTaskExceptionButton.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
<script setup lang="ts">
import TaskExceptionDialog from '@/modules/task-viewer/components/TaskExceptionDialog.vue'
import { ref } from 'vue'
import { TaskStatus } from '@/modules/connection/model/task/TaskStatus'
import { useI18n } from 'vue-i18n'
const { t } = useI18n()
const props = defineProps<{
task: TaskStatus
}>()
const showExceptionDialog = ref<boolean>(false)
</script>

<template>
<TaskExceptionDialog
v-model="showExceptionDialog"
:exception="task.exception || ''"
>
<template #activator="{ props }">
<VBtn
icon
variant="text"
color="warning"
v-bind="props"
@click="showExceptionDialog = true"
>
<VIcon>mdi-alert-outline</VIcon>

<VTooltip activator="parent">
{{ t('taskViewer.tasksVisualizer.task.button.exception') }}
</VTooltip>
</VBtn>
</template>
</TaskExceptionDialog>
</template>

<style lang="scss" scoped>
</style>
41 changes: 41 additions & 0 deletions src/modules/task-viewer/components/ShowTaskTextResultButton.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
<script setup lang="ts">
import { TextTaskResult } from '@/modules/connection/model/task/TextTaskResult'
import TaskTextResultDialog from '@/modules/task-viewer/components/TaskTextResultDialog.vue'
import { ref } from 'vue'
import { TaskStatus } from '@/modules/connection/model/task/TaskStatus'
import { useI18n } from 'vue-i18n'
const { t } = useI18n()
const props = defineProps<{
task: TaskStatus
}>()
const showResultTextDialog = ref<boolean>(false)
</script>

<template>
<TaskTextResultDialog
v-model="showResultTextDialog"
:result="task.result as TextTaskResult"
>
<template #activator="{ props }">
<VBtn
icon
v-bind="props"
@click="showResultTextDialog = true"
>
<VIcon>mdi-file-document-outline</VIcon>

<VTooltip activator="parent">
{{ t('taskViewer.tasksVisualizer.task.button.textResult') }}
</VTooltip>
</VBtn>
</template>
</TaskTextResultDialog>
</template>

<style lang="scss" scoped>
</style>
Loading

0 comments on commit c3a27e9

Please sign in to comment.