mirror of
https://github.com/unraid/api.git
synced 2026-01-02 22:50:02 -06:00
feat: container stats
This commit is contained in:
@@ -1213,6 +1213,25 @@ type DockerContainerLogs {
|
||||
cursor: DateTime
|
||||
}
|
||||
|
||||
type DockerContainerStats {
|
||||
id: PrefixedID!
|
||||
|
||||
"""CPU Usage Percentage"""
|
||||
cpuPercent: Float!
|
||||
|
||||
"""Memory Usage String (e.g. 100MB / 1GB)"""
|
||||
memUsage: String!
|
||||
|
||||
"""Memory Usage Percentage"""
|
||||
memPercent: Float!
|
||||
|
||||
"""Network I/O String (e.g. 100MB / 1GB)"""
|
||||
netIO: String!
|
||||
|
||||
"""Block I/O String (e.g. 100MB / 1GB)"""
|
||||
blockIO: String!
|
||||
}
|
||||
|
||||
type Docker implements Node {
|
||||
id: PrefixedID!
|
||||
containers(skipCache: Boolean! = false): [DockerContainer!]!
|
||||
@@ -2772,6 +2791,7 @@ type Subscription {
|
||||
serversSubscription: Server!
|
||||
parityHistorySubscription: ParityCheck!
|
||||
arraySubscription: UnraidArray!
|
||||
dockerContainerStats: DockerContainerStats!
|
||||
logFile(path: String!): LogFileContent!
|
||||
systemMetricsCpu: CpuUtilization!
|
||||
systemMetricsCpuTelemetry: CpuPackages!
|
||||
|
||||
@@ -0,0 +1,117 @@
|
||||
import { Injectable, Logger, OnModuleDestroy } from '@nestjs/common';
|
||||
import { createInterface } from 'readline';
|
||||
|
||||
import { execa } from 'execa';
|
||||
|
||||
import { pubsub, PUBSUB_CHANNEL } from '@app/core/pubsub.js';
|
||||
import { catchHandlers } from '@app/core/utils/misc/catch-handlers.js';
|
||||
import { DockerContainerStats } from '@app/unraid-api/graph/resolvers/docker/docker.model.js';
|
||||
|
||||
@Injectable()
|
||||
export class DockerStatsService implements OnModuleDestroy {
|
||||
private readonly logger = new Logger(DockerStatsService.name);
|
||||
private statsProcess: ReturnType<typeof execa> | null = null;
|
||||
private readonly STATS_FORMAT =
|
||||
'{{.ID}};{{.CPUPerc}};{{.MemUsage}};{{.MemPerc}};{{.NetIO}};{{.BlockIO}}';
|
||||
|
||||
onModuleDestroy() {
|
||||
this.stopStatsStream();
|
||||
}
|
||||
|
||||
public startStatsStream() {
|
||||
if (this.statsProcess) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.logger.log('Starting docker stats stream');
|
||||
|
||||
try {
|
||||
this.statsProcess = execa('docker', ['stats', '--format', this.STATS_FORMAT, '--no-trunc'], {
|
||||
all: true,
|
||||
reject: false, // Don't throw on exit code != 0, handle via parsing/events
|
||||
});
|
||||
|
||||
if (this.statsProcess.stdout) {
|
||||
const rl = createInterface({
|
||||
input: this.statsProcess.stdout,
|
||||
crlfDelay: Infinity,
|
||||
});
|
||||
|
||||
rl.on('line', (line) => {
|
||||
if (!line.trim()) return;
|
||||
this.processStatsLine(line);
|
||||
});
|
||||
|
||||
rl.on('error', (err) => {
|
||||
this.logger.error('Error reading docker stats stream', err);
|
||||
});
|
||||
}
|
||||
|
||||
if (this.statsProcess.stderr) {
|
||||
this.statsProcess.stderr.on('data', (data: Buffer) => {
|
||||
// Log docker stats errors but don't crash
|
||||
this.logger.debug(`Docker stats stderr: ${data.toString()}`);
|
||||
});
|
||||
}
|
||||
|
||||
// Handle process exit
|
||||
this.statsProcess
|
||||
.then((result) => {
|
||||
if (result.failed && !result.signal) {
|
||||
this.logger.error('Docker stats process exited with error', result.shortMessage);
|
||||
this.stopStatsStream();
|
||||
}
|
||||
})
|
||||
.catch((err) => {
|
||||
if (!err.killed) {
|
||||
this.logger.error('Docker stats process ended unexpectedly', err);
|
||||
this.stopStatsStream();
|
||||
}
|
||||
});
|
||||
} catch (error) {
|
||||
this.logger.error('Failed to start docker stats', error);
|
||||
catchHandlers.docker(error as Error);
|
||||
}
|
||||
}
|
||||
|
||||
public stopStatsStream() {
|
||||
if (this.statsProcess) {
|
||||
this.logger.log('Stopping docker stats stream');
|
||||
this.statsProcess.kill();
|
||||
this.statsProcess = null;
|
||||
}
|
||||
}
|
||||
|
||||
private processStatsLine(line: string) {
|
||||
try {
|
||||
// format: ID;CPUPerc;MemUsage;MemPerc;NetIO;BlockIO
|
||||
// Example: 123abcde;0.00%;10MiB / 100MiB;10.00%;1kB / 2kB;0B / 0B
|
||||
|
||||
// Remove ANSI escape codes if any (docker stats sometimes includes them)
|
||||
// eslint-disable-next-line no-control-regex
|
||||
const cleanLine = line.replace(/\x1B\[[0-9;]*[mK]/g, '');
|
||||
|
||||
const parts = cleanLine.split(';');
|
||||
if (parts.length < 6) return;
|
||||
|
||||
const [id, cpuPercStr, memUsage, memPercStr, netIO, blockIO] = parts;
|
||||
|
||||
const stats: DockerContainerStats = {
|
||||
id,
|
||||
cpuPercent: this.parsePercentage(cpuPercStr),
|
||||
memUsage,
|
||||
memPercent: this.parsePercentage(memPercStr),
|
||||
netIO,
|
||||
blockIO,
|
||||
};
|
||||
|
||||
pubsub.publish(PUBSUB_CHANNEL.DOCKER_STATS, { dockerContainerStats: stats });
|
||||
} catch (error) {
|
||||
this.logger.debug(`Failed to process stats line: ${line}`, error);
|
||||
}
|
||||
}
|
||||
|
||||
private parsePercentage(value: string): number {
|
||||
return parseFloat(value.replace('%', '')) || 0;
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
import {
|
||||
Field,
|
||||
Float,
|
||||
GraphQLISODateTime,
|
||||
ID,
|
||||
InputType,
|
||||
@@ -272,6 +273,27 @@ export class DockerContainerLogs {
|
||||
cursor?: Date | null;
|
||||
}
|
||||
|
||||
@ObjectType()
|
||||
export class DockerContainerStats {
|
||||
@Field(() => PrefixedID)
|
||||
id!: string;
|
||||
|
||||
@Field(() => Float, { description: 'CPU Usage Percentage' })
|
||||
cpuPercent!: number;
|
||||
|
||||
@Field(() => String, { description: 'Memory Usage String (e.g. 100MB / 1GB)' })
|
||||
memUsage!: string;
|
||||
|
||||
@Field(() => Float, { description: 'Memory Usage Percentage' })
|
||||
memPercent!: number;
|
||||
|
||||
@Field(() => String, { description: 'Network I/O String (e.g. 100MB / 1GB)' })
|
||||
netIO!: string;
|
||||
|
||||
@Field(() => String, { description: 'Block I/O String (e.g. 100MB / 1GB)' })
|
||||
blockIO!: string;
|
||||
}
|
||||
|
||||
@ObjectType({
|
||||
implements: () => Node,
|
||||
})
|
||||
|
||||
@@ -6,6 +6,7 @@ import { DockerConfigService } from '@app/unraid-api/graph/resolvers/docker/dock
|
||||
import { DockerEventService } from '@app/unraid-api/graph/resolvers/docker/docker-event.service.js';
|
||||
import { DockerFormService } from '@app/unraid-api/graph/resolvers/docker/docker-form.service.js';
|
||||
import { DockerPhpService } from '@app/unraid-api/graph/resolvers/docker/docker-php.service.js';
|
||||
import { DockerStatsService } from '@app/unraid-api/graph/resolvers/docker/docker-stats.service.js';
|
||||
import { DockerTemplateScannerService } from '@app/unraid-api/graph/resolvers/docker/docker-template-scanner.service.js';
|
||||
import { DockerModule } from '@app/unraid-api/graph/resolvers/docker/docker.module.js';
|
||||
import { DockerMutationsResolver } from '@app/unraid-api/graph/resolvers/docker/docker.mutations.resolver.js';
|
||||
@@ -13,6 +14,8 @@ import { DockerResolver } from '@app/unraid-api/graph/resolvers/docker/docker.re
|
||||
import { DockerService } from '@app/unraid-api/graph/resolvers/docker/docker.service.js';
|
||||
import { DockerOrganizerConfigService } from '@app/unraid-api/graph/resolvers/docker/organizer/docker-organizer-config.service.js';
|
||||
import { DockerOrganizerService } from '@app/unraid-api/graph/resolvers/docker/organizer/docker-organizer.service.js';
|
||||
import { SubscriptionHelperService } from '@app/unraid-api/graph/services/subscription-helper.service.js';
|
||||
import { SubscriptionTrackerService } from '@app/unraid-api/graph/services/subscription-tracker.service.js';
|
||||
|
||||
describe('DockerModule', () => {
|
||||
it('should compile the module', async () => {
|
||||
@@ -25,6 +28,16 @@ describe('DockerModule', () => {
|
||||
.useValue({ getConfig: vi.fn() })
|
||||
.overrideProvider(DockerConfigService)
|
||||
.useValue({ getConfig: vi.fn() })
|
||||
.overrideProvider(SubscriptionTrackerService)
|
||||
.useValue({
|
||||
registerTopic: vi.fn(),
|
||||
subscribe: vi.fn(),
|
||||
unsubscribe: vi.fn(),
|
||||
})
|
||||
.overrideProvider(SubscriptionHelperService)
|
||||
.useValue({
|
||||
createTrackedSubscription: vi.fn(),
|
||||
})
|
||||
.compile();
|
||||
|
||||
expect(module).toBeDefined();
|
||||
@@ -75,6 +88,25 @@ describe('DockerModule', () => {
|
||||
syncMissingContainers: vi.fn(),
|
||||
},
|
||||
},
|
||||
{
|
||||
provide: DockerStatsService,
|
||||
useValue: {
|
||||
startStatsStream: vi.fn(),
|
||||
stopStatsStream: vi.fn(),
|
||||
},
|
||||
},
|
||||
{
|
||||
provide: SubscriptionTrackerService,
|
||||
useValue: {
|
||||
registerTopic: vi.fn(),
|
||||
},
|
||||
},
|
||||
{
|
||||
provide: SubscriptionHelperService,
|
||||
useValue: {
|
||||
createTrackedSubscription: vi.fn(),
|
||||
},
|
||||
},
|
||||
],
|
||||
}).compile();
|
||||
|
||||
|
||||
@@ -7,6 +7,7 @@ import { DockerContainerResolver } from '@app/unraid-api/graph/resolvers/docker/
|
||||
import { DockerFormService } from '@app/unraid-api/graph/resolvers/docker/docker-form.service.js';
|
||||
import { DockerManifestService } from '@app/unraid-api/graph/resolvers/docker/docker-manifest.service.js';
|
||||
import { DockerPhpService } from '@app/unraid-api/graph/resolvers/docker/docker-php.service.js';
|
||||
import { DockerStatsService } from '@app/unraid-api/graph/resolvers/docker/docker-stats.service.js';
|
||||
import { DockerTemplateIconService } from '@app/unraid-api/graph/resolvers/docker/docker-template-icon.service.js';
|
||||
import { DockerTemplateScannerService } from '@app/unraid-api/graph/resolvers/docker/docker-template-scanner.service.js';
|
||||
import { DockerMutationsResolver } from '@app/unraid-api/graph/resolvers/docker/docker.mutations.resolver.js';
|
||||
@@ -15,9 +16,10 @@ import { DockerService } from '@app/unraid-api/graph/resolvers/docker/docker.ser
|
||||
import { DockerOrganizerConfigService } from '@app/unraid-api/graph/resolvers/docker/organizer/docker-organizer-config.service.js';
|
||||
import { DockerOrganizerService } from '@app/unraid-api/graph/resolvers/docker/organizer/docker-organizer.service.js';
|
||||
import { NotificationsModule } from '@app/unraid-api/graph/resolvers/notifications/notifications.module.js';
|
||||
import { ServicesModule } from '@app/unraid-api/graph/services/services.module.js';
|
||||
|
||||
@Module({
|
||||
imports: [JobModule, NotificationsModule],
|
||||
imports: [JobModule, NotificationsModule, ServicesModule],
|
||||
providers: [
|
||||
// Services
|
||||
DockerService,
|
||||
@@ -29,6 +31,7 @@ import { NotificationsModule } from '@app/unraid-api/graph/resolvers/notificatio
|
||||
DockerConfigService,
|
||||
DockerTemplateScannerService,
|
||||
DockerTemplateIconService,
|
||||
DockerStatsService,
|
||||
|
||||
// Jobs
|
||||
ContainerStatusJob,
|
||||
|
||||
@@ -5,6 +5,7 @@ import { beforeEach, describe, expect, it, vi } from 'vitest';
|
||||
|
||||
import { DockerFormService } from '@app/unraid-api/graph/resolvers/docker/docker-form.service.js';
|
||||
import { DockerPhpService } from '@app/unraid-api/graph/resolvers/docker/docker-php.service.js';
|
||||
import { DockerStatsService } from '@app/unraid-api/graph/resolvers/docker/docker-stats.service.js';
|
||||
import { DockerTemplateScannerService } from '@app/unraid-api/graph/resolvers/docker/docker-template-scanner.service.js';
|
||||
import {
|
||||
ContainerState,
|
||||
@@ -14,6 +15,8 @@ import {
|
||||
import { DockerResolver } from '@app/unraid-api/graph/resolvers/docker/docker.resolver.js';
|
||||
import { DockerService } from '@app/unraid-api/graph/resolvers/docker/docker.service.js';
|
||||
import { DockerOrganizerService } from '@app/unraid-api/graph/resolvers/docker/organizer/docker-organizer.service.js';
|
||||
import { SubscriptionHelperService } from '@app/unraid-api/graph/services/subscription-helper.service.js';
|
||||
import { SubscriptionTrackerService } from '@app/unraid-api/graph/services/subscription-tracker.service.js';
|
||||
import { GraphQLFieldHelper } from '@app/unraid-api/utils/graphql-field-helper.js';
|
||||
|
||||
vi.mock('@app/unraid-api/utils/graphql-field-helper.js', () => ({
|
||||
@@ -69,6 +72,27 @@ describe('DockerResolver', () => {
|
||||
syncMissingContainers: vi.fn().mockResolvedValue(false),
|
||||
},
|
||||
},
|
||||
{
|
||||
provide: DockerStatsService,
|
||||
useValue: {
|
||||
startStatsStream: vi.fn(),
|
||||
stopStatsStream: vi.fn(),
|
||||
},
|
||||
},
|
||||
{
|
||||
provide: SubscriptionTrackerService,
|
||||
useValue: {
|
||||
registerTopic: vi.fn(),
|
||||
subscribe: vi.fn(),
|
||||
unsubscribe: vi.fn(),
|
||||
},
|
||||
},
|
||||
{
|
||||
provide: SubscriptionHelperService,
|
||||
useValue: {
|
||||
createTrackedSubscription: vi.fn(),
|
||||
},
|
||||
},
|
||||
],
|
||||
}).compile();
|
||||
|
||||
|
||||
@@ -7,6 +7,7 @@ import {
|
||||
Query,
|
||||
ResolveField,
|
||||
Resolver,
|
||||
Subscription,
|
||||
} from '@nestjs/graphql';
|
||||
|
||||
import type { GraphQLResolveInfo } from 'graphql';
|
||||
@@ -15,9 +16,11 @@ import { PrefixedID } from '@unraid/shared/prefixed-id-scalar.js';
|
||||
import { UsePermissions } from '@unraid/shared/use-permissions.directive.js';
|
||||
import { GraphQLJSON } from 'graphql-scalars';
|
||||
|
||||
import { PUBSUB_CHANNEL } from '@app/core/pubsub.js';
|
||||
import { UseFeatureFlag } from '@app/unraid-api/decorators/use-feature-flag.decorator.js';
|
||||
import { DockerFormService } from '@app/unraid-api/graph/resolvers/docker/docker-form.service.js';
|
||||
import { DockerPhpService } from '@app/unraid-api/graph/resolvers/docker/docker-php.service.js';
|
||||
import { DockerStatsService } from '@app/unraid-api/graph/resolvers/docker/docker-stats.service.js';
|
||||
import { DockerTemplateSyncResult } from '@app/unraid-api/graph/resolvers/docker/docker-template-scanner.model.js';
|
||||
import { DockerTemplateScannerService } from '@app/unraid-api/graph/resolvers/docker/docker-template-scanner.service.js';
|
||||
import { ExplicitStatusItem } from '@app/unraid-api/graph/resolvers/docker/docker-update-status.model.js';
|
||||
@@ -26,11 +29,14 @@ import {
|
||||
DockerContainer,
|
||||
DockerContainerLogs,
|
||||
DockerContainerOverviewForm,
|
||||
DockerContainerStats,
|
||||
DockerNetwork,
|
||||
DockerPortConflicts,
|
||||
} from '@app/unraid-api/graph/resolvers/docker/docker.model.js';
|
||||
import { DockerService } from '@app/unraid-api/graph/resolvers/docker/docker.service.js';
|
||||
import { DockerOrganizerService } from '@app/unraid-api/graph/resolvers/docker/organizer/docker-organizer.service.js';
|
||||
import { SubscriptionHelperService } from '@app/unraid-api/graph/services/subscription-helper.service.js';
|
||||
import { SubscriptionTrackerService } from '@app/unraid-api/graph/services/subscription-tracker.service.js';
|
||||
import { DEFAULT_ORGANIZER_ROOT_ID } from '@app/unraid-api/organizer/organizer.js';
|
||||
import { ResolvedOrganizerV1 } from '@app/unraid-api/organizer/organizer.model.js';
|
||||
import { GraphQLFieldHelper } from '@app/unraid-api/utils/graphql-field-helper.js';
|
||||
@@ -42,8 +48,17 @@ export class DockerResolver {
|
||||
private readonly dockerFormService: DockerFormService,
|
||||
private readonly dockerOrganizerService: DockerOrganizerService,
|
||||
private readonly dockerPhpService: DockerPhpService,
|
||||
private readonly dockerTemplateScannerService: DockerTemplateScannerService
|
||||
) {}
|
||||
private readonly dockerTemplateScannerService: DockerTemplateScannerService,
|
||||
private readonly dockerStatsService: DockerStatsService,
|
||||
private readonly subscriptionTracker: SubscriptionTrackerService,
|
||||
private readonly subscriptionHelper: SubscriptionHelperService
|
||||
) {
|
||||
this.subscriptionTracker.registerTopic(
|
||||
PUBSUB_CHANNEL.DOCKER_STATS,
|
||||
() => this.dockerStatsService.startStatsStream(),
|
||||
() => this.dockerStatsService.stopStatsStream()
|
||||
);
|
||||
}
|
||||
|
||||
@UsePermissions({
|
||||
action: AuthAction.READ_ANY,
|
||||
@@ -312,4 +327,15 @@ export class DockerResolver {
|
||||
public async syncDockerTemplatePaths() {
|
||||
return this.dockerTemplateScannerService.scanTemplates();
|
||||
}
|
||||
|
||||
@UsePermissions({
|
||||
action: AuthAction.READ_ANY,
|
||||
resource: Resource.DOCKER,
|
||||
})
|
||||
@Subscription(() => DockerContainerStats, {
|
||||
resolve: (payload) => payload.dockerContainerStats,
|
||||
})
|
||||
public dockerContainerStats() {
|
||||
return this.subscriptionHelper.createTrackedSubscription(PUBSUB_CHANNEL.DOCKER_STATS);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,6 +17,7 @@ export enum GRAPHQL_PUBSUB_CHANNEL {
|
||||
OWNER = "OWNER",
|
||||
SERVERS = "SERVERS",
|
||||
VMS = "VMS",
|
||||
DOCKER_STATS = "DOCKER_STATS",
|
||||
LOG_FILE = "LOG_FILE",
|
||||
PARITY = "PARITY",
|
||||
}
|
||||
|
||||
28
web/src/components/Docker/DockerContainerStatCell.vue
Normal file
28
web/src/components/Docker/DockerContainerStatCell.vue
Normal file
@@ -0,0 +1,28 @@
|
||||
<script setup lang="ts">
|
||||
import { computed } from 'vue';
|
||||
|
||||
import type { DockerContainerStats } from '@/composables/gql/graphql';
|
||||
|
||||
interface Props {
|
||||
containerId?: string | null;
|
||||
statsMap: Map<string, DockerContainerStats>;
|
||||
type: 'cpu' | 'memory';
|
||||
}
|
||||
|
||||
const props = defineProps<Props>();
|
||||
|
||||
const value = computed(() => {
|
||||
if (!props.containerId) return '—';
|
||||
const stats = props.statsMap.get(props.containerId);
|
||||
if (!stats) return '—';
|
||||
|
||||
if (props.type === 'cpu') {
|
||||
return `${stats.cpuPercent.toFixed(2)}%`;
|
||||
}
|
||||
return stats.memUsage;
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<span class="tabular-nums">{{ value }}</span>
|
||||
</template>
|
||||
@@ -1,6 +1,6 @@
|
||||
<script setup lang="ts">
|
||||
import { computed, h, nextTick, onBeforeUnmount, reactive, ref, resolveComponent, watch } from 'vue';
|
||||
import { useApolloClient, useMutation } from '@vue/apollo-composable';
|
||||
import { useApolloClient, useMutation, useSubscription } from '@vue/apollo-composable';
|
||||
|
||||
import BaseTreeTable from '@/components/Common/BaseTreeTable.vue';
|
||||
import MultiValueCopyBadges from '@/components/Common/MultiValueCopyBadges.vue';
|
||||
@@ -15,10 +15,12 @@ import { PAUSE_DOCKER_CONTAINER } from '@/components/Docker/docker-pause-contain
|
||||
import { REFRESH_DOCKER_DIGESTS } from '@/components/Docker/docker-refresh-digests.mutation';
|
||||
import { SET_DOCKER_FOLDER_CHILDREN } from '@/components/Docker/docker-set-folder-children.mutation';
|
||||
import { START_DOCKER_CONTAINER } from '@/components/Docker/docker-start-container.mutation';
|
||||
import { DOCKER_STATS_SUBSCRIPTION } from '@/components/Docker/docker-stats.subscription';
|
||||
import { STOP_DOCKER_CONTAINER } from '@/components/Docker/docker-stop-container.mutation';
|
||||
import { UNPAUSE_DOCKER_CONTAINER } from '@/components/Docker/docker-unpause-container.mutation';
|
||||
import { UPDATE_ALL_DOCKER_CONTAINERS } from '@/components/Docker/docker-update-all-containers.mutation';
|
||||
import { UPDATE_DOCKER_CONTAINERS } from '@/components/Docker/docker-update-containers.mutation';
|
||||
import DockerContainerStatCell from '@/components/Docker/DockerContainerStatCell.vue';
|
||||
import { ContainerState } from '@/composables/gql/graphql';
|
||||
import { useContainerActions } from '@/composables/useContainerActions';
|
||||
import { useDockerViewPreferences } from '@/composables/useDockerColumnVisibility';
|
||||
@@ -29,6 +31,7 @@ import { useTreeData } from '@/composables/useTreeData';
|
||||
|
||||
import type {
|
||||
DockerContainer,
|
||||
DockerContainerStats,
|
||||
FlatOrganizerEntry,
|
||||
GetDockerContainerLogsQuery,
|
||||
GetDockerContainerLogsQueryVariables,
|
||||
@@ -97,6 +100,19 @@ const emit = defineEmits<{
|
||||
}>();
|
||||
const { client: apolloClient } = useApolloClient();
|
||||
|
||||
const containerStats = reactive(new Map<string, DockerContainerStats>());
|
||||
|
||||
const { onResult: onStatsResult } = useSubscription(DOCKER_STATS_SUBSCRIPTION, null, () => ({
|
||||
fetchPolicy: 'network-only',
|
||||
}));
|
||||
|
||||
onStatsResult((result) => {
|
||||
const stat = result.data?.dockerContainerStats as DockerContainerStats | undefined;
|
||||
if (stat && stat.id) {
|
||||
containerStats.set(stat.id, stat);
|
||||
}
|
||||
});
|
||||
|
||||
const COMMA_SEPARATED_LIST = /\s*,\s*/;
|
||||
|
||||
function normalizeListString(value: string): string[] {
|
||||
@@ -833,6 +849,30 @@ const columns = computed<TableColumn<TreeRow<DockerContainer>>[]>(() => {
|
||||
return h(UBadge, { color }, () => state);
|
||||
},
|
||||
},
|
||||
{
|
||||
accessorKey: 'cpu',
|
||||
header: 'CPU',
|
||||
cell: ({ row }) => {
|
||||
if (row.original.type === 'folder' || !row.original.containerId) return '';
|
||||
return h(DockerContainerStatCell, {
|
||||
containerId: row.original.containerId,
|
||||
statsMap: containerStats,
|
||||
type: 'cpu',
|
||||
});
|
||||
},
|
||||
},
|
||||
{
|
||||
accessorKey: 'memory',
|
||||
header: 'Memory',
|
||||
cell: ({ row }) => {
|
||||
if (row.original.type === 'folder' || !row.original.containerId) return '';
|
||||
return h(DockerContainerStatCell, {
|
||||
containerId: row.original.containerId,
|
||||
statsMap: containerStats,
|
||||
type: 'memory',
|
||||
});
|
||||
},
|
||||
},
|
||||
{
|
||||
accessorKey: 'version',
|
||||
header: 'Version',
|
||||
@@ -914,6 +954,8 @@ function getDefaultColumnVisibility(isCompact: boolean): Record<string, boolean>
|
||||
if (isCompact) {
|
||||
return {
|
||||
state: false,
|
||||
cpu: false,
|
||||
memory: false,
|
||||
version: false,
|
||||
network: false,
|
||||
containerIp: false,
|
||||
@@ -927,6 +969,8 @@ function getDefaultColumnVisibility(isCompact: boolean): Record<string, boolean>
|
||||
} else {
|
||||
return {
|
||||
state: true,
|
||||
cpu: true,
|
||||
memory: true,
|
||||
version: false,
|
||||
network: false,
|
||||
containerIp: false,
|
||||
@@ -1525,6 +1569,35 @@ function getRowActionItems(row: TreeRow<DockerContainer>): DropdownMenuItems {
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
function handleRowClick(payload: { id: string; type: string; name: string; meta?: DockerContainer }) {
|
||||
emit('row:click', {
|
||||
id: payload.id,
|
||||
type: payload.type as 'container' | 'folder',
|
||||
name: payload.name,
|
||||
containerId: payload.meta?.id,
|
||||
});
|
||||
}
|
||||
|
||||
function handleRowSelect(payload: {
|
||||
id: string;
|
||||
type: string;
|
||||
name: string;
|
||||
meta?: DockerContainer;
|
||||
selected: boolean;
|
||||
}) {
|
||||
emit('row:select', {
|
||||
id: payload.id,
|
||||
type: payload.type as 'container' | 'folder',
|
||||
name: payload.name,
|
||||
containerId: payload.meta?.id,
|
||||
selected: payload.selected,
|
||||
});
|
||||
}
|
||||
|
||||
function handleUpdateSelectedIds(ids: string[]) {
|
||||
emit('update:selectedIds', ids);
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
@@ -1541,28 +1614,11 @@ function getRowActionItems(row: TreeRow<DockerContainer>): DropdownMenuItems {
|
||||
:enable-drag-drop="!!flatEntries"
|
||||
:searchable-keys="searchableKeys"
|
||||
:search-accessor="dockerSearchAccessor"
|
||||
@row:click="
|
||||
(payload) =>
|
||||
emit('row:click', {
|
||||
id: payload.id,
|
||||
type: payload.type as 'container' | 'folder',
|
||||
name: payload.name,
|
||||
containerId: payload.meta?.id,
|
||||
})
|
||||
"
|
||||
@row:click="handleRowClick"
|
||||
@row:contextmenu="handleRowContextMenu"
|
||||
@row:select="
|
||||
(payload) =>
|
||||
emit('row:select', {
|
||||
id: payload.id,
|
||||
type: payload.type as 'container' | 'folder',
|
||||
name: payload.name,
|
||||
containerId: payload.meta?.id,
|
||||
selected: payload.selected,
|
||||
})
|
||||
"
|
||||
@row:select="handleRowSelect"
|
||||
@row:drop="handleDropOnRow"
|
||||
@update:selected-ids="(ids) => emit('update:selectedIds', ids)"
|
||||
@update:selected-ids="handleUpdateSelectedIds"
|
||||
>
|
||||
<template #toolbar="{ selectedCount: count, globalFilter: filterText, setGlobalFilter }">
|
||||
<div :class="['mb-4 flex flex-wrap items-center gap-2', compact ? 'sm:px-0.5' : '']">
|
||||
@@ -1763,16 +1819,15 @@ function getRowActionItems(row: TreeRow<DockerContainer>): DropdownMenuItems {
|
||||
class="flex min-w-0 flex-1 items-center gap-2"
|
||||
>
|
||||
<span class="i-lucide-folder text-gray-500" />
|
||||
<!-- @vue-expect-error - Vue auto-unwraps refs in templates -->
|
||||
<template v-if="folderOps.renamingFolderId === row.id">
|
||||
<template v-if="folderOps.renamingFolderId.value === row.id">
|
||||
<input
|
||||
v-model="folderOps.renameValue"
|
||||
class="border-default bg-default flex-1 rounded border px-2 py-1"
|
||||
@keydown.enter.prevent="folderOps.commitRenameFolder(row.id)"
|
||||
@keydown.esc.prevent="
|
||||
() => {
|
||||
folderOps.renamingFolderId = '';
|
||||
folderOps.renameValue = '';
|
||||
folderOps.renamingFolderId.value = '';
|
||||
folderOps.renameValue.value = '';
|
||||
}
|
||||
"
|
||||
@blur="folderOps.commitRenameFolder(row.id)"
|
||||
|
||||
14
web/src/components/Docker/docker-stats.subscription.ts
Normal file
14
web/src/components/Docker/docker-stats.subscription.ts
Normal file
@@ -0,0 +1,14 @@
|
||||
import { gql } from '@apollo/client';
|
||||
|
||||
export const DOCKER_STATS_SUBSCRIPTION = gql`
|
||||
subscription DockerContainerStats {
|
||||
dockerContainerStats {
|
||||
id
|
||||
cpuPercent
|
||||
memUsage
|
||||
memPercent
|
||||
netIO
|
||||
blockIO
|
||||
}
|
||||
}
|
||||
`;
|
||||
@@ -43,6 +43,7 @@ type Documents = {
|
||||
"\n mutation RenameDockerFolder($folderId: String!, $newName: String!) {\n renameDockerFolder(folderId: $folderId, newName: $newName) {\n version\n views {\n id\n name\n rootId\n flatEntries {\n id\n type\n name\n parentId\n depth\n position\n path\n hasChildren\n childrenIds\n meta {\n id\n names\n state\n status\n image\n ports {\n privatePort\n publicPort\n type\n }\n autoStart\n hostConfig {\n networkMode\n }\n created\n isUpdateAvailable\n isRebuildReady\n }\n }\n }\n }\n }\n": typeof types.RenameDockerFolderDocument,
|
||||
"\n mutation SetDockerFolderChildren($folderId: String, $childrenIds: [String!]!) {\n setDockerFolderChildren(folderId: $folderId, childrenIds: $childrenIds) {\n version\n views {\n id\n name\n rootId\n flatEntries {\n id\n type\n name\n parentId\n depth\n position\n path\n hasChildren\n childrenIds\n }\n }\n }\n }\n": typeof types.SetDockerFolderChildrenDocument,
|
||||
"\n mutation StartDockerContainer($id: PrefixedID!) {\n docker {\n start(id: $id) {\n id\n names\n state\n }\n }\n }\n": typeof types.StartDockerContainerDocument,
|
||||
"\n subscription DockerContainerStats {\n dockerContainerStats {\n id\n cpuPercent\n memUsage\n memPercent\n netIO\n blockIO\n }\n }\n": typeof types.DockerContainerStatsDocument,
|
||||
"\n mutation StopDockerContainer($id: PrefixedID!) {\n docker {\n stop(id: $id) {\n id\n names\n state\n }\n }\n }\n": typeof types.StopDockerContainerDocument,
|
||||
"\n mutation UnpauseDockerContainer($id: PrefixedID!) {\n docker {\n unpause(id: $id) {\n id\n names\n state\n }\n }\n }\n": typeof types.UnpauseDockerContainerDocument,
|
||||
"\n mutation UpdateAllDockerContainers {\n docker {\n updateAllContainers {\n id\n names\n state\n isUpdateAvailable\n isRebuildReady\n }\n }\n }\n": typeof types.UpdateAllDockerContainersDocument,
|
||||
@@ -113,6 +114,7 @@ const documents: Documents = {
|
||||
"\n mutation RenameDockerFolder($folderId: String!, $newName: String!) {\n renameDockerFolder(folderId: $folderId, newName: $newName) {\n version\n views {\n id\n name\n rootId\n flatEntries {\n id\n type\n name\n parentId\n depth\n position\n path\n hasChildren\n childrenIds\n meta {\n id\n names\n state\n status\n image\n ports {\n privatePort\n publicPort\n type\n }\n autoStart\n hostConfig {\n networkMode\n }\n created\n isUpdateAvailable\n isRebuildReady\n }\n }\n }\n }\n }\n": types.RenameDockerFolderDocument,
|
||||
"\n mutation SetDockerFolderChildren($folderId: String, $childrenIds: [String!]!) {\n setDockerFolderChildren(folderId: $folderId, childrenIds: $childrenIds) {\n version\n views {\n id\n name\n rootId\n flatEntries {\n id\n type\n name\n parentId\n depth\n position\n path\n hasChildren\n childrenIds\n }\n }\n }\n }\n": types.SetDockerFolderChildrenDocument,
|
||||
"\n mutation StartDockerContainer($id: PrefixedID!) {\n docker {\n start(id: $id) {\n id\n names\n state\n }\n }\n }\n": types.StartDockerContainerDocument,
|
||||
"\n subscription DockerContainerStats {\n dockerContainerStats {\n id\n cpuPercent\n memUsage\n memPercent\n netIO\n blockIO\n }\n }\n": types.DockerContainerStatsDocument,
|
||||
"\n mutation StopDockerContainer($id: PrefixedID!) {\n docker {\n stop(id: $id) {\n id\n names\n state\n }\n }\n }\n": types.StopDockerContainerDocument,
|
||||
"\n mutation UnpauseDockerContainer($id: PrefixedID!) {\n docker {\n unpause(id: $id) {\n id\n names\n state\n }\n }\n }\n": types.UnpauseDockerContainerDocument,
|
||||
"\n mutation UpdateAllDockerContainers {\n docker {\n updateAllContainers {\n id\n names\n state\n isUpdateAvailable\n isRebuildReady\n }\n }\n }\n": types.UpdateAllDockerContainersDocument,
|
||||
@@ -284,6 +286,10 @@ export function graphql(source: "\n mutation SetDockerFolderChildren($folderId:
|
||||
* The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
|
||||
*/
|
||||
export function graphql(source: "\n mutation StartDockerContainer($id: PrefixedID!) {\n docker {\n start(id: $id) {\n id\n names\n state\n }\n }\n }\n"): (typeof documents)["\n mutation StartDockerContainer($id: PrefixedID!) {\n docker {\n start(id: $id) {\n id\n names\n state\n }\n }\n }\n"];
|
||||
/**
|
||||
* The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
|
||||
*/
|
||||
export function graphql(source: "\n subscription DockerContainerStats {\n dockerContainerStats {\n id\n cpuPercent\n memUsage\n memPercent\n netIO\n blockIO\n }\n }\n"): (typeof documents)["\n subscription DockerContainerStats {\n dockerContainerStats {\n id\n cpuPercent\n memUsage\n memPercent\n netIO\n blockIO\n }\n }\n"];
|
||||
/**
|
||||
* The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
|
||||
*/
|
||||
|
||||
@@ -798,6 +798,21 @@ export type DockerContainerPortConflict = {
|
||||
type: ContainerPortType;
|
||||
};
|
||||
|
||||
export type DockerContainerStats = {
|
||||
__typename?: 'DockerContainerStats';
|
||||
/** Block I/O String (e.g. 100MB / 1GB) */
|
||||
blockIO: Scalars['String']['output'];
|
||||
/** CPU Usage Percentage */
|
||||
cpuPercent: Scalars['Float']['output'];
|
||||
id: Scalars['PrefixedID']['output'];
|
||||
/** Memory Usage Percentage */
|
||||
memPercent: Scalars['Float']['output'];
|
||||
/** Memory Usage String (e.g. 100MB / 1GB) */
|
||||
memUsage: Scalars['String']['output'];
|
||||
/** Network I/O String (e.g. 100MB / 1GB) */
|
||||
netIO: Scalars['String']['output'];
|
||||
};
|
||||
|
||||
export type DockerLanPortConflict = {
|
||||
__typename?: 'DockerLanPortConflict';
|
||||
containers: Array<DockerPortConflictContainer>;
|
||||
@@ -2233,6 +2248,7 @@ export type SsoSettings = Node & {
|
||||
export type Subscription = {
|
||||
__typename?: 'Subscription';
|
||||
arraySubscription: UnraidArray;
|
||||
dockerContainerStats: Array<DockerContainerStats>;
|
||||
logFile: LogFileContent;
|
||||
notificationAdded: Notification;
|
||||
notificationsOverview: NotificationOverview;
|
||||
@@ -2964,6 +2980,11 @@ export type StartDockerContainerMutationVariables = Exact<{
|
||||
|
||||
export type StartDockerContainerMutation = { __typename?: 'Mutation', docker: { __typename?: 'DockerMutations', start: { __typename?: 'DockerContainer', id: string, names: Array<string>, state: ContainerState } } };
|
||||
|
||||
export type DockerContainerStatsSubscriptionVariables = Exact<{ [key: string]: never; }>;
|
||||
|
||||
|
||||
export type DockerContainerStatsSubscription = { __typename?: 'Subscription', dockerContainerStats: Array<{ __typename?: 'DockerContainerStats', id: string, cpuPercent: number, memUsage: string, memPercent: number, netIO: string, blockIO: string }> };
|
||||
|
||||
export type StopDockerContainerMutationVariables = Exact<{
|
||||
id: Scalars['PrefixedID']['input'];
|
||||
}>;
|
||||
@@ -3252,6 +3273,7 @@ export const RefreshDockerDigestsDocument = {"kind":"Document","definitions":[{"
|
||||
export const RenameDockerFolderDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"RenameDockerFolder"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"folderId"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"newName"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"renameDockerFolder"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"folderId"},"value":{"kind":"Variable","name":{"kind":"Name","value":"folderId"}}},{"kind":"Argument","name":{"kind":"Name","value":"newName"},"value":{"kind":"Variable","name":{"kind":"Name","value":"newName"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"version"}},{"kind":"Field","name":{"kind":"Name","value":"views"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"rootId"}},{"kind":"Field","name":{"kind":"Name","value":"flatEntries"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"type"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"parentId"}},{"kind":"Field","name":{"kind":"Name","value":"depth"}},{"kind":"Field","name":{"kind":"Name","value":"position"}},{"kind":"Field","name":{"kind":"Name","value":"path"}},{"kind":"Field","name":{"kind":"Name","value":"hasChildren"}},{"kind":"Field","name":{"kind":"Name","value":"childrenIds"}},{"kind":"Field","name":{"kind":"Name","value":"meta"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"names"}},{"kind":"Field","name":{"kind":"Name","value":"state"}},{"kind":"Field","name":{"kind":"Name","value":"status"}},{"kind":"Field","name":{"kind":"Name","value":"image"}},{"kind":"Field","name":{"kind":"Name","value":"ports"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"privatePort"}},{"kind":"Field","name":{"kind":"Name","value":"publicPort"}},{"kind":"Field","name":{"kind":"Name","value":"type"}}]}},{"kind":"Field","name":{"kind":"Name","value":"autoStart"}},{"kind":"Field","name":{"kind":"Name","value":"hostConfig"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"networkMode"}}]}},{"kind":"Field","name":{"kind":"Name","value":"created"}},{"kind":"Field","name":{"kind":"Name","value":"isUpdateAvailable"}},{"kind":"Field","name":{"kind":"Name","value":"isRebuildReady"}}]}}]}}]}}]}}]}}]} as unknown as DocumentNode<RenameDockerFolderMutation, RenameDockerFolderMutationVariables>;
|
||||
export const SetDockerFolderChildrenDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"SetDockerFolderChildren"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"folderId"}},"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"childrenIds"}},"type":{"kind":"NonNullType","type":{"kind":"ListType","type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"setDockerFolderChildren"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"folderId"},"value":{"kind":"Variable","name":{"kind":"Name","value":"folderId"}}},{"kind":"Argument","name":{"kind":"Name","value":"childrenIds"},"value":{"kind":"Variable","name":{"kind":"Name","value":"childrenIds"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"version"}},{"kind":"Field","name":{"kind":"Name","value":"views"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"rootId"}},{"kind":"Field","name":{"kind":"Name","value":"flatEntries"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"type"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"parentId"}},{"kind":"Field","name":{"kind":"Name","value":"depth"}},{"kind":"Field","name":{"kind":"Name","value":"position"}},{"kind":"Field","name":{"kind":"Name","value":"path"}},{"kind":"Field","name":{"kind":"Name","value":"hasChildren"}},{"kind":"Field","name":{"kind":"Name","value":"childrenIds"}}]}}]}}]}}]}}]} as unknown as DocumentNode<SetDockerFolderChildrenMutation, SetDockerFolderChildrenMutationVariables>;
|
||||
export const StartDockerContainerDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"StartDockerContainer"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"id"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"PrefixedID"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"docker"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"start"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"id"},"value":{"kind":"Variable","name":{"kind":"Name","value":"id"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"names"}},{"kind":"Field","name":{"kind":"Name","value":"state"}}]}}]}}]}}]} as unknown as DocumentNode<StartDockerContainerMutation, StartDockerContainerMutationVariables>;
|
||||
export const DockerContainerStatsDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"subscription","name":{"kind":"Name","value":"DockerContainerStats"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"dockerContainerStats"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"cpuPercent"}},{"kind":"Field","name":{"kind":"Name","value":"memUsage"}},{"kind":"Field","name":{"kind":"Name","value":"memPercent"}},{"kind":"Field","name":{"kind":"Name","value":"netIO"}},{"kind":"Field","name":{"kind":"Name","value":"blockIO"}}]}}]}}]} as unknown as DocumentNode<DockerContainerStatsSubscription, DockerContainerStatsSubscriptionVariables>;
|
||||
export const StopDockerContainerDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"StopDockerContainer"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"id"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"PrefixedID"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"docker"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"stop"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"id"},"value":{"kind":"Variable","name":{"kind":"Name","value":"id"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"names"}},{"kind":"Field","name":{"kind":"Name","value":"state"}}]}}]}}]}}]} as unknown as DocumentNode<StopDockerContainerMutation, StopDockerContainerMutationVariables>;
|
||||
export const UnpauseDockerContainerDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"UnpauseDockerContainer"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"id"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"PrefixedID"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"docker"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"unpause"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"id"},"value":{"kind":"Variable","name":{"kind":"Name","value":"id"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"names"}},{"kind":"Field","name":{"kind":"Name","value":"state"}}]}}]}}]}}]} as unknown as DocumentNode<UnpauseDockerContainerMutation, UnpauseDockerContainerMutationVariables>;
|
||||
export const UpdateAllDockerContainersDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"UpdateAllDockerContainers"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"docker"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"updateAllContainers"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"names"}},{"kind":"Field","name":{"kind":"Name","value":"state"}},{"kind":"Field","name":{"kind":"Name","value":"isUpdateAvailable"}},{"kind":"Field","name":{"kind":"Name","value":"isRebuildReady"}}]}}]}}]}}]} as unknown as DocumentNode<UpdateAllDockerContainersMutation, UpdateAllDockerContainersMutationVariables>;
|
||||
|
||||
Reference in New Issue
Block a user