Files
api/api/src/unraid-api/graph/resolvers/docker/docker.mutations.resolver.ts
T
Pujit Mehrotra 277ac42046 feat: replace docker overview table with web component (7.3+) (#1764)
## Summary

Introduces a new Vue-based Docker container management interface
replacing the legacy webgui table.

### Container Management
- Start, stop, pause, resume, and remove containers via GraphQL
mutations
- Bulk actions for managing multiple containers at once
- Container update detection with one-click updates
- Real-time container statistics (CPU, memory, I/O)

### Organization & Navigation
- Folder-based container organization with drag-and-drop support
- Accessible reordering via keyboard controls
- Customizable column visibility with persistent preferences
- Column resizing and reordering
- Filtering and search across container properties

### Auto-start Configuration
- Dedicated autostart view with delay configuration
- Drag-and-drop reordering of start/stop sequences

### Logs & Console
- Integrated log viewer with filtering and download
- Persistent console sessions with shell selection
- Slideover panel for quick access

### Networking
- Port conflict detection and alerts
- Tailscale integration for container networking status
- LAN IP and port information display

### Additional Features
- Orphaned container detection and cleanup
- Template mapping management
- Critical notifications system
- WebUI visit links with Tailscale support

<sub>PR Summary by Claude Opus 4.5</sub>
2025-12-18 11:11:05 -05:00

122 lines
4.3 KiB
TypeScript

import { Args, ResolveField, Resolver } from '@nestjs/graphql';
import { AuthAction, Resource } from '@unraid/shared/graphql.model.js';
import { PrefixedID } from '@unraid/shared/prefixed-id-scalar.js';
import { UsePermissions } from '@unraid/shared/use-permissions.directive.js';
import { UseFeatureFlag } from '@app/unraid-api/decorators/use-feature-flag.decorator.js';
import {
DockerAutostartEntryInput,
DockerContainer,
} from '@app/unraid-api/graph/resolvers/docker/docker.model.js';
import { DockerService } from '@app/unraid-api/graph/resolvers/docker/docker.service.js';
import { DockerMutations } from '@app/unraid-api/graph/resolvers/mutation/mutation.model.js';
/**
* Nested Resolvers for Mutations MUST use @ResolveField() instead of @Mutation()
*/
@Resolver(() => DockerMutations)
export class DockerMutationsResolver {
constructor(private readonly dockerService: DockerService) {}
@ResolveField(() => DockerContainer, { description: 'Start a container' })
@UsePermissions({
action: AuthAction.UPDATE_ANY,
resource: Resource.DOCKER,
})
public async start(@Args('id', { type: () => PrefixedID }) id: string) {
return this.dockerService.start(id);
}
@ResolveField(() => DockerContainer, { description: 'Stop a container' })
@UsePermissions({
action: AuthAction.UPDATE_ANY,
resource: Resource.DOCKER,
})
public async stop(@Args('id', { type: () => PrefixedID }) id: string) {
return this.dockerService.stop(id);
}
@ResolveField(() => DockerContainer, { description: 'Pause (Suspend) a container' })
@UsePermissions({
action: AuthAction.UPDATE_ANY,
resource: Resource.DOCKER,
})
public async pause(@Args('id', { type: () => PrefixedID }) id: string) {
return this.dockerService.pause(id);
}
@ResolveField(() => DockerContainer, { description: 'Unpause (Resume) a container' })
@UsePermissions({
action: AuthAction.UPDATE_ANY,
resource: Resource.DOCKER,
})
public async unpause(@Args('id', { type: () => PrefixedID }) id: string) {
return this.dockerService.unpause(id);
}
@ResolveField(() => Boolean, { description: 'Remove a container' })
@UsePermissions({
action: AuthAction.DELETE_ANY,
resource: Resource.DOCKER,
})
public async removeContainer(
@Args('id', { type: () => PrefixedID }) id: string,
@Args('withImage', { type: () => Boolean, nullable: true }) withImage?: boolean
) {
return this.dockerService.removeContainer(id, { withImage });
}
@ResolveField(() => Boolean, {
description: 'Update auto-start configuration for Docker containers',
})
@UseFeatureFlag('ENABLE_NEXT_DOCKER_RELEASE')
@UsePermissions({
action: AuthAction.UPDATE_ANY,
resource: Resource.DOCKER,
})
public async updateAutostartConfiguration(
@Args('entries', { type: () => [DockerAutostartEntryInput] })
entries: DockerAutostartEntryInput[],
@Args('persistUserPreferences', { type: () => Boolean, nullable: true })
persistUserPreferences?: boolean
) {
await this.dockerService.updateAutostartConfiguration(entries, {
persistUserPreferences,
});
return true;
}
@ResolveField(() => DockerContainer, { description: 'Update a container to the latest image' })
@UsePermissions({
action: AuthAction.UPDATE_ANY,
resource: Resource.DOCKER,
})
public async updateContainer(@Args('id', { type: () => PrefixedID }) id: string) {
return this.dockerService.updateContainer(id);
}
@ResolveField(() => [DockerContainer], {
description: 'Update multiple containers to the latest images',
})
@UsePermissions({
action: AuthAction.UPDATE_ANY,
resource: Resource.DOCKER,
})
public async updateContainers(
@Args('ids', { type: () => [PrefixedID] })
ids: string[]
) {
return this.dockerService.updateContainers(ids);
}
@ResolveField(() => [DockerContainer], {
description: 'Update all containers that have available updates',
})
@UsePermissions({
action: AuthAction.UPDATE_ANY,
resource: Resource.DOCKER,
})
public async updateAllContainers() {
return this.dockerService.updateAllContainers();
}
}