Skip to content

Commit 802901c

Browse files
committed
unify iconUrl retrieval
1 parent b69e7cc commit 802901c

File tree

10 files changed

+120
-54
lines changed

10 files changed

+120
-54
lines changed

api/generated-schema.graphql

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1361,7 +1361,6 @@ type FlatOrganizerEntry {
13611361
hasChildren: Boolean!
13621362
childrenIds: [String!]!
13631363
meta: DockerContainer
1364-
icon: String
13651364
}
13661365

13671366
type FlashBackupStatus {

api/src/unraid-api/cli/generated/graphql.ts

Lines changed: 106 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -560,6 +560,17 @@ export type CpuLoad = {
560560
percentUser: Scalars['Float']['output'];
561561
};
562562

563+
export type CpuPackages = Node & {
564+
__typename?: 'CpuPackages';
565+
id: Scalars['PrefixedID']['output'];
566+
/** Power draw per package (W) */
567+
power: Array<Scalars['Float']['output']>;
568+
/** Temperature per package (°C) */
569+
temp: Array<Scalars['Float']['output']>;
570+
/** Total CPU package power draw (W) */
571+
totalPower: Scalars['Float']['output'];
572+
};
573+
563574
export type CpuUtilization = Node & {
564575
__typename?: 'CpuUtilization';
565576
/** CPU load for each core */
@@ -682,8 +693,11 @@ export type Docker = Node & {
682693
containerUpdateStatuses: Array<ExplicitStatusItem>;
683694
containers: Array<DockerContainer>;
684695
id: Scalars['PrefixedID']['output'];
696+
/** Access container logs. Requires specifying a target container id through resolver arguments. */
697+
logs: DockerContainerLogs;
685698
networks: Array<DockerNetwork>;
686699
organizer: ResolvedOrganizerV1;
700+
portConflicts: DockerPortConflicts;
687701
};
688702

689703

@@ -692,6 +706,13 @@ export type DockerContainersArgs = {
692706
};
693707

694708

709+
export type DockerLogsArgs = {
710+
id: Scalars['PrefixedID']['input'];
711+
since?: InputMaybe<Scalars['DateTime']['input']>;
712+
tail?: InputMaybe<Scalars['Int']['input']>;
713+
};
714+
715+
695716
export type DockerNetworksArgs = {
696717
skipCache?: Scalars['Boolean']['input'];
697718
};
@@ -701,6 +722,11 @@ export type DockerOrganizerArgs = {
701722
skipCache?: Scalars['Boolean']['input'];
702723
};
703724

725+
726+
export type DockerPortConflictsArgs = {
727+
skipCache?: Scalars['Boolean']['input'];
728+
};
729+
704730
export type DockerAutostartEntryInput = {
705731
/** Whether the container should auto-start */
706732
autoStart: Scalars['Boolean']['input'];
@@ -720,9 +746,13 @@ export type DockerContainer = Node & {
720746
command: Scalars['String']['output'];
721747
created: Scalars['Int']['output'];
722748
hostConfig?: Maybe<ContainerHostConfig>;
749+
/** Icon URL */
750+
iconUrl?: Maybe<Scalars['String']['output']>;
723751
id: Scalars['PrefixedID']['output'];
724752
image: Scalars['String']['output'];
725753
imageId: Scalars['String']['output'];
754+
/** Whether the container is orphaned (no template found) */
755+
isOrphaned: Scalars['Boolean']['output'];
726756
isRebuildReady?: Maybe<Scalars['Boolean']['output']>;
727757
isUpdateAvailable?: Maybe<Scalars['Boolean']['output']>;
728758
labels?: Maybe<Scalars['JSON']['output']>;
@@ -732,6 +762,10 @@ export type DockerContainer = Node & {
732762
names: Array<Scalars['String']['output']>;
733763
networkSettings?: Maybe<Scalars['JSON']['output']>;
734764
ports: Array<ContainerPort>;
765+
/** Project/Product homepage URL */
766+
projectUrl?: Maybe<Scalars['String']['output']>;
767+
/** Registry/Docker Hub URL */
768+
registryUrl?: Maybe<Scalars['String']['output']>;
735769
/** Size of container logs (in bytes) */
736770
sizeLog?: Maybe<Scalars['BigInt']['output']>;
737771
/** Total size of all files in the container (in bytes) */
@@ -740,9 +774,25 @@ export type DockerContainer = Node & {
740774
sizeRw?: Maybe<Scalars['BigInt']['output']>;
741775
state: ContainerState;
742776
status: Scalars['String']['output'];
777+
/** Support page/thread URL */
778+
supportUrl?: Maybe<Scalars['String']['output']>;
743779
templatePath?: Maybe<Scalars['String']['output']>;
744780
};
745781

782+
export type DockerContainerLogLine = {
783+
__typename?: 'DockerContainerLogLine';
784+
message: Scalars['String']['output'];
785+
timestamp: Scalars['DateTime']['output'];
786+
};
787+
788+
export type DockerContainerLogs = {
789+
__typename?: 'DockerContainerLogs';
790+
containerId: Scalars['PrefixedID']['output'];
791+
/** Cursor that can be passed back through the since argument to continue streaming logs. */
792+
cursor?: Maybe<Scalars['DateTime']['output']>;
793+
lines: Array<DockerContainerLogLine>;
794+
};
795+
746796
export type DockerContainerOverviewForm = {
747797
__typename?: 'DockerContainerOverviewForm';
748798
data: Scalars['JSON']['output'];
@@ -751,16 +801,50 @@ export type DockerContainerOverviewForm = {
751801
uiSchema: Scalars['JSON']['output'];
752802
};
753803

804+
export type DockerContainerPortConflict = {
805+
__typename?: 'DockerContainerPortConflict';
806+
containers: Array<DockerPortConflictContainer>;
807+
privatePort: Scalars['Port']['output'];
808+
type: ContainerPortType;
809+
};
810+
811+
export type DockerContainerStats = {
812+
__typename?: 'DockerContainerStats';
813+
/** Block I/O String (e.g. 100MB / 1GB) */
814+
blockIO: Scalars['String']['output'];
815+
/** CPU Usage Percentage */
816+
cpuPercent: Scalars['Float']['output'];
817+
id: Scalars['PrefixedID']['output'];
818+
/** Memory Usage Percentage */
819+
memPercent: Scalars['Float']['output'];
820+
/** Memory Usage String (e.g. 100MB / 1GB) */
821+
memUsage: Scalars['String']['output'];
822+
/** Network I/O String (e.g. 100MB / 1GB) */
823+
netIO: Scalars['String']['output'];
824+
};
825+
826+
export type DockerLanPortConflict = {
827+
__typename?: 'DockerLanPortConflict';
828+
containers: Array<DockerPortConflictContainer>;
829+
lanIpPort: Scalars['String']['output'];
830+
publicPort?: Maybe<Scalars['Port']['output']>;
831+
type: ContainerPortType;
832+
};
833+
754834
export type DockerMutations = {
755835
__typename?: 'DockerMutations';
756836
/** Pause (Suspend) a container */
757837
pause: DockerContainer;
838+
/** Remove a container */
839+
removeContainer: Scalars['Boolean']['output'];
758840
/** Start a container */
759841
start: DockerContainer;
760842
/** Stop a container */
761843
stop: DockerContainer;
762844
/** Unpause (Resume) a container */
763845
unpause: DockerContainer;
846+
/** Update all containers that have available updates */
847+
updateAllContainers: Array<DockerContainer>;
764848
/** Update auto-start configuration for Docker containers */
765849
updateAutostartConfiguration: Scalars['Boolean']['output'];
766850
/** Update a container to the latest image */
@@ -775,6 +859,11 @@ export type DockerMutationsPauseArgs = {
775859
};
776860

777861

862+
export type DockerMutationsRemoveContainerArgs = {
863+
id: Scalars['PrefixedID']['input'];
864+
};
865+
866+
778867
export type DockerMutationsStartArgs = {
779868
id: Scalars['PrefixedID']['input'];
780869
};
@@ -824,6 +913,18 @@ export type DockerNetwork = Node & {
824913
scope: Scalars['String']['output'];
825914
};
826915

916+
export type DockerPortConflictContainer = {
917+
__typename?: 'DockerPortConflictContainer';
918+
id: Scalars['PrefixedID']['output'];
919+
name: Scalars['String']['output'];
920+
};
921+
922+
export type DockerPortConflicts = {
923+
__typename?: 'DockerPortConflicts';
924+
containerPorts: Array<DockerContainerPortConflict>;
925+
lanPorts: Array<DockerLanPortConflict>;
926+
};
927+
827928
export type DockerTemplateSyncResult = {
828929
__typename?: 'DockerTemplateSyncResult';
829930
errors: Array<Scalars['String']['output']>;
@@ -882,7 +983,6 @@ export type FlatOrganizerEntry = {
882983
childrenIds: Array<Scalars['String']['output']>;
883984
depth: Scalars['Float']['output'];
884985
hasChildren: Scalars['Boolean']['output'];
885-
icon?: Maybe<Scalars['String']['output']>;
886986
id: Scalars['String']['output'];
887987
meta?: Maybe<DockerContainer>;
888988
name: Scalars['String']['output'];
@@ -962,6 +1062,7 @@ export type InfoCpu = Node & {
9621062
manufacturer?: Maybe<Scalars['String']['output']>;
9631063
/** CPU model */
9641064
model?: Maybe<Scalars['String']['output']>;
1065+
packages: CpuPackages;
9651066
/** Number of physical processors */
9661067
processors?: Maybe<Scalars['Int']['output']>;
9671068
/** CPU revision */
@@ -978,6 +1079,8 @@ export type InfoCpu = Node & {
9781079
stepping?: Maybe<Scalars['Int']['output']>;
9791080
/** Number of CPU threads */
9801081
threads?: Maybe<Scalars['Int']['output']>;
1082+
/** Per-package array of core/thread pairs, e.g. [[[0,1],[2,3]], [[4,5],[6,7]]] */
1083+
topology: Array<Array<Array<Scalars['Int']['output']>>>;
9811084
/** CPU vendor */
9821085
vendor?: Maybe<Scalars['String']['output']>;
9831086
/** CPU voltage */
@@ -2161,6 +2264,7 @@ export type SsoSettings = Node & {
21612264
export type Subscription = {
21622265
__typename?: 'Subscription';
21632266
arraySubscription: UnraidArray;
2267+
dockerContainerStats: DockerContainerStats;
21642268
logFile: LogFileContent;
21652269
notificationAdded: Notification;
21662270
notificationsOverview: NotificationOverview;
@@ -2169,6 +2273,7 @@ export type Subscription = {
21692273
parityHistorySubscription: ParityCheck;
21702274
serversSubscription: Server;
21712275
systemMetricsCpu: CpuUtilization;
2276+
systemMetricsCpuTelemetry: CpuPackages;
21722277
systemMetricsMemory: MemoryUtilization;
21732278
upsUpdates: UpsDevice;
21742279
};

api/src/unraid-api/graph/resolvers/docker/organizer/docker-organizer.service.ts

Lines changed: 2 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@ import { Injectable, Logger } from '@nestjs/common';
33
import type { ContainerListOptions } from 'dockerode';
44

55
import { AppError } from '@app/core/errors/app-error.js';
6-
import { DockerTemplateIconService } from '@app/unraid-api/graph/resolvers/docker/docker-template-icon.service.js';
76
import { DockerContainer } from '@app/unraid-api/graph/resolvers/docker/docker.model.js';
87
import { DockerService } from '@app/unraid-api/graph/resolvers/docker/docker.service.js';
98
import { DockerOrganizerConfigService } from '@app/unraid-api/graph/resolvers/docker/organizer/docker-organizer-config.service.js';
@@ -52,8 +51,7 @@ export class DockerOrganizerService {
5251
private readonly logger = new Logger(DockerOrganizerService.name);
5352
constructor(
5453
private readonly dockerConfigService: DockerOrganizerConfigService,
55-
private readonly dockerService: DockerService,
56-
private readonly dockerTemplateIconService: DockerTemplateIconService
54+
private readonly dockerService: DockerService
5755
) {}
5856

5957
async getResources(
@@ -99,17 +97,7 @@ export class DockerOrganizerService {
9997
opts?: { skipCache?: boolean }
10098
): Promise<ResolvedOrganizerV1> {
10199
organizer ??= await this.syncAndGetOrganizer(opts);
102-
103-
const containers = Object.values(organizer.resources)
104-
.filter((r) => r.type === 'container')
105-
.map((r) => ({
106-
id: r.id,
107-
templatePath: (r as OrganizerContainerResource).meta?.templatePath,
108-
}));
109-
110-
const iconMap = await this.dockerTemplateIconService.getIconsForContainers(containers);
111-
112-
return resolveOrganizer(organizer, iconMap);
100+
return resolveOrganizer(organizer);
113101
}
114102

115103
async createFolder(params: {

api/src/unraid-api/organizer/organizer.model.ts

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -302,9 +302,4 @@ export class FlatOrganizerEntry {
302302
@ValidateNested()
303303
@Type(() => DockerContainer)
304304
meta?: DockerContainer;
305-
306-
@Field({ nullable: true })
307-
@IsOptional()
308-
@IsString()
309-
icon?: string;
310305
}

api/src/unraid-api/organizer/organizer.ts

Lines changed: 5 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -94,13 +94,11 @@ export function addMissingResourcesToView(
9494
*
9595
* @param view - The flat organizer view
9696
* @param resources - The collection of all available resources
97-
* @param iconMap - Optional map of resource IDs to icon URLs
9897
* @returns Array of enriched flat organizer entries with metadata
9998
*/
10099
export function enrichFlatEntries(
101100
view: OrganizerView,
102-
resources: OrganizerV1['resources'],
103-
iconMap?: Map<string, string>
101+
resources: OrganizerV1['resources']
104102
): FlatOrganizerEntry[] {
105103
const entries: FlatOrganizerEntry[] = [];
106104
const parentMap = new Map<string, string>();
@@ -141,16 +139,6 @@ export function enrichFlatEntries(
141139
name = (entry as OrganizerFolder).name;
142140
}
143141

144-
let icon: string | undefined;
145-
if (entry.type === 'folder') {
146-
icon = undefined;
147-
} else if (entry.type === 'ref') {
148-
const resource = resources[(entry as OrganizerResourceRef).target];
149-
if (resource && iconMap) {
150-
icon = iconMap.get(resource.id);
151-
}
152-
}
153-
154142
entries.push({
155143
id: entryId,
156144
type,
@@ -162,7 +150,6 @@ export function enrichFlatEntries(
162150
hasChildren: isFolder && children.length > 0,
163151
childrenIds: children,
164152
meta,
165-
icon,
166153
});
167154

168155
if (isFolder) {
@@ -184,15 +171,13 @@ export function enrichFlatEntries(
184171
*
185172
* @param view - The flat organizer view to resolve
186173
* @param resources - The collection of all available resources
187-
* @param iconMap - Optional map of resource IDs to icon URLs
188174
* @returns A resolved view with nested objects instead of ID references
189175
*/
190176
export function resolveOrganizerView(
191177
view: OrganizerView,
192-
resources: OrganizerV1['resources'],
193-
iconMap?: Map<string, string>
178+
resources: OrganizerV1['resources']
194179
): ResolvedOrganizerView {
195-
const flatEntries = enrichFlatEntries(view, resources, iconMap);
180+
const flatEntries = enrichFlatEntries(view, resources);
196181

197182
return {
198183
id: view.id,
@@ -208,17 +193,13 @@ export function resolveOrganizerView(
208193
* are replaced with actual objects for frontend convenience.
209194
*
210195
* @param organizer - The flat organizer structure to resolve
211-
* @param iconMap - Optional map of resource IDs to icon URLs
212196
* @returns A resolved organizer with nested objects instead of ID references
213197
*/
214-
export function resolveOrganizer(
215-
organizer: OrganizerV1,
216-
iconMap?: Map<string, string>
217-
): ResolvedOrganizerV1 {
198+
export function resolveOrganizer(organizer: OrganizerV1): ResolvedOrganizerV1 {
218199
const resolvedViews: ResolvedOrganizerView[] = [];
219200

220201
for (const [viewId, view] of Object.entries(organizer.views)) {
221-
resolvedViews.push(resolveOrganizerView(view, organizer.resources, iconMap));
202+
resolvedViews.push(resolveOrganizerView(view, organizer.resources));
222203
}
223204

224205
return {

web/src/components/Docker/docker-containers.query.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,6 @@ export const GET_DOCKER_CONTAINERS = gql`
6767
path
6868
hasChildren
6969
childrenIds
70-
icon
7170
meta {
7271
id
7372
names

0 commit comments

Comments
 (0)