diff --git a/package.json b/package.json index 4ff15889..3f19af15 100644 --- a/package.json +++ b/package.json @@ -54,7 +54,7 @@ "vue-router": "^4.0.0", "vue-toastification": "^2.0.0-rc.5", "vue3-apexcharts": "^1.4.4", - "vuetify": "^3.1.0", + "vuetify": "^3.6.0", "webfontloader": "^1.0.0", "xml-formatter": "^3.5.0", "xxhashjs": "^0.2.2" diff --git a/src/modules/backup-viewer/BackupViewerModuleRegistrar.ts b/src/modules/backup-viewer/BackupViewerModuleRegistrar.ts new file mode 100644 index 00000000..027cbae7 --- /dev/null +++ b/src/modules/backup-viewer/BackupViewerModuleRegistrar.ts @@ -0,0 +1,14 @@ +import { ModuleContextBuilder } from "@/ModuleContextBuilder"; +import { ModuleRegistrar } from "@/ModuleRegistrar"; +import { BackupViewerService, backupViewerServiceInjectionKey } from "./service/BackupViewerService"; +import { ConnectionService, connectionServiceInjectionKey } from '@/modules/connection/service/ConnectionService' + +//TODO: docs +export class BackupViewerModuleRegistrar implements ModuleRegistrar { + + register(builder: ModuleContextBuilder): void { + const connectionService: ConnectionService = builder.inject(connectionServiceInjectionKey) + const backupViewerService: BackupViewerService = new BackupViewerService(connectionService) + builder.provide(backupViewerServiceInjectionKey, backupViewerService) + } +} diff --git a/src/modules/backup-viewer/components/BackupCatalogDialog.vue b/src/modules/backup-viewer/components/BackupCatalogDialog.vue new file mode 100644 index 00000000..4a081dfc --- /dev/null +++ b/src/modules/backup-viewer/components/BackupCatalogDialog.vue @@ -0,0 +1,141 @@ + + + + + diff --git a/src/modules/backup-viewer/components/BackupViewer.vue b/src/modules/backup-viewer/components/BackupViewer.vue new file mode 100644 index 00000000..6adeaf50 --- /dev/null +++ b/src/modules/backup-viewer/components/BackupViewer.vue @@ -0,0 +1,286 @@ + + + + + diff --git a/src/modules/backup-viewer/components/RestoreCatalogDialog.vue b/src/modules/backup-viewer/components/RestoreCatalogDialog.vue new file mode 100644 index 00000000..557f4558 --- /dev/null +++ b/src/modules/backup-viewer/components/RestoreCatalogDialog.vue @@ -0,0 +1,119 @@ + + + + + diff --git a/src/modules/backup-viewer/model/BackupViewerDefinition.ts b/src/modules/backup-viewer/model/BackupViewerDefinition.ts new file mode 100644 index 00000000..2c287598 --- /dev/null +++ b/src/modules/backup-viewer/model/BackupViewerDefinition.ts @@ -0,0 +1,17 @@ +import { TabDefinition } from "@/modules/workspace/tab/model/TabDefinition"; +import { VoidTabData } from "@/modules/workspace/tab/model/void/VoidTabData"; +import { DefineComponent, markRaw } from "vue"; +import { BackupViewerTabParams } from '@/modules/backup-viewer/model/BackupViewerTabParams' +import BackupViewer from '@/modules/backup-viewer/components/BackupViewer.vue' + +export class BackupViewerDefinition extends TabDefinition { + constructor(title: string, params: BackupViewerTabParams) { + super(undefined, + title, + 'mdi-cloud-download-outline', + markRaw(BackupViewer as DefineComponent), + params, + new VoidTabData() + ) + } +} diff --git a/src/modules/backups/model/BackupsTabParams.ts b/src/modules/backup-viewer/model/BackupViewerTabParams.ts similarity index 74% rename from src/modules/backups/model/BackupsTabParams.ts rename to src/modules/backup-viewer/model/BackupViewerTabParams.ts index 52144d7f..22a97644 100644 --- a/src/modules/backups/model/BackupsTabParams.ts +++ b/src/modules/backup-viewer/model/BackupViewerTabParams.ts @@ -1,9 +1,9 @@ import { TabParams } from "@/modules/workspace/tab/model/TabParams"; -import { BackupsTabParamsDto } from "./BackupsTabParamsDto"; +import { BackupViewerTabParamsDto } from "./BackupViewerTabParamsDto"; import { ExecutableTabRequest } from "@/modules/workspace/tab/model/ExecutableTabRequest"; import { Connection } from "@/modules/connection/model/Connection"; -export class BackupTabParams implements TabParams, ExecutableTabRequest { +export class BackupViewerTabParams implements TabParams, ExecutableTabRequest { readonly executeOnOpen: boolean readonly connection: Connection readonly catalogName: string @@ -13,10 +13,10 @@ export class BackupTabParams implements TabParams, Executab this.executeOnOpen = executeOnOpen this.catalogName = catalogName } - toSerializable(): BackupsTabParamsDto { + toSerializable(): BackupViewerTabParamsDto { return { connection: this.connection, catalogName: this.catalogName } } -} \ No newline at end of file +} diff --git a/src/modules/backups/model/BackupsTabParamsDto.ts b/src/modules/backup-viewer/model/BackupViewerTabParamsDto.ts similarity index 81% rename from src/modules/backups/model/BackupsTabParamsDto.ts rename to src/modules/backup-viewer/model/BackupViewerTabParamsDto.ts index 63ab05dc..88e78201 100644 --- a/src/modules/backups/model/BackupsTabParamsDto.ts +++ b/src/modules/backup-viewer/model/BackupViewerTabParamsDto.ts @@ -2,7 +2,7 @@ import { Connection } from "@/modules/connection/model/Connection"; import { TabDataDto } from "@/modules/workspace/tab/model/TabDataDto"; import { TabParamsDto } from '@/modules/workspace/tab/model/TabParamsDto' -export interface BackupsTabParamsDto extends TabParamsDto { +export interface BackupViewerTabParamsDto extends TabParamsDto { readonly connection: Connection readonly catalogName: string } diff --git a/src/modules/backup-viewer/service/BackupViewerService.ts b/src/modules/backup-viewer/service/BackupViewerService.ts new file mode 100644 index 00000000..db098002 --- /dev/null +++ b/src/modules/backup-viewer/service/BackupViewerService.ts @@ -0,0 +1,104 @@ +import { Connection } from '@/modules/connection/model/Connection' +import { OffsetDateTime } from '@/modules/connection/model/data-type/OffsetDateTime' +import { Uuid } from '@/modules/connection/model/data-type/Uuid' +import { mandatoryInject } from '@/utils/reactivity' +import { InjectionKey } from 'vue' +import { + GrpcRestoreCatalogRequest, + GrpcRestoreCatalogResponse +} from '@/modules/connection/driver/grpc/gen/GrpcEvitaManagementAPI_pb' +import { ConnectionService } from '@/modules/connection/service/ConnectionService' +import { CatalogVersionAtResponse } from '@/modules/connection/model/CatalogVersionAtResponse' +import { TaskStatus } from '@/modules/connection/model/task/TaskStatus' +import { FilesToFetch } from '@/modules/connection/model/file/FilesToFetch' +import { ClassifierValidationErrorType } from '@/modules/connection/model/data-type/ClassifierValidationErrorType' +import { EvitaDBDriver } from '@/modules/connection/driver/EvitaDBDriver' +import { ClassifierType } from '@/modules/connection/model/data-type/ClassifierType' +import { UnexpectedError } from '@/modules/base/exception/UnexpectedError' + +export const backupViewerServiceInjectionKey: InjectionKey = Symbol('backupViewerService') + +export const backupTaskName: string = 'BackupTask' +export const restoreTaskName: string = 'RestoreTask' + +export class BackupViewerService { + private readonly connectionService: ConnectionService + + constructor(connectionService: ConnectionService) { + this.connectionService = connectionService + } + + async getMinimalBackupDate( + connection: Connection, + catalogName: string + ): Promise { + const driver = await this.connectionService.getDriver(connection) + return driver.getMinimalBackupDate(connection, catalogName) + } + + async backupCatalog( + connection: Connection, + catalogName: string, + includingWAL: boolean, + pastMoment: OffsetDateTime + ): Promise { + const driver = await this.connectionService.getDriver(connection) + return driver.createBackup( + connection, + catalogName, + includingWAL, + pastMoment + ) + } + + async getBackupFiles( + connection: Connection, + pageNumber: number, + pageSize: number + ): Promise { + const driver = await this.connectionService.getDriver(connection) + return await driver.getFilesToFetch(connection, backupTaskName, pageNumber, pageSize) + } + + async restoreCatalog( + connection: Connection, + fileId: Uuid, + catalogName: string + ): Promise { + const driver = await this.connectionService.getDriver(connection) + return await driver.restoreCatalog(connection, fileId, catalogName) + } + + async downloadBackup(connection: Connection, fileId: Uuid): Promise { + const driver = await this.connectionService.getDriver(connection) + return await driver.downloadFile(connection, fileId) + } + + async uploadBackup(connection: Connection, stream: AsyncIterable): Promise{ + const driver = await this.connectionService.getDriver(connection) + return await driver.uploadFile(connection, stream) + } + + async isCatalogNameValid(connection: Connection, catalogName: string): Promise { + const driver: EvitaDBDriver = await this.connectionService.getDriver(connection) + return driver.isClassifierValid(connection, ClassifierType.Catalog, catalogName) + } + + async isCatalogNameAvailable(connection: Connection, catalogName: string): Promise { + const driver: EvitaDBDriver = await this.connectionService.getDriver(connection) + try { + await driver.getCatalog(connection, catalogName) + } catch (e) { + // todo lho better exceptions + if (e instanceof UnexpectedError) { + // catalog not found + return true + } + } + return false + } +} + +export const useBackupViewerService = (): BackupViewerService => { + return mandatoryInject(backupViewerServiceInjectionKey) as BackupViewerService +} diff --git a/src/modules/backup-viewer/service/BackupViewerTabFactory.ts b/src/modules/backup-viewer/service/BackupViewerTabFactory.ts new file mode 100644 index 00000000..eb00a176 --- /dev/null +++ b/src/modules/backup-viewer/service/BackupViewerTabFactory.ts @@ -0,0 +1,36 @@ +import { Connection } from "@/modules/connection/model/Connection"; +import { ConnectionService } from "@/modules/connection/service/ConnectionService"; +import { mandatoryInject } from "@/utils/reactivity"; +import { InjectionKey } from "vue"; +import { BackupViewerDefinition } from "../model/BackupViewerDefinition"; +import { TabParamsDto } from "@/modules/workspace/tab/model/TabParamsDto"; +import { TabDataDto } from "@/modules/workspace/tab/model/TabDataDto"; +import { BackupViewerTabParamsDto } from "../model/BackupViewerTabParamsDto"; +import { BackupViewerTabParams } from '@/modules/backup-viewer/model/BackupViewerTabParams' + +export const backupsTabFactoryInjectionKey: InjectionKey = Symbol('BackupsTabFactory') + +export class BackupViewerTabFactory { + private readonly connectionService: ConnectionService + + constructor(connectionService: ConnectionService){ + this.connectionService = connectionService + } + + createNew(connection: Connection, catalogName: string, executeOnOpen: boolean = false):BackupViewerDefinition { + return new BackupViewerDefinition('Backups', this.createTabParams(connection, catalogName, executeOnOpen)) + } + + private createTabParams(connection: Connection, catalogName: string, executeOnOpen: boolean = false):BackupViewerTabParams { + return new BackupViewerTabParams(connection, catalogName, executeOnOpen) + } + + restoreFromJson(paramsJson: TabParamsDto, dataJson?: TabDataDto): BackupViewerDefinition { + const params: BackupViewerTabParamsDto = paramsJson as BackupViewerTabParams + return new BackupViewerDefinition('Backups', this.createTabParams(this.connectionService.getConnection(params.connection.id), params.catalogName)) + } +} + +export const useBackupsTabFactory = (): BackupViewerTabFactory => { + return mandatoryInject(backupsTabFactoryInjectionKey) as BackupViewerTabFactory +} diff --git a/src/modules/backups/BackupsModuleRegistrar.ts b/src/modules/backups/BackupsModuleRegistrar.ts deleted file mode 100644 index ade16d73..00000000 --- a/src/modules/backups/BackupsModuleRegistrar.ts +++ /dev/null @@ -1,14 +0,0 @@ -import { ModuleContextBuilder } from "@/ModuleContextBuilder"; -import { ModuleRegistrar } from "@/ModuleRegistrar"; -import { EvitaDBDriverResolver, evitaDBDriverResolverInjectionKey } from "../connection/driver/EvitaDBDriverResolver"; -import { BackupsService, backupsServiceInjectionKey } from "./service/BackupsService"; - -//TODO: docs -export class BackupsModuleRegistrar implements ModuleRegistrar { - register(builder: ModuleContextBuilder): void { - const evitaDBDriverResolver: EvitaDBDriverResolver = builder.inject(evitaDBDriverResolverInjectionKey) - const backupService: BackupsService = new BackupsService(evitaDBDriverResolver) - builder.provide(backupsServiceInjectionKey, backupService) - } - -} \ No newline at end of file diff --git a/src/modules/backups/components/BackupCatalog.vue b/src/modules/backups/components/BackupCatalog.vue deleted file mode 100644 index d87b2029..00000000 --- a/src/modules/backups/components/BackupCatalog.vue +++ /dev/null @@ -1,86 +0,0 @@ - - - - - diff --git a/src/modules/backups/components/Backups.vue b/src/modules/backups/components/Backups.vue deleted file mode 100644 index 5de59cbb..00000000 --- a/src/modules/backups/components/Backups.vue +++ /dev/null @@ -1,262 +0,0 @@ - - - - - diff --git a/src/modules/backups/components/RestoreCatalog.vue b/src/modules/backups/components/RestoreCatalog.vue deleted file mode 100644 index 7eea26ae..00000000 --- a/src/modules/backups/components/RestoreCatalog.vue +++ /dev/null @@ -1,62 +0,0 @@ - - - - - diff --git a/src/modules/backups/model/BackupsDefinition.ts b/src/modules/backups/model/BackupsDefinition.ts deleted file mode 100644 index f461b3c6..00000000 --- a/src/modules/backups/model/BackupsDefinition.ts +++ /dev/null @@ -1,17 +0,0 @@ -import { TabDefinition } from "@/modules/workspace/tab/model/TabDefinition"; -import { BackupTabParams } from "./BackupsTabParams"; -import { VoidTabData } from "@/modules/workspace/tab/model/void/VoidTabData"; -import { DefineComponent, markRaw } from "vue"; -import Backups from "../components/Backups.vue"; - -export class BackupsDefinition extends TabDefinition { - constructor(title: string, params: BackupTabParams) { - super(undefined, - title, - 'mdi-cloud-download-outline', - markRaw(Backups as DefineComponent), - params, - new VoidTabData() - ) - } -} diff --git a/src/modules/backups/service/BackupsService.ts b/src/modules/backups/service/BackupsService.ts deleted file mode 100644 index 4c9d648a..00000000 --- a/src/modules/backups/service/BackupsService.ts +++ /dev/null @@ -1,87 +0,0 @@ -import { EvitaDBDriverResolver } from '@/modules/connection/driver/EvitaDBDriverResolver' -import { Connection } from '@/modules/connection/model/Connection' -import { OffsetDateTime } from '@/modules/connection/model/data-type/OffsetDateTime' -import { Uuid } from '@/modules/connection/model/data-type/Uuid' -import { CatalogVersionAtResponse } from '@/modules/connection/model/data/CatalogVersionAtResponse' -import { FilesToFetch } from '@/modules/connection/model/data/FilesToFetch' -import { TaskStatus } from '@/modules/connection/model/data/TaskStatus' -import { mandatoryInject } from '@/utils/reactivity' -import { InjectionKey } from 'vue' -import { - GrpcRestoreCatalogRequest, - GrpcRestoreCatalogResponse -} from '@/modules/connection/driver/grpc/gen/GrpcEvitaManagementAPI_pb' - -export const backupsServiceInjectionKey: InjectionKey = - Symbol('backupsService') - -export class BackupsService { - private readonly evitaDBDriverResolver: EvitaDBDriverResolver - - constructor(evitaDBDriver: EvitaDBDriverResolver) { - this.evitaDBDriverResolver = evitaDBDriver - } - - async getMinimalBackupDate( - connection: Connection, - catalogName: string - ): Promise { - const driver = await this.evitaDBDriverResolver.resolveDriver( - connection - ) - return driver.getMinimalBackupDate(connection, catalogName) - } - - async backupCatalog( - connection: Connection, - catalogName: string, - includingWAL: boolean, - pastMoment: OffsetDateTime - ): Promise { - const driver = await this.evitaDBDriverResolver.resolveDriver( - connection - ) - return driver.createBackup( - connection, - catalogName, - includingWAL, - pastMoment - ) - } - - async getAllBackups( - connection: Connection, - pageNumber: number, - pageSize: number - ): Promise { - const driver = await this.evitaDBDriverResolver.resolveDriver( - connection - ) - return await driver.getBackups(connection, pageNumber, pageSize) - } - - async restoreCatalog( - connection: Connection, - catalogName: string, - fileId: Uuid - ) { - const driver = await this.evitaDBDriverResolver.resolveDriver( - connection - ) - return await driver.restoreCatalog(connection, catalogName, fileId) - } - - async downloadBackup(connection: Connection, fileId: Uuid){ - const driver = await this.evitaDBDriverResolver.resolveDriver(connection) - return await driver.downloadFile(connection, fileId) - } - - async uploadBackup(connection: Connection, stream: AsyncIterable):Promise{ - const driver = await this.evitaDBDriverResolver.resolveDriver(connection) - return await driver.uploadFile(connection, stream) - } -} - -export const useBackupsService = (): BackupsService => { - return mandatoryInject(backupsServiceInjectionKey) as BackupsService -} diff --git a/src/modules/backups/service/BackupsTabFactory.ts b/src/modules/backups/service/BackupsTabFactory.ts deleted file mode 100644 index d3e1f491..00000000 --- a/src/modules/backups/service/BackupsTabFactory.ts +++ /dev/null @@ -1,36 +0,0 @@ -import { Connection } from "@/modules/connection/model/Connection"; -import { ConnectionService } from "@/modules/connection/service/ConnectionService"; -import { mandatoryInject } from "@/utils/reactivity"; -import { InjectionKey } from "vue"; -import { BackupsDefinition } from "../model/BackupsDefinition"; -import { BackupTabParams } from "../model/BackupsTabParams"; -import { TabParamsDto } from "@/modules/workspace/tab/model/TabParamsDto"; -import { TabDataDto } from "@/modules/workspace/tab/model/TabDataDto"; -import { BackupsTabParamsDto } from "../model/BackupsTabParamsDto"; - -export const backupsTabFactoryInjectionKey: InjectionKey = Symbol('BackupsTabFactory') - -export class BackupsTabFactory { - private readonly connectionService: ConnectionService - - constructor(connectionService: ConnectionService){ - this.connectionService = connectionService - } - - createNew(connection: Connection, catalogName: string, executeOnOpen: boolean = false):BackupsDefinition { - return new BackupsDefinition('Backups', this.createTabParams(connection, catalogName, executeOnOpen)) - } - - private createTabParams(connection: Connection, catalogName: string, executeOnOpen: boolean = false):BackupTabParams { - return new BackupTabParams(connection, catalogName, executeOnOpen) - } - - restoreFromJson(paramsJson: TabParamsDto, dataJson?: TabDataDto): BackupsDefinition { - const params: BackupsTabParamsDto = paramsJson as BackupTabParams - return new BackupsDefinition('Backups', this.createTabParams(this.connectionService.getConnection(params.connection.id), params.catalogName)) - } -} - -export const useBackupsTabFactory = (): BackupsTabFactory => { - return mandatoryInject(backupsTabFactoryInjectionKey) as BackupsTabFactory -} \ No newline at end of file diff --git a/src/modules/base/component/VExecuteQueryButton.vue b/src/modules/base/component/VExecuteQueryButton.vue index b9069648..4dfd99e9 100644 --- a/src/modules/base/component/VExecuteQueryButton.vue +++ b/src/modules/base/component/VExecuteQueryButton.vue @@ -1,6 +1,7 @@ diff --git a/src/modules/base/component/VTabToolbar.vue b/src/modules/base/component/VTabToolbar.vue index 939be21e..ae625807 100644 --- a/src/modules/base/component/VTabToolbar.vue +++ b/src/modules/base/component/VTabToolbar.vue @@ -67,7 +67,7 @@ const normalizedFlags = computed>(() => { -