scaffold docker form service

This commit is contained in:
Pujit Mehrotra
2025-09-22 11:07:33 -04:00
parent 280a5f76ac
commit 7ae92a2f90
7 changed files with 73 additions and 72 deletions
+16 -1
View File
@@ -862,6 +862,12 @@ type DockerMutations {
"""Stop a container"""
stop(id: PrefixedID!): DockerContainer!
"""Pause (Suspend) a container"""
pause(id: PrefixedID!): DockerContainer!
"""Unpause (Resume) a container"""
unpause(id: PrefixedID!): DockerContainer!
}
type VmMutations {
@@ -1108,6 +1114,7 @@ type DockerContainer implements Node {
enum ContainerState {
RUNNING
PAUSED
EXITED
}
@@ -1133,10 +1140,17 @@ type Docker implements Node {
id: PrefixedID!
containers(skipCache: Boolean! = false): [DockerContainer!]!
networks(skipCache: Boolean! = false): [DockerNetwork!]!
organizer: ResolvedOrganizerV1!
organizer(skipCache: Boolean! = false): ResolvedOrganizerV1!
containerUpdateStatuses: [ExplicitStatusItem!]!
}
type DockerContainerOverviewForm {
id: ID!
dataSchema: JSON!
uiSchema: JSON!
data: JSON!
}
type ResolvedOrganizerView {
id: String!
name: String!
@@ -2388,6 +2402,7 @@ type Query {
publicPartnerInfo: PublicPartnerInfo
publicTheme: Theme!
docker: Docker!
dockerContainerOverviewForm(skipCache: Boolean! = false): DockerContainerOverviewForm!
disks: [Disk!]!
disk(id: PrefixedID!): Disk!
rclone: RCloneBackupSettings!
@@ -695,6 +695,11 @@ export type DockerNetworksArgs = {
skipCache?: Scalars['Boolean']['input'];
};
export type DockerOrganizerArgs = {
skipCache?: Scalars['Boolean']['input'];
};
export type DockerContainer = Node & {
__typename?: 'DockerContainer';
autoStart: Scalars['Boolean']['output'];
@@ -717,6 +722,14 @@ export type DockerContainer = Node & {
status: Scalars['String']['output'];
};
export type DockerContainerOverviewForm = {
__typename?: 'DockerContainerOverviewForm';
data: Scalars['JSON']['output'];
dataSchema: Scalars['JSON']['output'];
id: Scalars['ID']['output'];
uiSchema: Scalars['JSON']['output'];
};
export type DockerMutations = {
__typename?: 'DockerMutations';
/** Start a container */
@@ -1663,6 +1676,7 @@ export type Query = {
disk: Disk;
disks: Array<Disk>;
docker: Docker;
dockerContainerOverviewForm: DockerContainerOverviewForm;
flash: Flash;
/** Get JSON Schema for API key creation form */
getApiKeyCreationFormSchema: ApiKeyFormSettings;
@@ -1726,6 +1740,11 @@ export type QueryDiskArgs = {
};
export type QueryDockerContainerOverviewFormArgs = {
skipCache?: Scalars['Boolean']['input'];
};
export type QueryGetPermissionsForRolesArgs = {
roles: Array<Role>;
};
@@ -44,10 +44,11 @@ export class DockerFormService {
type: 'object',
properties: dataSchema,
},
uiSchema,
data: {
containers: tableData,
uiSchema: {
type: 'VerticalLayout',
elements: [uiSchema],
},
data: tableData,
};
}
@@ -99,72 +100,11 @@ export class DockerFormService {
private createUiSchema(): UISchemaElement {
return {
type: 'VerticalLayout',
elements: [
{
type: 'Control',
scope: '#/properties/containers',
options: {
detail: {
type: 'HorizontalLayout',
elements: [
{
type: 'Control',
scope: '#/properties/name',
options: {
trim: true,
readonly: true,
},
},
{
type: 'Control',
scope: '#/properties/state',
options: {
readonly: true,
format: 'badge',
},
},
{
type: 'Control',
scope: '#/properties/status',
options: {
readonly: true,
},
},
{
type: 'Control',
scope: '#/properties/image',
options: {
readonly: true,
trim: true,
},
},
{
type: 'Control',
scope: '#/properties/ports',
options: {
readonly: true,
},
},
{
type: 'Control',
scope: '#/properties/autoStart',
options: {
readonly: true,
},
},
{
type: 'Control',
scope: '#/properties/network',
options: {
readonly: true,
},
},
],
},
},
},
],
type: 'Control',
scope: '#',
options: {
variant: 'table',
},
};
}
}
@@ -4,6 +4,7 @@ import { describe, expect, it, vi } from 'vitest';
import { DockerConfigService } from '@app/unraid-api/graph/resolvers/docker/docker-config.service.js';
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 { DockerModule } from '@app/unraid-api/graph/resolvers/docker/docker.module.js';
import { DockerMutationsResolver } from '@app/unraid-api/graph/resolvers/docker/docker.mutations.resolver.js';
@@ -63,6 +64,7 @@ describe('DockerModule', () => {
providers: [
DockerResolver,
{ provide: DockerService, useValue: {} },
{ provide: DockerFormService, useValue: { getContainerOverviewForm: vi.fn() } },
{ provide: DockerOrganizerService, useValue: {} },
{ provide: DockerPhpService, useValue: { getContainerUpdateStatuses: vi.fn() } },
],
@@ -4,6 +4,7 @@ import { JobModule } from '@app/unraid-api/cron/job.module.js';
import { ContainerStatusJob } from '@app/unraid-api/graph/resolvers/docker/container-status.job.js';
import { DockerConfigService } from '@app/unraid-api/graph/resolvers/docker/docker-config.service.js';
import { DockerContainerResolver } from '@app/unraid-api/graph/resolvers/docker/docker-container.resolver.js';
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 { DockerMutationsResolver } from '@app/unraid-api/graph/resolvers/docker/docker.mutations.resolver.js';
@@ -17,6 +18,7 @@ import { DockerOrganizerService } from '@app/unraid-api/graph/resolvers/docker/o
providers: [
// Services
DockerService,
DockerFormService,
DockerOrganizerConfigService,
DockerOrganizerService,
DockerManifestService,
@@ -3,6 +3,7 @@ import { Test } from '@nestjs/testing';
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 { ContainerState, DockerContainer } from '@app/unraid-api/graph/resolvers/docker/docker.model.js';
import { DockerResolver } from '@app/unraid-api/graph/resolvers/docker/docker.resolver.js';
@@ -31,6 +32,12 @@ describe('DockerResolver', () => {
getNetworks: vi.fn(),
},
},
{
provide: DockerFormService,
useValue: {
getContainerOverviewForm: vi.fn(),
},
},
{
provide: DockerOrganizerService,
useValue: {
@@ -5,11 +5,13 @@ import { AuthAction, Resource } from '@unraid/shared/graphql.model.js';
import { UsePermissions } from '@unraid/shared/use-permissions.directive.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 { ExplicitStatusItem } from '@app/unraid-api/graph/resolvers/docker/docker-update-status.model.js';
import {
Docker,
DockerContainer,
DockerContainerOverviewForm,
DockerNetwork,
} from '@app/unraid-api/graph/resolvers/docker/docker.model.js';
import { DockerService } from '@app/unraid-api/graph/resolvers/docker/docker.service.js';
@@ -22,6 +24,7 @@ import { GraphQLFieldHelper } from '@app/unraid-api/utils/graphql-field-helper.j
export class DockerResolver {
constructor(
private readonly dockerService: DockerService,
private readonly dockerFormService: DockerFormService,
private readonly dockerOrganizerService: DockerOrganizerService,
private readonly dockerPhpService: DockerPhpService
) {}
@@ -61,14 +64,27 @@ export class DockerResolver {
return this.dockerService.getNetworks({ skipCache });
}
@UsePermissions({
action: AuthAction.READ_ANY,
resource: Resource.DOCKER,
})
@Query(() => DockerContainerOverviewForm)
public async dockerContainerOverviewForm(
@Args('skipCache', { defaultValue: false, type: () => Boolean }) skipCache: boolean
) {
return this.dockerFormService.getContainerOverviewForm(skipCache);
}
@UseFeatureFlag('ENABLE_NEXT_DOCKER_RELEASE')
@UsePermissions({
action: AuthAction.READ_ANY,
resource: Resource.DOCKER,
})
@ResolveField(() => ResolvedOrganizerV1)
public async organizer() {
return this.dockerOrganizerService.resolveOrganizer();
public async organizer(
@Args('skipCache', { defaultValue: false, type: () => Boolean }) skipCache: boolean
) {
return this.dockerOrganizerService.resolveOrganizer(undefined, { skipCache });
}
@UseFeatureFlag('ENABLE_NEXT_DOCKER_RELEASE')