feat: backups page cleanup before worlds (#5844)
* feat: card alignment + fix modals * feat: change admon title in restore alert modal * fix: lint * feat: backups queue api into api-client * feat: impl backup queue api endpoints into frontend * feat: ack fix * feat: bulk actions * feat: bulk delete impl * fix: lint * fix: align error states * fix: transition group * feat: ready for qa * fix: lint * feat: qa * feat: stacked admonitions component * fix: issues with stacking * feat: hook up admonition stacking + fix app csp for staging kyros nodes * fix: logs.vue * qa: close stack on admonitions click * fix: all problems with stacked admonitions * qa: admonition cleanup and copy overhaul draft * fix: qa issues padding * fix: padding bug * feat: qa * fix: intercom in app csp bug * fix: positioning intercom * feat: loading overlay on top of console + admon consistency changes * feat: scroll indicator fade in backup delete modal + admon timestamp fix * feat: move action bar behind modal * fix: lint + i18n * fix: server ping spam on filter (cache but clear on unmount) * fix: 1 admon fade in flicker issue * chore: temp staging undo * qa: changes * fix: lint * chore: revert staging to use staging * fix: scoping
This commit is contained in:
1
packages/api-client/AGENTS.md
Symbolic link
1
packages/api-client/AGENTS.md
Symbolic link
@@ -0,0 +1 @@
|
||||
CLAUDE.md
|
||||
@@ -37,7 +37,7 @@ client.labrinth.collections
|
||||
client.labrinth.billing_internal
|
||||
client.archon.servers_v0
|
||||
client.archon.servers_v1
|
||||
client.archon.backups_v0
|
||||
client.archon.backups_queue_v1
|
||||
client.archon.backups_v1
|
||||
client.archon.content_v0
|
||||
client.kyros.files_v0
|
||||
|
||||
@@ -9,6 +9,11 @@ import { AbstractUploadClient } from './abstract-upload-client'
|
||||
import type { AbstractWebSocketClient } from './abstract-websocket'
|
||||
import { ModrinthApiError, ModrinthServerError } from './errors'
|
||||
|
||||
type ArchonClientModules = Omit<InferredClientModules['archon'], 'backups_v1'> & {
|
||||
/** @deprecated Use `backups_queue_v1` for the Backups Queue API. */
|
||||
backups_v1: InferredClientModules['archon']['backups_v1']
|
||||
}
|
||||
|
||||
/**
|
||||
* Abstract base client for Modrinth APIs
|
||||
*/
|
||||
@@ -27,7 +32,7 @@ export abstract class AbstractModrinthClient extends AbstractUploadClient {
|
||||
private _moduleNamespaces: Map<string, Record<string, AbstractModule>> = new Map()
|
||||
|
||||
public readonly labrinth!: InferredClientModules['labrinth']
|
||||
public readonly archon!: InferredClientModules['archon'] & { sockets: AbstractWebSocketClient }
|
||||
public readonly archon!: ArchonClientModules & { sockets: AbstractWebSocketClient }
|
||||
public readonly kyros!: InferredClientModules['kyros']
|
||||
public readonly iso3166!: InferredClientModules['iso3166']
|
||||
public readonly mclogs!: InferredClientModules['mclogs']
|
||||
|
||||
93
packages/api-client/src/modules/archon/backups-queue/v1.ts
Normal file
93
packages/api-client/src/modules/archon/backups-queue/v1.ts
Normal file
@@ -0,0 +1,93 @@
|
||||
import { AbstractModule } from '../../../core/abstract-module'
|
||||
import type { Archon } from '../types'
|
||||
|
||||
export class ArchonBackupsQueueV1Module extends AbstractModule {
|
||||
public getModuleID(): string {
|
||||
return 'archon_backups_queue_v1'
|
||||
}
|
||||
|
||||
/** GET /v1/servers/:server_id/worlds/:world_id/backups-queue */
|
||||
public async list(
|
||||
serverId: string,
|
||||
worldId: string,
|
||||
): Promise<Archon.BackupsQueue.v1.BackupsQueueResponse> {
|
||||
return this.client.request<Archon.BackupsQueue.v1.BackupsQueueResponse>(
|
||||
`/servers/${serverId}/worlds/${worldId}/backups-queue`,
|
||||
{ api: 'archon', version: 1, method: 'GET' },
|
||||
)
|
||||
}
|
||||
|
||||
/** POST /v1/servers/:server_id/worlds/:world_id/backups-queue */
|
||||
public async create(
|
||||
serverId: string,
|
||||
worldId: string,
|
||||
request: Archon.BackupsQueue.v1.BackupRequest,
|
||||
): Promise<Archon.BackupsQueue.v1.PostBackupQueueResponse> {
|
||||
return this.client.request<Archon.BackupsQueue.v1.PostBackupQueueResponse>(
|
||||
`/servers/${serverId}/worlds/${worldId}/backups-queue`,
|
||||
{ api: 'archon', version: 1, method: 'POST', body: request },
|
||||
)
|
||||
}
|
||||
|
||||
/** POST /v1/servers/:server_id/worlds/:world_id/backups-queue/history/create/:operation_id/ack */
|
||||
public async ackCreate(serverId: string, worldId: string, operationId: number): Promise<void> {
|
||||
await this.client.request<void>(
|
||||
`/servers/${serverId}/worlds/${worldId}/backups-queue/history/create/${operationId}/ack`,
|
||||
{ api: 'archon', version: 1, method: 'POST' },
|
||||
)
|
||||
}
|
||||
|
||||
/** POST /v1/servers/:server_id/worlds/:world_id/backups-queue/history/restore/:operation_id/ack */
|
||||
public async ackRestore(serverId: string, worldId: string, operationId: number): Promise<void> {
|
||||
await this.client.request<void>(
|
||||
`/servers/${serverId}/worlds/${worldId}/backups-queue/history/restore/${operationId}/ack`,
|
||||
{ api: 'archon', version: 1, method: 'POST' },
|
||||
)
|
||||
}
|
||||
|
||||
/** DELETE /v1/servers/:server_id/worlds/:world_id/backups-queue/:backup_id */
|
||||
public async delete(serverId: string, worldId: string, backupId: string): Promise<void> {
|
||||
await this.client.request<void>(
|
||||
`/servers/${serverId}/worlds/${worldId}/backups-queue/${backupId}`,
|
||||
{
|
||||
api: 'archon',
|
||||
version: 1,
|
||||
method: 'DELETE',
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
/** POST /v1/servers/:server_id/worlds/:world_id/backups-queue/delete-many */
|
||||
public async deleteMany(serverId: string, worldId: string, backupIds: string[]): Promise<void> {
|
||||
await this.client.request<void>(
|
||||
`/servers/${serverId}/worlds/${worldId}/backups-queue/delete-many`,
|
||||
{
|
||||
api: 'archon',
|
||||
version: 1,
|
||||
method: 'POST',
|
||||
body: { backup_ids: backupIds } satisfies Archon.BackupsQueue.v1.DeleteManyBackupRequest,
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
/** POST /v1/servers/:server_id/worlds/:world_id/backups-queue/:backup_id/restore */
|
||||
public async restore(
|
||||
serverId: string,
|
||||
worldId: string,
|
||||
backupId: string,
|
||||
request: Archon.BackupsQueue.v1.BackupRequest,
|
||||
): Promise<void> {
|
||||
await this.client.request<void>(
|
||||
`/servers/${serverId}/worlds/${worldId}/backups-queue/${backupId}/restore`,
|
||||
{ api: 'archon', version: 1, method: 'POST', body: request },
|
||||
)
|
||||
}
|
||||
|
||||
/** POST /v1/servers/:server_id/worlds/:world_id/backups-queue/:backup_id/retry */
|
||||
public async retry(serverId: string, worldId: string, backupId: string): Promise<void> {
|
||||
await this.client.request<void>(
|
||||
`/servers/${serverId}/worlds/${worldId}/backups-queue/${backupId}/retry`,
|
||||
{ api: 'archon', version: 1, method: 'POST' },
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -1,11 +1,17 @@
|
||||
import { AbstractModule } from '../../../core/abstract-module'
|
||||
import type { Archon } from '../types'
|
||||
|
||||
/**
|
||||
* @deprecated Use `client.archon.backups_queue_v1` (Backups Queue API) instead.
|
||||
*/
|
||||
export class ArchonBackupsV1Module extends AbstractModule {
|
||||
public getModuleID(): string {
|
||||
return 'archon_backups_v1'
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated Use `client.archon.backups_queue_v1.list` instead.
|
||||
*/
|
||||
/** GET /v1/servers/:server_id/worlds/:world_id/backups */
|
||||
public async list(serverId: string, worldId: string): Promise<Archon.Backups.v1.Backup[]> {
|
||||
return this.client.request<Archon.Backups.v1.Backup[]>(
|
||||
@@ -14,6 +20,9 @@ export class ArchonBackupsV1Module extends AbstractModule {
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated Use `client.archon.backups_queue_v1.list` instead.
|
||||
*/
|
||||
/** GET /v1/servers/:server_id/worlds/:world_id/backups/:backup_id */
|
||||
public async get(
|
||||
serverId: string,
|
||||
@@ -26,6 +35,9 @@ export class ArchonBackupsV1Module extends AbstractModule {
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated Use `client.archon.backups_queue_v1.create` instead.
|
||||
*/
|
||||
/** POST /v1/servers/:server_id/worlds/:world_id/backups */
|
||||
public async create(
|
||||
serverId: string,
|
||||
@@ -38,6 +50,9 @@ export class ArchonBackupsV1Module extends AbstractModule {
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated Use `client.archon.backups_queue_v1.restore` instead.
|
||||
*/
|
||||
/** POST /v1/servers/:server_id/worlds/:world_id/backups/:backup_id/restore */
|
||||
public async restore(serverId: string, worldId: string, backupId: string): Promise<void> {
|
||||
await this.client.request<void>(
|
||||
@@ -50,6 +65,9 @@ export class ArchonBackupsV1Module extends AbstractModule {
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated Use `client.archon.backups_queue_v1.delete` instead.
|
||||
*/
|
||||
/** DELETE /v1/servers/:server_id/worlds/:world_id/backups/:backup_id */
|
||||
public async delete(serverId: string, worldId: string, backupId: string): Promise<void> {
|
||||
await this.client.request<void>(`/servers/${serverId}/worlds/${worldId}/backups/${backupId}`, {
|
||||
@@ -59,6 +77,9 @@ export class ArchonBackupsV1Module extends AbstractModule {
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated Use `client.archon.backups_queue_v1.retry` instead.
|
||||
*/
|
||||
/** POST /v1/servers/:server_id/worlds/:world_id/backups/:backup_id/retry */
|
||||
public async retry(serverId: string, worldId: string, backupId: string): Promise<void> {
|
||||
await this.client.request<void>(
|
||||
@@ -71,6 +92,9 @@ export class ArchonBackupsV1Module extends AbstractModule {
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated Legacy backups only; no queue equivalent. Prefer renaming via other supported flows if available.
|
||||
*/
|
||||
/** PATCH /v1/servers/:server_id/worlds/:world_id/backups/:backup_id */
|
||||
public async rename(
|
||||
serverId: string,
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
export * from './backups/v1'
|
||||
export * from './backups-queue/v1'
|
||||
export * from './content/v1'
|
||||
export * from './properties/v1'
|
||||
export * from './servers/v0'
|
||||
|
||||
@@ -404,6 +404,9 @@ export namespace Archon {
|
||||
name: string
|
||||
created_at: string
|
||||
is_active: boolean
|
||||
/**
|
||||
* @deprecated Prefer `client.archon.backups_queue_v1.list()` for queue-aware backup state.
|
||||
*/
|
||||
backups: Archon.Backups.v1.Backup[]
|
||||
content: WorldContentInfo | null
|
||||
readiness: WorldReadiness
|
||||
@@ -434,16 +437,24 @@ export namespace Archon {
|
||||
}
|
||||
|
||||
export namespace Backups {
|
||||
/**
|
||||
* @deprecated Use {@link Archon.BackupsQueue.v1} and `client.archon.backups_queue_v1` instead.
|
||||
*/
|
||||
export namespace v1 {
|
||||
/** @deprecated Use {@link Archon.BackupsQueue.v1} instead. */
|
||||
export type BackupState = 'ongoing' | 'done' | 'failed' | 'cancelled' | 'unchanged'
|
||||
/** @deprecated Use {@link Archon.BackupsQueue.v1} instead. */
|
||||
export type BackupTask = 'file' | 'create' | 'restore'
|
||||
/** @deprecated Use {@link Archon.BackupsQueue.v1} instead. */
|
||||
export type BackupStatus = 'pending' | 'in_progress' | 'timed_out' | 'error' | 'done'
|
||||
|
||||
/** @deprecated Use {@link Archon.BackupsQueue.v1} instead. */
|
||||
export type BackupTaskProgress = {
|
||||
progress: number // 0.0 to 1.0
|
||||
state: BackupState
|
||||
}
|
||||
|
||||
/** @deprecated Use {@link Archon.BackupsQueue.v1.BackupQueueBackup} instead. */
|
||||
export type Backup = {
|
||||
id: string
|
||||
physical_id: string
|
||||
@@ -461,20 +472,87 @@ export namespace Archon {
|
||||
}
|
||||
}
|
||||
|
||||
/** @deprecated Use {@link Archon.BackupsQueue.v1.BackupRequest} instead. */
|
||||
export type BackupRequest = {
|
||||
name: string
|
||||
}
|
||||
|
||||
/** @deprecated Use {@link Archon.BackupsQueue.v1} instead. */
|
||||
export type PatchBackup = {
|
||||
name?: string
|
||||
}
|
||||
|
||||
/** @deprecated Use {@link Archon.BackupsQueue.v1.PostBackupQueueResponse} instead. */
|
||||
export type PostBackupResponse = {
|
||||
id: string
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export namespace BackupsQueue {
|
||||
export namespace v1 {
|
||||
export type BackupQueueOperationType = 'create' | 'restore'
|
||||
|
||||
export type BackupQueueState =
|
||||
| 'pending'
|
||||
| 'ongoing'
|
||||
| 'completed'
|
||||
| 'cancelled'
|
||||
| 'failed'
|
||||
| 'timed_out'
|
||||
|
||||
export type BackupStatus = 'pending' | 'in_progress' | 'timed_out' | 'error' | 'done'
|
||||
|
||||
export type BackupRequest = {
|
||||
name: string
|
||||
}
|
||||
|
||||
export type PostBackupQueueResponse = {
|
||||
id: string
|
||||
}
|
||||
|
||||
export type DeleteManyBackupRequest = {
|
||||
backup_ids: string[]
|
||||
}
|
||||
|
||||
export type ActiveOperation = {
|
||||
backup_id: string
|
||||
operation_type: BackupQueueOperationType
|
||||
operation_id?: number | null
|
||||
has_parent: boolean
|
||||
scheduled_for: string
|
||||
synthetic_legacy: boolean
|
||||
}
|
||||
|
||||
export type BackupQueueOperation = {
|
||||
operation_type: BackupQueueOperationType
|
||||
operation_id?: number | null
|
||||
state: BackupQueueState
|
||||
scheduled_for: string
|
||||
completed_at?: string | null
|
||||
has_parent: boolean
|
||||
error?: string | null
|
||||
should_prompt: boolean
|
||||
synthetic_legacy: boolean
|
||||
}
|
||||
|
||||
export type BackupQueueBackup = {
|
||||
id: string
|
||||
name: string
|
||||
created_at: string
|
||||
status: BackupStatus
|
||||
locked: boolean
|
||||
automated: boolean
|
||||
history: BackupQueueOperation[]
|
||||
}
|
||||
|
||||
export type BackupsQueueResponse = {
|
||||
active_operations: ActiveOperation[]
|
||||
backups: BackupQueueBackup[]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export namespace Websocket {
|
||||
export namespace v0 {
|
||||
export type WSAuth = {
|
||||
@@ -482,7 +560,14 @@ export namespace Archon {
|
||||
token: string
|
||||
}
|
||||
|
||||
export type BackupState = 'ongoing' | 'done' | 'failed' | 'cancelled' | 'unchanged'
|
||||
export type BackupState =
|
||||
| 'pending'
|
||||
| 'ongoing'
|
||||
| 'done'
|
||||
| 'failed'
|
||||
| 'cancelled'
|
||||
| 'unchanged'
|
||||
| 'damaged'
|
||||
export type BackupTask = 'file' | 'create' | 'restore'
|
||||
|
||||
export type WSBackupProgressEvent = {
|
||||
@@ -491,6 +576,8 @@ export namespace Archon {
|
||||
task: BackupTask
|
||||
state: BackupState
|
||||
progress: number
|
||||
start_time?: number | null
|
||||
finish_time?: number | null
|
||||
}
|
||||
|
||||
export type WSLogEvent = {
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import type { AbstractModrinthClient } from '../core/abstract-client'
|
||||
import type { AbstractModule } from '../core/abstract-module'
|
||||
import { ArchonBackupsV1Module } from './archon/backups/v1'
|
||||
import { ArchonBackupsQueueV1Module } from './archon/backups-queue/v1'
|
||||
import { ArchonContentV1Module } from './archon/content/v1'
|
||||
import { ArchonOptionsV1Module } from './archon/options/v1'
|
||||
import { ArchonPropertiesV1Module } from './archon/properties/v1'
|
||||
@@ -55,6 +56,7 @@ type ModuleConstructor = new (client: AbstractModrinthClient) => AbstractModule
|
||||
* TODO: Better way? Probably not
|
||||
*/
|
||||
export const MODULE_REGISTRY = {
|
||||
archon_backups_queue_v1: ArchonBackupsQueueV1Module,
|
||||
archon_backups_v1: ArchonBackupsV1Module,
|
||||
archon_content_v1: ArchonContentV1Module,
|
||||
archon_options_v1: ArchonOptionsV1Module,
|
||||
|
||||
Reference in New Issue
Block a user