From 69c8a75860e958eaa4646aca65d6e8bdd6273616 Mon Sep 17 00:00:00 2001 From: Grzegorz Godlewski Date: Tue, 19 Dec 2023 18:38:47 +0100 Subject: [PATCH] Improve jobs preview --- apps/ui/src/components/ChangesViewer.vue | 50 ++++++++-------- apps/ui/src/components/JobLogsViewer.vue | 31 +++++++++- src/containers/server/ServerContainer.ts | 57 ++++++++++--------- .../server/routes/LogsController.ts | 11 ++-- tsconfig.json | 1 + 5 files changed, 87 insertions(+), 63 deletions(-) diff --git a/apps/ui/src/components/ChangesViewer.vue b/apps/ui/src/components/ChangesViewer.vue index 19c0c8bd..1ce8de6b 100644 --- a/apps/ui/src/components/ChangesViewer.vue +++ b/apps/ui/src/components/ChangesViewer.vue @@ -50,7 +50,6 @@ Jobs
-
Last full sync @@ -64,40 +63,26 @@
- +
- - + + + + + - - + + + + -
JobProgress
JobStartedFinished
{{ job.title }}{{ job.startedStr || job.state }}  {{ job.progress.completed }} / {{ job.progress.total }} - {{ job.state }} + Logs
- -
- No active jobs -
- -
- -
-
- Jobs done -
-
- - - - - - @@ -111,7 +96,6 @@
JobStartedFinished
{{ job.title }}
-
@@ -133,6 +117,18 @@ export default { }, components: {StatusToolBar}, computed: { + active_jobs_reverse() { + return [].concat(this.active_jobs) + .map(a => { + return { + ...a, + finishedStr: a.finished ? new Date(a.finished).toISOString() : undefined, + startedStr: a.started ? new Date(a.started).toISOString() : undefined, + durationStr: a.started && a.finished ? Math.round((+new Date(a.finished) - +new Date(a.started)) / 100)/10 + 's' : undefined + }; + }) + .reverse(); + }, fileChanges() { return this.changes.filter(change => change.mimeType !== 'application/vnd.google-apps.folder'); }, diff --git a/apps/ui/src/components/JobLogsViewer.vue b/apps/ui/src/components/JobLogsViewer.vue index 79181f36..1e5f8dbc 100644 --- a/apps/ui/src/components/JobLogsViewer.vue +++ b/apps/ui/src/components/JobLogsViewer.vue @@ -36,15 +36,22 @@ export default { }, contentDir: { type: String + }, + autoRefresh: { + type: Boolean } }, data() { return { errorsOnly: false, - logs: [] + logs: [], + intervalHandle: null }; }, computed: { + currentJob() { + return this.$root.jobs.find(job => 'job-' + job.id === this.jobId); + }, absPath() { return '/drive/' + this.driveId + this.contentDir; }, @@ -63,13 +70,19 @@ export default { } const jobId = this.jobId.substring('job-'.length); - const response = await this.authenticatedClient.fetchApi(`/api/logs/${this.driveId}?order=asc&jobId=` + (jobId)); + const response = await this.authenticatedClient.fetchApi(`/api/logs/${this.driveId}?order=asc&jobId=` + (jobId) + '&offset=' + this.logs.length); const logs = await response.json(); + + if (this.intervalHandle && this.currentJob && this.currentJob.finished) { + clearInterval(this.intervalHandle); + this.intervalHandle = null; + } + if (logs.length === 0) { return; } - this.logs = logs; + this.logs = this.logs.concat(logs); if (logs.length > 0) { this.handleScroll(); @@ -139,6 +152,18 @@ export default { this.handleScroll(); // Prism.highlightElement(this.$refs.code); + if (!this.intervalHandle && this.currentJob && !this.currentJob.finished) { + this.intervalHandle = setInterval(() => { + this.fetch(); + }, 1000); + } + }, + beforeUnmount() { + if (!this.intervalHandle) { + return; + } + clearInterval(this.intervalHandle); + this.intervalHandle = null; } }; diff --git a/src/containers/server/ServerContainer.ts b/src/containers/server/ServerContainer.ts index 5116183c..7de4a0f6 100644 --- a/src/containers/server/ServerContainer.ts +++ b/src/containers/server/ServerContainer.ts @@ -1,29 +1,31 @@ -import {Container, ContainerConfig, ContainerEngine} from '../../ContainerEngine'; import type {Express, NextFunction, Request, Response} from 'express'; import express from 'express'; import http from 'http'; import {WebSocketServer} from 'ws'; import winston from 'winston'; import path from 'path'; -import {FileId} from '../../model/model'; -import {saveRunningInstance} from './loadRunningInstance'; -import {urlToFolderId} from '../../utils/idParsers'; -import {GoogleDriveService} from '../../google/GoogleDriveService'; -import {FolderRegistryContainer} from '../folder_registry/FolderRegistryContainer'; -import {DriveJobsMap, initJob, JobManagerContainer} from '../job/JobManagerContainer'; import {fileURLToPath} from 'url'; -import GitController from './routes/GitController'; -import FolderController from './routes/FolderController'; -import {ConfigController} from './routes/ConfigController'; -import {DriveController} from './routes/DriveController'; -import {BackLinksController} from './routes/BackLinksController'; -import {GoogleDriveController} from './routes/GoogleDriveController'; -import {LogsController} from './routes/LogsController'; -import {PreviewController} from './routes/PreviewController'; import cookieParser from 'cookie-parser'; import rateLimit from 'express-rate-limit'; +import compress from 'compression'; -import {SocketManager} from './SocketManager'; +import {Container, ContainerConfig, ContainerEngine} from '../../ContainerEngine.ts'; +import {FileId} from '../../model/model.ts'; +import {saveRunningInstance} from './loadRunningInstance.ts'; +import {urlToFolderId} from '../../utils/idParsers.ts'; +import {GoogleDriveService} from '../../google/GoogleDriveService.ts'; +import {FolderRegistryContainer} from '../folder_registry/FolderRegistryContainer.ts'; +import {DriveJobsMap, initJob, JobManagerContainer} from '../job/JobManagerContainer.ts'; +import GitController from './routes/GitController.ts'; +import FolderController from './routes/FolderController.ts'; +import {ConfigController} from './routes/ConfigController.ts'; +import {DriveController} from './routes/DriveController.ts'; +import {BackLinksController} from './routes/BackLinksController.ts'; +import {GoogleDriveController} from './routes/GoogleDriveController.ts'; +import {LogsController} from './routes/LogsController.ts'; +import {PreviewController} from './routes/PreviewController.ts'; + +import {SocketManager} from './SocketManager.ts'; import { authenticate, @@ -32,18 +34,17 @@ import { authenticateOptionally, validateGetAuthState, handleDriveUiInstall, handleShare, handlePopupClose, redirError -} from './auth'; -import {filterParams} from '../../google/driveFetch'; -import {SearchController} from './routes/SearchController'; -import {DriveUiController} from './routes/DriveUiController'; -import {GoogleApiContainer} from '../google_api/GoogleApiContainer'; -import {UserAuthClient} from '../../google/AuthClient'; -import {getTokenInfo} from '../../google/GoogleAuthService'; -import {GoogleTreeProcessor} from '../google_folder/GoogleTreeProcessor'; -import compress from 'compression'; -import {initStaticDistPages} from './static'; -import {initUiServer} from './vuejs'; -import {initErrorHandler} from './error'; +} from './auth.ts'; +import {filterParams} from '../../google/driveFetch.ts'; +import {SearchController} from './routes/SearchController.ts'; +import {DriveUiController} from './routes/DriveUiController.ts'; +import {GoogleApiContainer} from '../google_api/GoogleApiContainer.ts'; +import {UserAuthClient} from '../../google/AuthClient.ts'; +import {getTokenInfo} from '../../google/GoogleAuthService.ts'; +import {GoogleTreeProcessor} from '../google_folder/GoogleTreeProcessor.ts'; +import {initStaticDistPages} from './static.ts'; +import {initUiServer} from './vuejs.ts'; +import {initErrorHandler} from './error.ts'; const __filename = fileURLToPath(import.meta.url); const __dirname = path.dirname(__filename); diff --git a/src/containers/server/routes/LogsController.ts b/src/containers/server/routes/LogsController.ts index d7a522da..0e8b5772 100644 --- a/src/containers/server/routes/LogsController.ts +++ b/src/containers/server/routes/LogsController.ts @@ -1,5 +1,5 @@ -import {Controller, RouteGet, RouteParamPath, RouteParamQuery} from './Controller'; -import {Logger, QueryOptions} from 'winston'; +import {Controller, RouteGet, RouteParamPath, RouteParamQuery} from './Controller.ts'; +import {Logger} from 'winston'; export class LogsController extends Controller { @@ -12,7 +12,8 @@ export class LogsController extends Controller { @RouteParamQuery('from') from?: number, @RouteParamQuery('until') until?: number, @RouteParamQuery('jobId') jobId?: string, - @RouteParamQuery('order') order?: 'desc' | 'asc' + @RouteParamQuery('order') order?: 'desc' | 'asc', + @RouteParamQuery('offset') offset?: number ) { if (!until && !from) { @@ -44,10 +45,10 @@ export class LogsController extends Controller { })); if (jobId) { - return results['jobLogFile']; + return results['jobLogFile'].slice(offset || 0); } - return results['dailyRotateFile'].reverse(); + return results['dailyRotateFile'].reverse().slice(offset || 0); } } diff --git a/tsconfig.json b/tsconfig.json index 864dc78a..f8a14777 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -4,6 +4,7 @@ "module": "node16", "moduleResolution": "node16", "target": "es2022", + "allowImportingTsExtensions": true, "resolveJsonModule": true, "esModuleInterop": true, "sourceMap": true,