Skip to content

Commit

Permalink
Merge pull request #242 from lukashornych/218-management-tooling---le…
Browse files Browse the repository at this point in the history
…t-users-close-all-sessions-to-a-server

feat(connection): allow closing open evitaDB sessions. Refs #218
  • Loading branch information
lukashornych authored Nov 26, 2024
2 parents fde68dc + 74c3cf4 commit 55201cb
Show file tree
Hide file tree
Showing 10 changed files with 167 additions and 58 deletions.
5 changes: 4 additions & 1 deletion src/modules/base/component/VTreeViewItem.vue
Original file line number Diff line number Diff line change
Expand Up @@ -24,10 +24,12 @@ const props = withDefaults(defineProps<Props>(), {
const actionsOpened = ref<boolean>(false)
const emit = defineEmits<{
(e: 'click:action', value: string): void
(e: 'click:action', value: string): void,
(e: 'click:actionMenu'): void
}>()
function openActions(): void {
emit('click:actionMenu')
if (props.actions && props.actions.length > 0) {
actionsOpened.value = true
}
Expand Down Expand Up @@ -103,6 +105,7 @@ function openActions(): void {
<VIcon
v-bind="props"
class="text-gray-light"
@click="emit('click:actionMenu')"
>
mdi-dots-vertical
</VIcon>
Expand Down
9 changes: 6 additions & 3 deletions src/modules/connection/driver/EvitaDBDriver.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,6 @@ import { ClassifierValidationErrorType } from '@/modules/connection/model/data-t
import { ClassifierType } from '@/modules/connection/model/data-type/ClassifierType'
import { OffsetDateTime } from '../model/data-type/OffsetDateTime'
import { Uuid } from '../model/data-type/Uuid'
import {
GrpcRestoreCatalogRequest, GrpcRestoreCatalogResponse
} from '@/modules/connection/driver/grpc/gen/GrpcEvitaManagementAPI_pb'
import { ServerStatus } from '@/modules/connection/model/status/ServerStatus'
import { CatalogVersionAtResponse } from '@/modules/connection/model/CatalogVersionAtResponse'
import { TaskStatus } from '@/modules/connection/model/task/TaskStatus'
Expand All @@ -29,6 +26,12 @@ export interface EvitaDBDriver {
*/
getSupportedVersions(): List<string>

/**
* Closes all open session to specified catalog. Any subsequent call to session
* will request new session.
*/
closeAllSessions(connection: Connection, catalogName?: string): void

/**
* Returns all available catalogs from server for the given evitaDB connection
*
Expand Down
4 changes: 4 additions & 0 deletions src/modules/connection/driver/grpc/EvitaDBDriverGrpc.ts
Original file line number Diff line number Diff line change
Expand Up @@ -245,6 +245,10 @@ export class EvitaDBDriverGrpc implements EvitaDBDriver {
return List(['all'])
}

closeAllSessions(connection: Connection, catalogName?: string): void {
this.evitaSessionProvider.closeAllSessions(connection, catalogName)
}

async getRuntimeConfiguration(connection: Connection): Promise<string> {
return (
await this.clientProvider
Expand Down
12 changes: 12 additions & 0 deletions src/modules/connection/driver/grpc/service/EvitaSessionProvider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,18 @@ export class EvitaSessionProvider {
this.clientProvider = clientProvider
}

closeAllSessions(connection: Connection, catalogName?: string): void {
if (catalogName != undefined) {
this.activeReadOnlySessions.get(connection.id)?.get(catalogName)?.invalidate()
this.activeReadWriteSessions.get(connection.id)?.get(catalogName)?.invalidate()
} else {
this.activeReadOnlySessions.get(connection.id)
?.forEach((session) => session.invalidate())
this.activeReadWriteSessions.get(connection.id)
?.forEach((session) => session.invalidate())
}
}

async executeInReadOnlySession<T>(connection: Connection,
catalog: Catalog,
sessionAction: (sessionId: string) => T,
Expand Down
54 changes: 45 additions & 9 deletions src/modules/connection/explorer/component/CatalogItem.vue
Original file line number Diff line number Diff line change
Expand Up @@ -48,11 +48,15 @@ import {
GraphQLConsoleTabDefinition
} from '@/modules/graphql-console/console/workspace/model/GraphQLConsoleTabDefinition'
import { SchemaViewerTabDefinition } from '@/modules/schema-viewer/viewer/workspace/model/SchemaViewerTabDefinition'
import { ConnectionService, useConnectionService } from '@/modules/connection/service/ConnectionService'
import { Toaster, useToaster } from '@/modules/notification/service/Toaster'
const workspaceService: WorkspaceService = useWorkspaceService()
const connectionService: ConnectionService = useConnectionService()
const evitaQLConsoleTabFactory: EvitaQLConsoleTabFactory = useEvitaQLConsoleTabFactory()
const graphQLConsoleTabFactory: GraphQLConsoleTabFactory = useGraphQLConsoleTabFactory()
const schemaViewerTabFactory: SchemaViewerTabFactory = useSchemaViewerTabFactory()
const toaster: Toaster = useToaster()
const { t } = useI18n()
const props = defineProps<{
Expand Down Expand Up @@ -82,16 +86,35 @@ const actions = computed<Map<CatalogItemType, MenuItem<CatalogItemType>>>(() =>
const actionList = computed<MenuItem<CatalogItemType>[]>(() => Array.from(actions.value.values()))
const entityCollections = computed<Immutable.List<EntityCollection>>(() => {
return props.catalog.entityCollections.sort((a: EntityCollection, b: EntityCollection) => {
return a.entityType.localeCompare(b.entityType)
})
return Immutable.List<EntityCollection>(props.catalog.entityCollections)
.sort((a: EntityCollection, b: EntityCollection) => {
return a.entityType.localeCompare(b.entityType)
})
})
const catalogRef = ref(props.catalog)
provideCatalog(catalogRef as Ref<Catalog>)
const loading = ref<boolean>(false)
async function closeAllSessions(): Promise<void> {
try {
await connectionService.closeAllSessions(connection, props.catalog.name)
toaster.success(t(
'explorer.catalog.notification.closedAllSessions',
{ catalogName: props.catalog.name }
))
} catch (e: any) {
toaster.error(t(
'explorer.catalog.notification.couldNotCloseSessions',
{
catalogName: props.catalog.name,
reason: e.message
}
))
}
}
function handleAction(action: string): void {
const foundedAction = actions.value?.get(action as CatalogItemType)
if (foundedAction && foundedAction instanceof MenuAction) {
Expand All @@ -106,9 +129,9 @@ function createActions(): Map<CatalogItemType, MenuItem<CatalogItemType>> {
const actions: Map<CatalogItemType, MenuItem<CatalogItemType>> = new Map()
actions.set(
CatalogItemType.OpenEvitaQLConsole,
CatalogItemType.EvitaQLConsole,
createMenuAction(
CatalogItemType.OpenEvitaQLConsole,
CatalogItemType.EvitaQLConsole,
EvitaQLConsoleTabDefinition.icon(),
() => {
workspaceService.createTab(
Expand All @@ -122,9 +145,9 @@ function createActions(): Map<CatalogItemType, MenuItem<CatalogItemType>> {
)
)
actions.set(
CatalogItemType.OpenGraphQLDataAPIConsole,
CatalogItemType.GraphQLDataAPIConsole,
createMenuAction(
CatalogItemType.OpenGraphQLDataAPIConsole,
CatalogItemType.GraphQLDataAPIConsole,
GraphQLConsoleTabDefinition.icon(),
() => {
workspaceService.createTab(
Expand All @@ -139,9 +162,9 @@ function createActions(): Map<CatalogItemType, MenuItem<CatalogItemType>> {
)
)
actions.set(
CatalogItemType.OpenGraphQLSchemaAPIConsole,
CatalogItemType.GraphQLSchemaAPIConsole,
createMenuAction(
CatalogItemType.OpenGraphQLSchemaAPIConsole,
CatalogItemType.GraphQLSchemaAPIConsole,
GraphQLConsoleTabDefinition.icon(),
() => {
workspaceService.createTab(
Expand Down Expand Up @@ -172,6 +195,19 @@ function createActions(): Map<CatalogItemType, MenuItem<CatalogItemType>> {
)
)
actions.set(
CatalogItemType.ManageSubheader,
new MenuSubheader(t('explorer.catalog.subheader.manage'))
)
actions.set(
CatalogItemType.CloseAllSessions,
createMenuAction(
CatalogItemType.CloseAllSessions,
'mdi-lan-disconnect',
() => closeAllSessions()
)
)
actions.set(
CatalogItemType.ModifySubheader,
new MenuSubheader(t('explorer.catalog.subheader.modify'))
Expand Down
82 changes: 57 additions & 25 deletions src/modules/connection/explorer/component/ConnectionItem.vue
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,6 @@ import { ItemFlag } from '@/modules/base/model/tree-view/ItemFlag'
import Immutable from 'immutable'
import { ServerStatus } from '@/modules/connection/model/status/ServerStatus'
import { ApiType } from '@/modules/connection/model/status/ApiType'
import { CatalogItemType } from '@/modules/connection/explorer/model/CatalogItemType'
import { BackupViewerTabFactory, useBackupsTabFactory } from '@/modules/backup-viewer/service/BackupViewerTabFactory'
import {
GraphQLConsoleTabDefinition
Expand Down Expand Up @@ -160,6 +159,24 @@ async function loadCatalogs(): Promise<boolean> {
}
}
async function closeAllSessions(): Promise<void> {
try {
await connectionService.closeAllSessions(props.connection)
toaster.success(t(
'explorer.connection.notification.closedAllSessions',
{ connectionName: props.connection.name }
))
} catch (e: any) {
toaster.error(t(
'explorer.connection.notification.couldNotCloseSessions',
{
connectionName: props.connection.name,
reason: e.message
}
))
}
}
function handleAction(action: string): void {
if (actions.value == undefined) {
return
Expand All @@ -180,30 +197,6 @@ async function createActions(): Promise<Map<ConnectionItemType, MenuItem<Connect
const serverWritable: boolean = serverReady && !serverStatus.value!.readOnly
const actions: Map<ConnectionItemType, MenuItem<ConnectionItemType>> = new Map()
actions.set(
ConnectionItemType.Refresh,
createMenuAction(
ConnectionItemType.Refresh,
'mdi-refresh',
async () => await reload()
)
)
actions.set(
ConnectionItemType.OpenGraphQLSystemAPIConsole,
createMenuAction(
ConnectionItemType.OpenGraphQLSystemAPIConsole,
GraphQLConsoleTabDefinition.icon(),
() =>
workspaceService.createTab(
graphQLConsoleTabFactory.createNew(
props.connection,
'system', // todo lho: this is not needed
GraphQLInstanceType.System
)
),
graphQlEnabled
)
)
actions.set(
ConnectionItemType.Server,
createMenuAction(
Expand Down Expand Up @@ -246,6 +239,44 @@ async function createActions(): Promise<Map<ConnectionItemType, MenuItem<Connect
serverWritable && observabilityEnabled
)
)
actions.set(
ConnectionItemType.GraphQLSystemAPIConsole,
createMenuAction(
ConnectionItemType.GraphQLSystemAPIConsole,
GraphQLConsoleTabDefinition.icon(),
() =>
workspaceService.createTab(
graphQLConsoleTabFactory.createNew(
props.connection,
'system', // todo lho: this is not needed
GraphQLInstanceType.System
)
),
graphQlEnabled
)
)
actions.set(
ConnectionItemType.ManageSubheader,
new MenuSubheader(t('explorer.connection.subheader.manage'))
)
actions.set(
ConnectionItemType.Refresh,
createMenuAction(
ConnectionItemType.Refresh,
'mdi-refresh',
async () => await reload()
)
)
actions.set(
ConnectionItemType.CloseAllSessions,
createMenuAction(
ConnectionItemType.CloseAllSessions,
'mdi-lan-disconnect',
() => closeAllSessions(),
serverReady
)
)
actions.set(
ConnectionItemType.ModifySubheader,
Expand Down Expand Up @@ -330,6 +361,7 @@ function createMenuAction(
:flags="flags"
:actions="actionList"
@click="load()"
@click:action-menu="load()"
@click:action="handleAction"
>
{{ connection.name }}
Expand Down
17 changes: 10 additions & 7 deletions src/modules/connection/explorer/model/CatalogItemType.ts
Original file line number Diff line number Diff line change
@@ -1,16 +1,19 @@
// todo docs
export enum CatalogItemType {
OpenEvitaQLConsole = 'openEvitaQLConsole',
OpenGraphQLDataAPIConsole = 'openGraphQLDataApiConsole',
OpenGraphQLSchemaAPIConsole = 'openGraphQLSchemaApiConsole',
EvitaQLConsole = 'evitaQLConsole',
GraphQLDataAPIConsole = 'graphQLDataApiConsole',
GraphQLSchemaAPIConsole = 'graphQLSchemaApiConsole',
ViewSchema = 'viewSchema',

ManageSubheader = 'manageSubheader',
CloseAllSessions = 'closeAllSessions',

ModifySubheader = 'modifySubheader',
DropCatalog = 'dropCatalog',
RenameCatalog = 'renameCatalog',
ReplaceCatalog = 'replaceCatalog',
SwitchCatalogToAliveState = 'switchCatalogToAliveState',
ModifySubheader = 'modifySubheader',

CollectionsSubheader = 'collectionsSubheader',
JobsSubheader = 'jobsSubheader',
CreateCollection = 'createCollection',
Jobs = 'jobs'
CreateCollection = 'createCollection'
}
15 changes: 10 additions & 5 deletions src/modules/connection/explorer/model/ConnectionItemType.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,18 @@
// todo docs
export enum ConnectionItemType {
Refresh = 'refresh',
OpenGraphQLSystemAPIConsole = 'openGraphQLSystemApiConsole',
Edit = 'edit',
Remove = 'remove',
GraphQLSystemAPIConsole = 'graphQLSystemApiConsole',
JfrRecordings = 'jfrRecordings',
Server = 'server',
Tasks = 'tasks',
JfrRecordings = 'jfrRecordings',

ManageSubheader = 'manageSubheader',
Refresh = 'refresh',
CloseAllSessions = 'closeAllSessions',

ModifySubheader = 'modifySubheader',
Edit = 'edit',
Remove = 'remove',

CatalogsSubheader = 'catalogsSubheader',
CreateCatalog = 'createCatalog',
CatalogBackups = 'catalogBackups'
Expand Down
4 changes: 4 additions & 0 deletions src/modules/connection/service/ConnectionService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -158,6 +158,10 @@ export class ConnectionService {
return serverStatus
}

async closeAllSessions(connection: Connection, catalogName?: string): Promise<void> {
(await this.getDriver(connection)).closeAllSessions(connection, catalogName)
}

/**
* Returns cached catalog. If not present, it tries to fetch current catalog.
*/
Expand Down
Loading

0 comments on commit 55201cb

Please sign in to comment.