mirror of
https://github.com/unraid/api.git
synced 2026-05-12 10:40:09 -05:00
fix: app can be linted (#639)
This commit is contained in:
@@ -0,0 +1,70 @@
|
||||
overwrite: true
|
||||
emitLegacyCommonJSImports: false
|
||||
verbose: true
|
||||
require:
|
||||
- ts-node/register
|
||||
config:
|
||||
namingConvention:
|
||||
typeNames: './fix-array-type.cjs'
|
||||
enumValues: 'change-case#upperCase'
|
||||
useTypeImports: true
|
||||
scalars:
|
||||
DateTime: string
|
||||
Long: number
|
||||
JSON: "{ [key: string]: any }"
|
||||
URL: URL
|
||||
Port: number
|
||||
UUID: string
|
||||
|
||||
generates:
|
||||
src/graphql/generated/client/:
|
||||
documents: './src/graphql/mothership/*.ts'
|
||||
schema:
|
||||
'${MOTHERSHIP_GRAPHQL_LINK}':
|
||||
headers:
|
||||
origin: 'https://forums.unraid.net'
|
||||
preset: client
|
||||
presetConfig:
|
||||
gqlTagName: graphql
|
||||
config:
|
||||
useTypeImports: true
|
||||
withObjectType: true
|
||||
plugins:
|
||||
- add: { content: '/* eslint-disable */' }
|
||||
src/graphql/generate/validators.ts:
|
||||
schema:
|
||||
'${MOTHERSHIP_GRAPHQL_LINK}':
|
||||
headers:
|
||||
origin: 'https://forums.unraid.net'
|
||||
plugins:
|
||||
- typescript-validation-schema
|
||||
- add: { content: '/* eslint-disable */'}
|
||||
config:
|
||||
importFrom: '@app/graphql/generated/client/graphql'
|
||||
strictScalars: false
|
||||
schema: 'zod'
|
||||
# Generate Types for the API Server
|
||||
src/graphql/generated/api/types.ts:
|
||||
schema:
|
||||
- './src/graphql/types.ts'
|
||||
- './src/graphql/schema/types/**/*.graphql'
|
||||
plugins:
|
||||
- typescript
|
||||
- typescript-resolvers
|
||||
- add: { content: '/* eslint-disable */' }
|
||||
config:
|
||||
contextType: '@app/graphql/schema/utils#Context'
|
||||
useIndexSignature: true
|
||||
# Generate Operations for any built in API Server Operations (ie report.ts)
|
||||
src/graphql/generated/api/operations.ts:
|
||||
documents: './src/graphql/client/api/*.ts'
|
||||
schema:
|
||||
- './src/graphql/types.ts'
|
||||
- './src/graphql/schema/types/**/*.graphql'
|
||||
preset: import-types
|
||||
presetConfig:
|
||||
typesPath: '@app/graphql/generated/api/types'
|
||||
plugins:
|
||||
- typescript-operations
|
||||
- typed-document-node
|
||||
- add: { content: '/* eslint-disable */' }
|
||||
@@ -1,5 +1,5 @@
|
||||
[api]
|
||||
version="3.1.0+948d5ecf"
|
||||
version="3.1.0+0baf1385"
|
||||
[local]
|
||||
[notifier]
|
||||
apikey="unnotify_30994bfaccf839c65bae75f7fa12dd5ee16e69389f754c3b98ed7d5"
|
||||
@@ -19,4 +19,4 @@ allowedOrigins="/var/run/unraid-notifications.sock, /var/run/unraid-php.sock, /v
|
||||
[upc]
|
||||
apikey="unupc_fab6ff6ffe51040595c6d9ffb63a353ba16cc2ad7d93f813a2e80a5810"
|
||||
[connectionStatus]
|
||||
minigraph="PRE_INIT"
|
||||
minigraph="CONNECTED"
|
||||
|
||||
@@ -83,14 +83,14 @@ test('Returns generated data', async () => {
|
||||
},
|
||||
"os": {
|
||||
"hostname": "Tower",
|
||||
"uptime": 2022-06-10T04:35:58.276Z,
|
||||
"uptime": "2022-06-10T04:35:58.276Z",
|
||||
},
|
||||
"services": [
|
||||
{
|
||||
"name": "unraid-api",
|
||||
"online": true,
|
||||
"uptime": {
|
||||
"timestamp": 2022-06-10T04:35:58.276Z,
|
||||
"timestamp": "2022-06-10T04:35:58.276Z",
|
||||
},
|
||||
"version": "THIS_WILL_BE_REPLACED_WHEN_BUILT",
|
||||
},
|
||||
@@ -98,7 +98,7 @@ test('Returns generated data', async () => {
|
||||
"name": "dynamic-remote-access",
|
||||
"online": false,
|
||||
"uptime": {
|
||||
"timestamp": 2022-06-10T04:35:58.276Z,
|
||||
"timestamp": "2022-06-10T04:35:58.276Z",
|
||||
},
|
||||
"version": "DISABLED",
|
||||
},
|
||||
|
||||
@@ -63,7 +63,7 @@ export const start = async () => {
|
||||
|
||||
// Spawn child
|
||||
// First arg is path (inside PKG), second arg is restart, stop, etc, rest is args to main argument
|
||||
const [path, _, ...rest] = process.argv.slice(1);
|
||||
const [path, , ...rest] = process.argv.slice(1);
|
||||
const replacedCommand = [path, 'start', ...rest];
|
||||
const child = spawn(process.execPath, replacedCommand, {
|
||||
// In the parent set the tracking environment variable
|
||||
|
||||
@@ -0,0 +1,93 @@
|
||||
import { getters, type RootState, store } from '@app/store';
|
||||
import { uniq } from 'lodash';
|
||||
import { getServerIps, getUrlForField } from '@app/graphql/resolvers/subscription/network';
|
||||
import { FileLoadStatus } from '@app/store/types';
|
||||
import { logger } from '../core';
|
||||
import { ENVIRONMENT, INTROSPECTION } from '@app/environment';
|
||||
|
||||
const getAllowedSocks = (): string[] => [
|
||||
// Notifier bridge
|
||||
'/var/run/unraid-notifications.sock',
|
||||
|
||||
// Unraid PHP scripts
|
||||
'/var/run/unraid-php.sock',
|
||||
|
||||
// CLI
|
||||
'/var/run/unraid-cli.sock',
|
||||
];
|
||||
|
||||
const getLocalAccessUrlsForServer = (state: RootState = store.getState()): string[] => {
|
||||
const { emhttp } = state;
|
||||
if (emhttp.status !== FileLoadStatus.LOADED) {
|
||||
return [];
|
||||
}
|
||||
|
||||
const { nginx } = emhttp;
|
||||
try {
|
||||
return [
|
||||
getUrlForField({ url: 'localhost', port: nginx.httpPort }).toString(),
|
||||
getUrlForField({ url: 'localhost', portSsl: nginx.httpsPort }).toString(),
|
||||
];
|
||||
} catch (error: unknown) {
|
||||
logger.debug('Caught error in getLocalAccessUrlsForServer: \n%o', error);
|
||||
return [];
|
||||
}
|
||||
};
|
||||
|
||||
const getRemoteAccessUrlsForAllowedOrigins = (state: RootState = store.getState()): string[] => {
|
||||
const { urls } = getServerIps(state);
|
||||
|
||||
if (urls) {
|
||||
return urls.reduce<string[]>((acc, curr) => {
|
||||
if (curr.ipv4 && curr.ipv6) {
|
||||
acc.push(curr.ipv4.toString());
|
||||
} else if (curr.ipv4) {
|
||||
acc.push(curr.ipv4.toString());
|
||||
} else if (curr.ipv6) {
|
||||
acc.push(curr.ipv6.toString());
|
||||
}
|
||||
|
||||
return acc;
|
||||
}, []);
|
||||
}
|
||||
|
||||
return [];
|
||||
};
|
||||
|
||||
const getExtraOrigins = (): string[] => {
|
||||
const { extraOrigins } = getters.config().api;
|
||||
if (extraOrigins) {
|
||||
return extraOrigins.split(', ').filter(origin => origin.startsWith('http://') || origin.startsWith('https://'));
|
||||
}
|
||||
|
||||
return [];
|
||||
};
|
||||
|
||||
const getConnectOrigins = () : string[] => {
|
||||
const connectMain = 'https://connect.myunraid.net';
|
||||
const connectStaging = 'https://staging.connect.myunraid.net';
|
||||
const connectDev = 'https://dev-my.myunraid.net:4000';
|
||||
|
||||
return [
|
||||
connectMain,
|
||||
connectStaging,
|
||||
connectDev
|
||||
]
|
||||
}
|
||||
|
||||
const getApolloSandbox = (): string[] => {
|
||||
if (INTROSPECTION || ENVIRONMENT === 'development') {
|
||||
return ['https://studio.apollographql.com'];
|
||||
}
|
||||
return [];
|
||||
}
|
||||
|
||||
export const getAllowedOrigins = (state: RootState = store.getState()): string[] => uniq([
|
||||
...getAllowedSocks(),
|
||||
...getLocalAccessUrlsForServer(),
|
||||
...getRemoteAccessUrlsForAllowedOrigins(state),
|
||||
...getExtraOrigins(),
|
||||
...getConnectOrigins(),
|
||||
...getApolloSandbox()
|
||||
|
||||
]).map(url => url.endsWith('/') ? url.slice(0, -1) : url);
|
||||
@@ -0,0 +1,4 @@
|
||||
import { uptime } from 'os';
|
||||
|
||||
// Get uptime on boot and convert to date
|
||||
export const bootTimestamp = new Date(new Date().getTime() - (uptime() * 1_000));
|
||||
@@ -1,7 +1,6 @@
|
||||
import { ConnectListAllDomainsFlags } from '@vmngr/libvirt';
|
||||
import { getHypervisor } from '@app/core/utils/vms/get-hypervisor';
|
||||
import display from '@app/graphql/resolvers/query/display';
|
||||
import { docker } from '@app/core/utils/clients/docker';
|
||||
import { getUnraidVersion } from '@app/common/dashboard/get-unraid-version';
|
||||
import { getArray } from '@app/common/dashboard/get-array';
|
||||
import { bootTimestamp } from '@app/common/dashboard/boot-timestamp';
|
||||
@@ -37,22 +36,7 @@ const getVmSummary = async (): Promise<DashboardInput['vms']> => {
|
||||
}
|
||||
};
|
||||
|
||||
/*
|
||||
const twoFactor = (): Dashboard['twoFactor'] => {
|
||||
const { isRemoteEnabled, isLocalEnabled } = checkTwoFactorEnabled();
|
||||
return {
|
||||
remote: {
|
||||
enabled: isRemoteEnabled,
|
||||
},
|
||||
local: {
|
||||
enabled: isLocalEnabled,
|
||||
},
|
||||
};
|
||||
}; */
|
||||
|
||||
const getDynamicRemoteAccessService = (): DashboardServiceInput | null => {
|
||||
const uptimeTimestamp = bootTimestamp.toISOString();
|
||||
|
||||
const { config, dynamicRemoteAccess } = store.getState();
|
||||
const enabledStatus = config.remote.dynamicRemoteAccessType;
|
||||
|
||||
@@ -61,23 +45,24 @@ const getDynamicRemoteAccessService = (): DashboardServiceInput | null => {
|
||||
online: enabledStatus !== DynamicRemoteAccessType.DISABLED,
|
||||
version: dynamicRemoteAccess.runningType,
|
||||
uptime: {
|
||||
timestamp: new Date(uptimeTimestamp),
|
||||
timestamp: bootTimestamp.toISOString(),
|
||||
},
|
||||
};
|
||||
};
|
||||
|
||||
const services = (): DashboardInput['services'] => {
|
||||
const uptimeTimestamp = bootTimestamp.toISOString();
|
||||
const dynamicRemoteAccess = getDynamicRemoteAccessService();
|
||||
return [{
|
||||
name: 'unraid-api',
|
||||
online: true,
|
||||
uptime: {
|
||||
timestamp: new Date(uptimeTimestamp),
|
||||
},
|
||||
version: API_VERSION,
|
||||
},
|
||||
...(dynamicRemoteAccess ? [dynamicRemoteAccess] : [])];
|
||||
return [
|
||||
{
|
||||
name: 'unraid-api',
|
||||
online: true,
|
||||
uptime: {
|
||||
timestamp: bootTimestamp.toISOString(),
|
||||
},
|
||||
version: API_VERSION,
|
||||
},
|
||||
...(dynamicRemoteAccess ? [dynamicRemoteAccess] : []),
|
||||
];
|
||||
};
|
||||
|
||||
const getData = async (): Promise<DashboardInput> => {
|
||||
@@ -99,7 +84,7 @@ const getData = async (): Promise<DashboardInput> => {
|
||||
},
|
||||
os: {
|
||||
hostname: emhttp.var.name,
|
||||
uptime: new Date(bootTimestamp.toISOString()),
|
||||
uptime: bootTimestamp.toISOString()
|
||||
},
|
||||
vms: await getVmSummary(),
|
||||
array: getArray(),
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
/* eslint-disable @typescript-eslint/no-unused-vars */
|
||||
import { getters } from '@app/store';
|
||||
import type { DiskShare, Share, UserShare } from '@app/core/types/states/share';
|
||||
import { type ArrayDisk } from '@app/graphql/generated/api/types';
|
||||
|
||||
@@ -0,0 +1,214 @@
|
||||
/* eslint-disable */
|
||||
import { z } from 'zod'
|
||||
import { AccessUrlInput, ArrayCapacityBytesInput, ArrayCapacityInput, ClientType, ConfigErrorState, DashboardAppsInput, DashboardArrayInput, DashboardCaseInput, DashboardConfigInput, DashboardDisplayInput, DashboardInput, DashboardOsInput, DashboardServiceInput, DashboardServiceUptimeInput, DashboardTwoFactorInput, DashboardTwoFactorLocalInput, DashboardTwoFactorRemoteInput, DashboardVarsInput, DashboardVersionsInput, DashboardVmsInput, EventType, Importance, KeyType, NetworkInput, NotificationInput, NotificationStatus, PingEventSource, RegistrationState, RemoteAccessEventActionType, RemoteAccessInput, RemoteGraphQLClientInput, RemoteGraphQLEventType, RemoteGraphQLServerInput, ServerStatus, URL_TYPE, UpdateType } from '@app/graphql/generated/client/graphql'
|
||||
|
||||
type Properties<T> = Required<{
|
||||
[K in keyof T]: z.ZodType<T[K], any, T[K]>;
|
||||
}>;
|
||||
|
||||
type definedNonNullAny = {};
|
||||
|
||||
export const isDefinedNonNullAny = (v: any): v is definedNonNullAny => v !== undefined && v !== null;
|
||||
|
||||
export const definedNonNullAnySchema = z.any().refine((v) => isDefinedNonNullAny(v));
|
||||
|
||||
export function AccessUrlInputSchema(): z.ZodObject<Properties<AccessUrlInput>> {
|
||||
return z.object<Properties<AccessUrlInput>>({
|
||||
ipv4: definedNonNullAnySchema.nullish(),
|
||||
ipv6: definedNonNullAnySchema.nullish(),
|
||||
name: z.string().nullish(),
|
||||
type: definedNonNullAnySchema
|
||||
})
|
||||
}
|
||||
|
||||
export function ArrayCapacityBytesInputSchema(): z.ZodObject<Properties<ArrayCapacityBytesInput>> {
|
||||
return z.object<Properties<ArrayCapacityBytesInput>>({
|
||||
free: z.number().nullish(),
|
||||
total: z.number().nullish(),
|
||||
used: z.number().nullish()
|
||||
})
|
||||
}
|
||||
|
||||
export function ArrayCapacityInputSchema(): z.ZodObject<Properties<ArrayCapacityInput>> {
|
||||
return z.object<Properties<ArrayCapacityInput>>({
|
||||
bytes: z.lazy(() => definedNonNullAnySchema.nullish())
|
||||
})
|
||||
}
|
||||
|
||||
export const ClientTypeSchema = z.nativeEnum(ClientType);
|
||||
|
||||
export const ConfigErrorStateSchema = z.nativeEnum(ConfigErrorState);
|
||||
|
||||
export function DashboardAppsInputSchema(): z.ZodObject<Properties<DashboardAppsInput>> {
|
||||
return z.object<Properties<DashboardAppsInput>>({
|
||||
installed: z.number(),
|
||||
started: z.number()
|
||||
})
|
||||
}
|
||||
|
||||
export function DashboardArrayInputSchema(): z.ZodObject<Properties<DashboardArrayInput>> {
|
||||
return z.object<Properties<DashboardArrayInput>>({
|
||||
capacity: z.lazy(() => definedNonNullAnySchema),
|
||||
state: z.string()
|
||||
})
|
||||
}
|
||||
|
||||
export function DashboardCaseInputSchema(): z.ZodObject<Properties<DashboardCaseInput>> {
|
||||
return z.object<Properties<DashboardCaseInput>>({
|
||||
base64: z.string(),
|
||||
error: z.string().nullish(),
|
||||
icon: z.string(),
|
||||
url: z.string()
|
||||
})
|
||||
}
|
||||
|
||||
export function DashboardConfigInputSchema(): z.ZodObject<Properties<DashboardConfigInput>> {
|
||||
return z.object<Properties<DashboardConfigInput>>({
|
||||
error: z.string().nullish(),
|
||||
valid: z.boolean()
|
||||
})
|
||||
}
|
||||
|
||||
export function DashboardDisplayInputSchema(): z.ZodObject<Properties<DashboardDisplayInput>> {
|
||||
return z.object<Properties<DashboardDisplayInput>>({
|
||||
case: z.lazy(() => definedNonNullAnySchema)
|
||||
})
|
||||
}
|
||||
|
||||
export function DashboardInputSchema(): z.ZodObject<Properties<DashboardInput>> {
|
||||
return z.object<Properties<DashboardInput>>({
|
||||
apps: z.lazy(() => definedNonNullAnySchema),
|
||||
array: z.lazy(() => definedNonNullAnySchema),
|
||||
config: z.lazy(() => definedNonNullAnySchema),
|
||||
display: z.lazy(() => definedNonNullAnySchema),
|
||||
os: z.lazy(() => definedNonNullAnySchema),
|
||||
services: z.array(z.lazy(() => definedNonNullAnySchema)),
|
||||
twoFactor: z.lazy(() => definedNonNullAnySchema.nullish()),
|
||||
vars: z.lazy(() => definedNonNullAnySchema),
|
||||
versions: z.lazy(() => definedNonNullAnySchema),
|
||||
vms: z.lazy(() => definedNonNullAnySchema)
|
||||
})
|
||||
}
|
||||
|
||||
export function DashboardOsInputSchema(): z.ZodObject<Properties<DashboardOsInput>> {
|
||||
return z.object<Properties<DashboardOsInput>>({
|
||||
hostname: z.string(),
|
||||
uptime: z.string()
|
||||
})
|
||||
}
|
||||
|
||||
export function DashboardServiceInputSchema(): z.ZodObject<Properties<DashboardServiceInput>> {
|
||||
return z.object<Properties<DashboardServiceInput>>({
|
||||
name: z.string(),
|
||||
online: z.boolean(),
|
||||
uptime: z.lazy(() => definedNonNullAnySchema.nullish()),
|
||||
version: z.string()
|
||||
})
|
||||
}
|
||||
|
||||
export function DashboardServiceUptimeInputSchema(): z.ZodObject<Properties<DashboardServiceUptimeInput>> {
|
||||
return z.object<Properties<DashboardServiceUptimeInput>>({
|
||||
timestamp: z.string()
|
||||
})
|
||||
}
|
||||
|
||||
export function DashboardTwoFactorInputSchema(): z.ZodObject<Properties<DashboardTwoFactorInput>> {
|
||||
return z.object<Properties<DashboardTwoFactorInput>>({
|
||||
local: z.lazy(() => definedNonNullAnySchema),
|
||||
remote: z.lazy(() => definedNonNullAnySchema)
|
||||
})
|
||||
}
|
||||
|
||||
export function DashboardTwoFactorLocalInputSchema(): z.ZodObject<Properties<DashboardTwoFactorLocalInput>> {
|
||||
return z.object<Properties<DashboardTwoFactorLocalInput>>({
|
||||
enabled: z.boolean()
|
||||
})
|
||||
}
|
||||
|
||||
export function DashboardTwoFactorRemoteInputSchema(): z.ZodObject<Properties<DashboardTwoFactorRemoteInput>> {
|
||||
return z.object<Properties<DashboardTwoFactorRemoteInput>>({
|
||||
enabled: z.boolean()
|
||||
})
|
||||
}
|
||||
|
||||
export function DashboardVarsInputSchema(): z.ZodObject<Properties<DashboardVarsInput>> {
|
||||
return z.object<Properties<DashboardVarsInput>>({
|
||||
flashGuid: z.string(),
|
||||
regState: z.string(),
|
||||
regTy: z.string()
|
||||
})
|
||||
}
|
||||
|
||||
export function DashboardVersionsInputSchema(): z.ZodObject<Properties<DashboardVersionsInput>> {
|
||||
return z.object<Properties<DashboardVersionsInput>>({
|
||||
unraid: z.string()
|
||||
})
|
||||
}
|
||||
|
||||
export function DashboardVmsInputSchema(): z.ZodObject<Properties<DashboardVmsInput>> {
|
||||
return z.object<Properties<DashboardVmsInput>>({
|
||||
installed: z.number(),
|
||||
started: z.number()
|
||||
})
|
||||
}
|
||||
|
||||
export const EventTypeSchema = z.nativeEnum(EventType);
|
||||
|
||||
export const ImportanceSchema = z.nativeEnum(Importance);
|
||||
|
||||
export const KeyTypeSchema = z.nativeEnum(KeyType);
|
||||
|
||||
export function NetworkInputSchema(): z.ZodObject<Properties<NetworkInput>> {
|
||||
return z.object<Properties<NetworkInput>>({
|
||||
accessUrls: z.array(z.lazy(() => definedNonNullAnySchema))
|
||||
})
|
||||
}
|
||||
|
||||
export function NotificationInputSchema(): z.ZodObject<Properties<NotificationInput>> {
|
||||
return z.object<Properties<NotificationInput>>({
|
||||
description: z.string().nullish(),
|
||||
importance: definedNonNullAnySchema,
|
||||
link: z.string().nullish(),
|
||||
subject: z.string().nullish(),
|
||||
title: z.string().nullish()
|
||||
})
|
||||
}
|
||||
|
||||
export const NotificationStatusSchema = z.nativeEnum(NotificationStatus);
|
||||
|
||||
export const PingEventSourceSchema = z.nativeEnum(PingEventSource);
|
||||
|
||||
export const RegistrationStateSchema = z.nativeEnum(RegistrationState);
|
||||
|
||||
export const RemoteAccessEventActionTypeSchema = z.nativeEnum(RemoteAccessEventActionType);
|
||||
|
||||
export function RemoteAccessInputSchema(): z.ZodObject<Properties<RemoteAccessInput>> {
|
||||
return z.object<Properties<RemoteAccessInput>>({
|
||||
apiKey: z.string(),
|
||||
type: definedNonNullAnySchema,
|
||||
url: z.lazy(() => definedNonNullAnySchema.nullish())
|
||||
})
|
||||
}
|
||||
|
||||
export function RemoteGraphQLClientInputSchema(): z.ZodObject<Properties<RemoteGraphQLClientInput>> {
|
||||
return z.object<Properties<RemoteGraphQLClientInput>>({
|
||||
apiKey: z.string(),
|
||||
body: z.string()
|
||||
})
|
||||
}
|
||||
|
||||
export const RemoteGraphQLEventTypeSchema = z.nativeEnum(RemoteGraphQLEventType);
|
||||
|
||||
export function RemoteGraphQLServerInputSchema(): z.ZodObject<Properties<RemoteGraphQLServerInput>> {
|
||||
return z.object<Properties<RemoteGraphQLServerInput>>({
|
||||
body: z.string(),
|
||||
sha256: z.string(),
|
||||
type: definedNonNullAnySchema
|
||||
})
|
||||
}
|
||||
|
||||
export const ServerStatusSchema = z.nativeEnum(ServerStatus);
|
||||
|
||||
export const URL_TYPESchema = z.nativeEnum(URL_TYPE);
|
||||
|
||||
export const UpdateTypeSchema = z.nativeEnum(UpdateType);
|
||||
@@ -14,7 +14,7 @@ export type Scalars = {
|
||||
Boolean: boolean;
|
||||
Int: number;
|
||||
Float: number;
|
||||
DateTime: Date;
|
||||
DateTime: string;
|
||||
JSON: { [key: string]: any };
|
||||
Long: number;
|
||||
UUID: string;
|
||||
|
||||
@@ -0,0 +1,770 @@
|
||||
/* eslint-disable */
|
||||
import type { TypedDocumentNode as DocumentNode } from '@graphql-typed-document-node/core';
|
||||
export type Maybe<T> = T | null;
|
||||
export type InputMaybe<T> = Maybe<T>;
|
||||
export type Exact<T extends { [key: string]: unknown }> = { [K in keyof T]: T[K] };
|
||||
export type MakeOptional<T, K extends keyof T> = Omit<T, K> & { [SubKey in K]?: Maybe<T[SubKey]> };
|
||||
export type MakeMaybe<T, K extends keyof T> = Omit<T, K> & { [SubKey in K]: Maybe<T[SubKey]> };
|
||||
/** All built-in and custom scalars, mapped to their actual values */
|
||||
export type Scalars = {
|
||||
ID: string;
|
||||
String: string;
|
||||
Boolean: boolean;
|
||||
Int: number;
|
||||
Float: number;
|
||||
/** A date-time string at UTC, such as 2007-12-03T10:15:30Z, compliant with the `date-time` format outlined in section 5.6 of the RFC 3339 profile of the ISO 8601 standard for representation of dates and times using the Gregorian calendar. */
|
||||
DateTime: string;
|
||||
/** A field whose value is a IPv4 address: https://en.wikipedia.org/wiki/IPv4. */
|
||||
IPv4: any;
|
||||
/** A field whose value is a IPv6 address: https://en.wikipedia.org/wiki/IPv6. */
|
||||
IPv6: any;
|
||||
/** The `JSON` scalar type represents JSON values as specified by [ECMA-404](http://www.ecma-international.org/publications/files/ECMA-ST/ECMA-404.pdf). */
|
||||
JSON: { [key: string]: any };
|
||||
/** The `Long` scalar type represents 52-bit integers */
|
||||
Long: number;
|
||||
/** A field whose value is a valid TCP port within the range of 0 to 65535: https://en.wikipedia.org/wiki/Transmission_Control_Protocol#TCP_ports */
|
||||
Port: number;
|
||||
/** A field whose value conforms to the standard URL format as specified in RFC3986: https://www.ietf.org/rfc/rfc3986.txt. */
|
||||
URL: URL;
|
||||
};
|
||||
|
||||
export type AccessUrl = {
|
||||
__typename?: 'AccessUrl';
|
||||
ipv4?: Maybe<Scalars['URL']>;
|
||||
ipv6?: Maybe<Scalars['URL']>;
|
||||
name?: Maybe<Scalars['String']>;
|
||||
type: URL_TYPE;
|
||||
};
|
||||
|
||||
export type AccessUrlInput = {
|
||||
ipv4?: InputMaybe<Scalars['URL']>;
|
||||
ipv6?: InputMaybe<Scalars['URL']>;
|
||||
name?: InputMaybe<Scalars['String']>;
|
||||
type: URL_TYPE;
|
||||
};
|
||||
|
||||
export type ArrayCapacity = {
|
||||
__typename?: 'ArrayCapacity';
|
||||
bytes?: Maybe<ArrayCapacityBytes>;
|
||||
};
|
||||
|
||||
export type ArrayCapacityBytes = {
|
||||
__typename?: 'ArrayCapacityBytes';
|
||||
free?: Maybe<Scalars['Long']>;
|
||||
total?: Maybe<Scalars['Long']>;
|
||||
used?: Maybe<Scalars['Long']>;
|
||||
};
|
||||
|
||||
export type ArrayCapacityBytesInput = {
|
||||
free?: InputMaybe<Scalars['Long']>;
|
||||
total?: InputMaybe<Scalars['Long']>;
|
||||
used?: InputMaybe<Scalars['Long']>;
|
||||
};
|
||||
|
||||
export type ArrayCapacityInput = {
|
||||
bytes?: InputMaybe<ArrayCapacityBytesInput>;
|
||||
};
|
||||
|
||||
export type ClientConnectedEvent = {
|
||||
__typename?: 'ClientConnectedEvent';
|
||||
data: ClientConnectionEventData;
|
||||
type: EventType;
|
||||
};
|
||||
|
||||
export type ClientConnectionEventData = {
|
||||
__typename?: 'ClientConnectionEventData';
|
||||
apiKey: Scalars['String'];
|
||||
type: ClientType;
|
||||
version: Scalars['String'];
|
||||
};
|
||||
|
||||
export type ClientDisconnectedEvent = {
|
||||
__typename?: 'ClientDisconnectedEvent';
|
||||
data: ClientConnectionEventData;
|
||||
type: EventType;
|
||||
};
|
||||
|
||||
export type ClientPingEvent = {
|
||||
__typename?: 'ClientPingEvent';
|
||||
data: PingEventData;
|
||||
type: EventType;
|
||||
};
|
||||
|
||||
export enum ClientType {
|
||||
API = 'API',
|
||||
DASHBOARD = 'DASHBOARD'
|
||||
}
|
||||
|
||||
export type Config = {
|
||||
__typename?: 'Config';
|
||||
error?: Maybe<ConfigErrorState>;
|
||||
valid?: Maybe<Scalars['Boolean']>;
|
||||
};
|
||||
|
||||
export enum ConfigErrorState {
|
||||
INVALID = 'INVALID',
|
||||
NO_KEY_SERVER = 'NO_KEY_SERVER',
|
||||
UNKNOWN_ERROR = 'UNKNOWN_ERROR',
|
||||
WITHDRAWN = 'WITHDRAWN'
|
||||
}
|
||||
|
||||
export type Dashboard = {
|
||||
__typename?: 'Dashboard';
|
||||
apps?: Maybe<DashboardApps>;
|
||||
array?: Maybe<DashboardArray>;
|
||||
config?: Maybe<DashboardConfig>;
|
||||
display?: Maybe<DashboardDisplay>;
|
||||
id: Scalars['ID'];
|
||||
lastPublish?: Maybe<Scalars['DateTime']>;
|
||||
network?: Maybe<Network>;
|
||||
online?: Maybe<Scalars['Boolean']>;
|
||||
os?: Maybe<DashboardOs>;
|
||||
services?: Maybe<Array<Maybe<DashboardService>>>;
|
||||
twoFactor?: Maybe<DashboardTwoFactor>;
|
||||
vars?: Maybe<DashboardVars>;
|
||||
versions?: Maybe<DashboardVersions>;
|
||||
vms?: Maybe<DashboardVms>;
|
||||
};
|
||||
|
||||
export type DashboardApps = {
|
||||
__typename?: 'DashboardApps';
|
||||
installed?: Maybe<Scalars['Int']>;
|
||||
started?: Maybe<Scalars['Int']>;
|
||||
};
|
||||
|
||||
export type DashboardAppsInput = {
|
||||
installed: Scalars['Int'];
|
||||
started: Scalars['Int'];
|
||||
};
|
||||
|
||||
export type DashboardArray = {
|
||||
__typename?: 'DashboardArray';
|
||||
/** Current array capacity */
|
||||
capacity?: Maybe<ArrayCapacity>;
|
||||
/** Current array state */
|
||||
state?: Maybe<Scalars['String']>;
|
||||
};
|
||||
|
||||
export type DashboardArrayInput = {
|
||||
/** Current array capacity */
|
||||
capacity: ArrayCapacityInput;
|
||||
/** Current array state */
|
||||
state: Scalars['String'];
|
||||
};
|
||||
|
||||
export type DashboardCase = {
|
||||
__typename?: 'DashboardCase';
|
||||
base64?: Maybe<Scalars['String']>;
|
||||
error?: Maybe<Scalars['String']>;
|
||||
icon?: Maybe<Scalars['String']>;
|
||||
url?: Maybe<Scalars['String']>;
|
||||
};
|
||||
|
||||
export type DashboardCaseInput = {
|
||||
base64: Scalars['String'];
|
||||
error?: InputMaybe<Scalars['String']>;
|
||||
icon: Scalars['String'];
|
||||
url: Scalars['String'];
|
||||
};
|
||||
|
||||
export type DashboardConfig = {
|
||||
__typename?: 'DashboardConfig';
|
||||
error?: Maybe<Scalars['String']>;
|
||||
valid?: Maybe<Scalars['Boolean']>;
|
||||
};
|
||||
|
||||
export type DashboardConfigInput = {
|
||||
error?: InputMaybe<Scalars['String']>;
|
||||
valid: Scalars['Boolean'];
|
||||
};
|
||||
|
||||
export type DashboardDisplay = {
|
||||
__typename?: 'DashboardDisplay';
|
||||
case?: Maybe<DashboardCase>;
|
||||
};
|
||||
|
||||
export type DashboardDisplayInput = {
|
||||
case: DashboardCaseInput;
|
||||
};
|
||||
|
||||
export type DashboardInput = {
|
||||
apps: DashboardAppsInput;
|
||||
array: DashboardArrayInput;
|
||||
config: DashboardConfigInput;
|
||||
display: DashboardDisplayInput;
|
||||
os: DashboardOsInput;
|
||||
services: Array<DashboardServiceInput>;
|
||||
twoFactor?: InputMaybe<DashboardTwoFactorInput>;
|
||||
vars: DashboardVarsInput;
|
||||
versions: DashboardVersionsInput;
|
||||
vms: DashboardVmsInput;
|
||||
};
|
||||
|
||||
export type DashboardOs = {
|
||||
__typename?: 'DashboardOs';
|
||||
hostname?: Maybe<Scalars['String']>;
|
||||
uptime?: Maybe<Scalars['DateTime']>;
|
||||
};
|
||||
|
||||
export type DashboardOsInput = {
|
||||
hostname: Scalars['String'];
|
||||
uptime: Scalars['DateTime'];
|
||||
};
|
||||
|
||||
export type DashboardService = {
|
||||
__typename?: 'DashboardService';
|
||||
name?: Maybe<Scalars['String']>;
|
||||
online?: Maybe<Scalars['Boolean']>;
|
||||
uptime?: Maybe<DashboardServiceUptime>;
|
||||
version?: Maybe<Scalars['String']>;
|
||||
};
|
||||
|
||||
export type DashboardServiceInput = {
|
||||
name: Scalars['String'];
|
||||
online: Scalars['Boolean'];
|
||||
uptime?: InputMaybe<DashboardServiceUptimeInput>;
|
||||
version: Scalars['String'];
|
||||
};
|
||||
|
||||
export type DashboardServiceUptime = {
|
||||
__typename?: 'DashboardServiceUptime';
|
||||
timestamp?: Maybe<Scalars['DateTime']>;
|
||||
};
|
||||
|
||||
export type DashboardServiceUptimeInput = {
|
||||
timestamp: Scalars['DateTime'];
|
||||
};
|
||||
|
||||
export type DashboardTwoFactor = {
|
||||
__typename?: 'DashboardTwoFactor';
|
||||
local?: Maybe<DashboardTwoFactorLocal>;
|
||||
remote?: Maybe<DashboardTwoFactorRemote>;
|
||||
};
|
||||
|
||||
export type DashboardTwoFactorInput = {
|
||||
local: DashboardTwoFactorLocalInput;
|
||||
remote: DashboardTwoFactorRemoteInput;
|
||||
};
|
||||
|
||||
export type DashboardTwoFactorLocal = {
|
||||
__typename?: 'DashboardTwoFactorLocal';
|
||||
enabled?: Maybe<Scalars['Boolean']>;
|
||||
};
|
||||
|
||||
export type DashboardTwoFactorLocalInput = {
|
||||
enabled: Scalars['Boolean'];
|
||||
};
|
||||
|
||||
export type DashboardTwoFactorRemote = {
|
||||
__typename?: 'DashboardTwoFactorRemote';
|
||||
enabled?: Maybe<Scalars['Boolean']>;
|
||||
};
|
||||
|
||||
export type DashboardTwoFactorRemoteInput = {
|
||||
enabled: Scalars['Boolean'];
|
||||
};
|
||||
|
||||
export type DashboardVars = {
|
||||
__typename?: 'DashboardVars';
|
||||
flashGuid?: Maybe<Scalars['String']>;
|
||||
regState?: Maybe<Scalars['String']>;
|
||||
regTy?: Maybe<Scalars['String']>;
|
||||
};
|
||||
|
||||
export type DashboardVarsInput = {
|
||||
flashGuid: Scalars['String'];
|
||||
regState: Scalars['String'];
|
||||
regTy: Scalars['String'];
|
||||
};
|
||||
|
||||
export type DashboardVersions = {
|
||||
__typename?: 'DashboardVersions';
|
||||
unraid?: Maybe<Scalars['String']>;
|
||||
};
|
||||
|
||||
export type DashboardVersionsInput = {
|
||||
unraid: Scalars['String'];
|
||||
};
|
||||
|
||||
export type DashboardVms = {
|
||||
__typename?: 'DashboardVms';
|
||||
installed?: Maybe<Scalars['Int']>;
|
||||
started?: Maybe<Scalars['Int']>;
|
||||
};
|
||||
|
||||
export type DashboardVmsInput = {
|
||||
installed: Scalars['Int'];
|
||||
started: Scalars['Int'];
|
||||
};
|
||||
|
||||
export type Event = ClientConnectedEvent | ClientDisconnectedEvent | ClientPingEvent | RemoteAccessEvent | RemoteGraphQLEvent | UpdateEvent;
|
||||
|
||||
export enum EventType {
|
||||
CLIENT_CONNECTED_EVENT = 'CLIENT_CONNECTED_EVENT',
|
||||
CLIENT_DISCONNECTED_EVENT = 'CLIENT_DISCONNECTED_EVENT',
|
||||
CLIENT_PING_EVENT = 'CLIENT_PING_EVENT',
|
||||
REMOTE_ACCESS_EVENT = 'REMOTE_ACCESS_EVENT',
|
||||
REMOTE_GRAPHQL_EVENT = 'REMOTE_GRAPHQL_EVENT',
|
||||
UPDATE_EVENT = 'UPDATE_EVENT'
|
||||
}
|
||||
|
||||
export type FullServerDetails = {
|
||||
__typename?: 'FullServerDetails';
|
||||
apiConnectedCount?: Maybe<Scalars['Int']>;
|
||||
apiVersion?: Maybe<Scalars['String']>;
|
||||
connectionTimestamp?: Maybe<Scalars['String']>;
|
||||
dashboard?: Maybe<Dashboard>;
|
||||
lastPublish?: Maybe<Scalars['String']>;
|
||||
network?: Maybe<Network>;
|
||||
online?: Maybe<Scalars['Boolean']>;
|
||||
};
|
||||
|
||||
export enum Importance {
|
||||
ALERT = 'ALERT',
|
||||
INFO = 'INFO',
|
||||
WARNING = 'WARNING'
|
||||
}
|
||||
|
||||
export enum KeyType {
|
||||
BASIC = 'BASIC',
|
||||
PLUS = 'PLUS',
|
||||
PRO = 'PRO',
|
||||
TRIAL = 'TRIAL'
|
||||
}
|
||||
|
||||
export type KsServerDetails = {
|
||||
__typename?: 'KsServerDetails';
|
||||
accessLabel: Scalars['String'];
|
||||
accessUrl: Scalars['String'];
|
||||
apiKey?: Maybe<Scalars['String']>;
|
||||
description: Scalars['String'];
|
||||
dnsHash: Scalars['String'];
|
||||
flashBackupDate?: Maybe<Scalars['Int']>;
|
||||
flashBackupUrl: Scalars['String'];
|
||||
flashProduct: Scalars['String'];
|
||||
flashVendor: Scalars['String'];
|
||||
guid: Scalars['String'];
|
||||
ipsId: Scalars['String'];
|
||||
keyType: KeyType;
|
||||
licenseKey: Scalars['String'];
|
||||
name: Scalars['String'];
|
||||
plgVersion?: Maybe<Scalars['String']>;
|
||||
signedIn: Scalars['Boolean'];
|
||||
};
|
||||
|
||||
export type LegacyService = {
|
||||
__typename?: 'LegacyService';
|
||||
name?: Maybe<Scalars['String']>;
|
||||
online?: Maybe<Scalars['Boolean']>;
|
||||
uptime?: Maybe<Scalars['Int']>;
|
||||
version?: Maybe<Scalars['String']>;
|
||||
};
|
||||
|
||||
export type Mutation = {
|
||||
__typename?: 'Mutation';
|
||||
remoteGraphQLResponse: Scalars['Boolean'];
|
||||
remoteMutation: Scalars['String'];
|
||||
remoteSession?: Maybe<Scalars['Boolean']>;
|
||||
sendNotification?: Maybe<Notification>;
|
||||
sendPing?: Maybe<Scalars['Boolean']>;
|
||||
updateDashboard: Dashboard;
|
||||
updateNetwork: Network;
|
||||
};
|
||||
|
||||
|
||||
export type MutationremoteGraphQLResponseArgs = {
|
||||
input: RemoteGraphQLServerInput;
|
||||
};
|
||||
|
||||
|
||||
export type MutationremoteMutationArgs = {
|
||||
input: RemoteGraphQLClientInput;
|
||||
};
|
||||
|
||||
|
||||
export type MutationremoteSessionArgs = {
|
||||
remoteAccess: RemoteAccessInput;
|
||||
};
|
||||
|
||||
|
||||
export type MutationsendNotificationArgs = {
|
||||
notification: NotificationInput;
|
||||
};
|
||||
|
||||
|
||||
export type MutationupdateDashboardArgs = {
|
||||
data: DashboardInput;
|
||||
};
|
||||
|
||||
|
||||
export type MutationupdateNetworkArgs = {
|
||||
data: NetworkInput;
|
||||
};
|
||||
|
||||
export type Network = {
|
||||
__typename?: 'Network';
|
||||
accessUrls?: Maybe<Array<AccessUrl>>;
|
||||
};
|
||||
|
||||
export type NetworkInput = {
|
||||
accessUrls: Array<AccessUrlInput>;
|
||||
};
|
||||
|
||||
export type Notification = {
|
||||
__typename?: 'Notification';
|
||||
description?: Maybe<Scalars['String']>;
|
||||
importance?: Maybe<Importance>;
|
||||
link?: Maybe<Scalars['String']>;
|
||||
status: NotificationStatus;
|
||||
subject?: Maybe<Scalars['String']>;
|
||||
title?: Maybe<Scalars['String']>;
|
||||
};
|
||||
|
||||
export type NotificationInput = {
|
||||
description?: InputMaybe<Scalars['String']>;
|
||||
importance: Importance;
|
||||
link?: InputMaybe<Scalars['String']>;
|
||||
subject?: InputMaybe<Scalars['String']>;
|
||||
title?: InputMaybe<Scalars['String']>;
|
||||
};
|
||||
|
||||
export enum NotificationStatus {
|
||||
FAILED_TO_SEND = 'FAILED_TO_SEND',
|
||||
NOT_FOUND = 'NOT_FOUND',
|
||||
PENDING = 'PENDING',
|
||||
SENT = 'SENT'
|
||||
}
|
||||
|
||||
export type PingEvent = {
|
||||
__typename?: 'PingEvent';
|
||||
data?: Maybe<Scalars['String']>;
|
||||
type: EventType;
|
||||
};
|
||||
|
||||
export type PingEventData = {
|
||||
__typename?: 'PingEventData';
|
||||
source: PingEventSource;
|
||||
};
|
||||
|
||||
export enum PingEventSource {
|
||||
API = 'API',
|
||||
MOTHERSHIP = 'MOTHERSHIP'
|
||||
}
|
||||
|
||||
export type ProfileModel = {
|
||||
__typename?: 'ProfileModel';
|
||||
avatar?: Maybe<Scalars['String']>;
|
||||
url?: Maybe<Scalars['String']>;
|
||||
userId?: Maybe<Scalars['ID']>;
|
||||
username?: Maybe<Scalars['String']>;
|
||||
};
|
||||
|
||||
export type Query = {
|
||||
__typename?: 'Query';
|
||||
apiVersion?: Maybe<Scalars['String']>;
|
||||
dashboard?: Maybe<Dashboard>;
|
||||
ksServers: Array<KsServerDetails>;
|
||||
online?: Maybe<Scalars['Boolean']>;
|
||||
remoteQuery: Scalars['String'];
|
||||
servers: Array<Maybe<Server>>;
|
||||
status?: Maybe<ServerStatus>;
|
||||
};
|
||||
|
||||
|
||||
export type QuerydashboardArgs = {
|
||||
id: Scalars['String'];
|
||||
};
|
||||
|
||||
|
||||
export type QueryremoteQueryArgs = {
|
||||
input: RemoteGraphQLClientInput;
|
||||
};
|
||||
|
||||
export enum RegistrationState {
|
||||
/** Basic */
|
||||
BASIC = 'BASIC',
|
||||
/** BLACKLISTED */
|
||||
EBLACKLISTED = 'EBLACKLISTED',
|
||||
/** BLACKLISTED */
|
||||
EBLACKLISTED1 = 'EBLACKLISTED1',
|
||||
/** BLACKLISTED */
|
||||
EBLACKLISTED2 = 'EBLACKLISTED2',
|
||||
/** Trial Expired */
|
||||
EEXPIRED = 'EEXPIRED',
|
||||
/** GUID Error */
|
||||
EGUID = 'EGUID',
|
||||
/** Multiple License Keys Present */
|
||||
EGUID1 = 'EGUID1',
|
||||
/** Trial Requires Internet Connection */
|
||||
ENOCONN = 'ENOCONN',
|
||||
/** No Flash */
|
||||
ENOFLASH = 'ENOFLASH',
|
||||
ENOFLASH1 = 'ENOFLASH1',
|
||||
ENOFLASH2 = 'ENOFLASH2',
|
||||
ENOFLASH3 = 'ENOFLASH3',
|
||||
ENOFLASH4 = 'ENOFLASH4',
|
||||
ENOFLASH5 = 'ENOFLASH5',
|
||||
ENOFLASH6 = 'ENOFLASH6',
|
||||
ENOFLASH7 = 'ENOFLASH7',
|
||||
/** No Keyfile */
|
||||
ENOKEYFILE = 'ENOKEYFILE',
|
||||
/** No Keyfile */
|
||||
ENOKEYFILE1 = 'ENOKEYFILE1',
|
||||
/** Missing key file */
|
||||
ENOKEYFILE2 = 'ENOKEYFILE2',
|
||||
/** Invalid installation */
|
||||
ETRIAL = 'ETRIAL',
|
||||
/** Plus */
|
||||
PLUS = 'PLUS',
|
||||
/** Pro */
|
||||
PRO = 'PRO',
|
||||
/** Trial */
|
||||
TRIAL = 'TRIAL'
|
||||
}
|
||||
|
||||
export type RemoteAccessEvent = {
|
||||
__typename?: 'RemoteAccessEvent';
|
||||
data: RemoteAccessEventData;
|
||||
type: EventType;
|
||||
};
|
||||
|
||||
/** Defines whether remote access event is the initiation (from connect) or the response (from the server) */
|
||||
export enum RemoteAccessEventActionType {
|
||||
ACK = 'ACK',
|
||||
END = 'END',
|
||||
INIT = 'INIT',
|
||||
PING = 'PING'
|
||||
}
|
||||
|
||||
export type RemoteAccessEventData = {
|
||||
__typename?: 'RemoteAccessEventData';
|
||||
apiKey: Scalars['String'];
|
||||
type: RemoteAccessEventActionType;
|
||||
url?: Maybe<AccessUrl>;
|
||||
};
|
||||
|
||||
export type RemoteAccessInput = {
|
||||
apiKey: Scalars['String'];
|
||||
type: RemoteAccessEventActionType;
|
||||
url?: InputMaybe<AccessUrlInput>;
|
||||
};
|
||||
|
||||
export type RemoteGraphQLClientInput = {
|
||||
apiKey: Scalars['String'];
|
||||
body: Scalars['String'];
|
||||
};
|
||||
|
||||
export type RemoteGraphQLEvent = {
|
||||
__typename?: 'RemoteGraphQLEvent';
|
||||
data: RemoteGraphQLEventData;
|
||||
type: EventType;
|
||||
};
|
||||
|
||||
export type RemoteGraphQLEventData = {
|
||||
__typename?: 'RemoteGraphQLEventData';
|
||||
/** Contains mutation / subscription / query data in the form of body: JSON, variables: JSON */
|
||||
body: Scalars['String'];
|
||||
/** sha256 hash of the body */
|
||||
sha256: Scalars['String'];
|
||||
type: RemoteGraphQLEventType;
|
||||
};
|
||||
|
||||
export enum RemoteGraphQLEventType {
|
||||
REMOTE_MUTATION_EVENT = 'REMOTE_MUTATION_EVENT',
|
||||
REMOTE_QUERY_EVENT = 'REMOTE_QUERY_EVENT',
|
||||
REMOTE_SUBSCRIPTION_EVENT = 'REMOTE_SUBSCRIPTION_EVENT',
|
||||
REMOTE_SUBSCRIPTION_EVENT_PING = 'REMOTE_SUBSCRIPTION_EVENT_PING'
|
||||
}
|
||||
|
||||
export type RemoteGraphQLServerInput = {
|
||||
/** Body - contains an object containing data: (GQL response data) or errors: (GQL Errors) */
|
||||
body: Scalars['String'];
|
||||
/** sha256 hash of the body */
|
||||
sha256: Scalars['String'];
|
||||
type: RemoteGraphQLEventType;
|
||||
};
|
||||
|
||||
export type Server = {
|
||||
__typename?: 'Server';
|
||||
apikey?: Maybe<Scalars['String']>;
|
||||
guid?: Maybe<Scalars['String']>;
|
||||
lanip?: Maybe<Scalars['String']>;
|
||||
localurl?: Maybe<Scalars['String']>;
|
||||
name?: Maybe<Scalars['String']>;
|
||||
owner?: Maybe<ProfileModel>;
|
||||
remoteurl?: Maybe<Scalars['String']>;
|
||||
status?: Maybe<ServerStatus>;
|
||||
wanip?: Maybe<Scalars['String']>;
|
||||
};
|
||||
|
||||
/** Defines server fields that have a TTL on them, for example last ping */
|
||||
export type ServerFieldsWithTtl = {
|
||||
__typename?: 'ServerFieldsWithTtl';
|
||||
lastPing?: Maybe<Scalars['String']>;
|
||||
};
|
||||
|
||||
export type ServerModel = {
|
||||
apikey: Scalars['String'];
|
||||
guid: Scalars['String'];
|
||||
lanip: Scalars['String'];
|
||||
localurl: Scalars['String'];
|
||||
name: Scalars['String'];
|
||||
remoteurl: Scalars['String'];
|
||||
wanip: Scalars['String'];
|
||||
};
|
||||
|
||||
export enum ServerStatus {
|
||||
NEVER_CONNECTED = 'never_connected',
|
||||
OFFLINE = 'offline',
|
||||
ONLINE = 'online'
|
||||
}
|
||||
|
||||
export type Service = {
|
||||
__typename?: 'Service';
|
||||
name?: Maybe<Scalars['String']>;
|
||||
online?: Maybe<Scalars['Boolean']>;
|
||||
uptime?: Maybe<Uptime>;
|
||||
version?: Maybe<Scalars['String']>;
|
||||
};
|
||||
|
||||
export type Subscription = {
|
||||
__typename?: 'Subscription';
|
||||
events?: Maybe<Array<Event>>;
|
||||
remoteSubscription: Scalars['String'];
|
||||
servers: Array<Server>;
|
||||
};
|
||||
|
||||
|
||||
export type SubscriptionremoteSubscriptionArgs = {
|
||||
input: RemoteGraphQLClientInput;
|
||||
};
|
||||
|
||||
export type TwoFactorLocal = {
|
||||
__typename?: 'TwoFactorLocal';
|
||||
enabled?: Maybe<Scalars['Boolean']>;
|
||||
};
|
||||
|
||||
export type TwoFactorRemote = {
|
||||
__typename?: 'TwoFactorRemote';
|
||||
enabled?: Maybe<Scalars['Boolean']>;
|
||||
};
|
||||
|
||||
export type TwoFactorWithToken = {
|
||||
__typename?: 'TwoFactorWithToken';
|
||||
local?: Maybe<TwoFactorLocal>;
|
||||
remote?: Maybe<TwoFactorRemote>;
|
||||
token?: Maybe<Scalars['String']>;
|
||||
};
|
||||
|
||||
export type TwoFactorWithoutToken = {
|
||||
__typename?: 'TwoFactorWithoutToken';
|
||||
local?: Maybe<TwoFactorLocal>;
|
||||
remote?: Maybe<TwoFactorRemote>;
|
||||
};
|
||||
|
||||
export enum URL_TYPE {
|
||||
DEFAULT = 'DEFAULT',
|
||||
LAN = 'LAN',
|
||||
MDNS = 'MDNS',
|
||||
WAN = 'WAN',
|
||||
WIREGUARD = 'WIREGUARD'
|
||||
}
|
||||
|
||||
export type UpdateEvent = {
|
||||
__typename?: 'UpdateEvent';
|
||||
data: UpdateEventData;
|
||||
type: EventType;
|
||||
};
|
||||
|
||||
export type UpdateEventData = {
|
||||
__typename?: 'UpdateEventData';
|
||||
apiKey: Scalars['String'];
|
||||
type: UpdateType;
|
||||
};
|
||||
|
||||
export enum UpdateType {
|
||||
DASHBOARD = 'DASHBOARD',
|
||||
NETWORK = 'NETWORK'
|
||||
}
|
||||
|
||||
export type Uptime = {
|
||||
__typename?: 'Uptime';
|
||||
timestamp?: Maybe<Scalars['String']>;
|
||||
};
|
||||
|
||||
export type UserProfileModelWithServers = {
|
||||
__typename?: 'UserProfileModelWithServers';
|
||||
profile: ProfileModel;
|
||||
servers: Array<Server>;
|
||||
};
|
||||
|
||||
export type Vars = {
|
||||
__typename?: 'Vars';
|
||||
expireTime?: Maybe<Scalars['DateTime']>;
|
||||
flashGuid?: Maybe<Scalars['String']>;
|
||||
regState?: Maybe<RegistrationState>;
|
||||
regTm2?: Maybe<Scalars['String']>;
|
||||
regTy?: Maybe<Scalars['String']>;
|
||||
};
|
||||
|
||||
export type updateDashboardMutationVariables = Exact<{
|
||||
data: DashboardInput;
|
||||
apiKey: Scalars['String'];
|
||||
}>;
|
||||
|
||||
|
||||
export type updateDashboardMutation = { __typename?: 'Mutation', updateDashboard: { __typename?: 'Dashboard', apps?: { __typename?: 'DashboardApps', installed?: number | null } | null } };
|
||||
|
||||
export type sendNotificationMutationVariables = Exact<{
|
||||
notification: NotificationInput;
|
||||
apiKey: Scalars['String'];
|
||||
}>;
|
||||
|
||||
|
||||
export type sendNotificationMutation = { __typename?: 'Mutation', sendNotification?: { __typename?: 'Notification', title?: string | null, subject?: string | null, description?: string | null, importance?: Importance | null, link?: string | null, status: NotificationStatus } | null };
|
||||
|
||||
export type updateNetworkMutationVariables = Exact<{
|
||||
data: NetworkInput;
|
||||
apiKey: Scalars['String'];
|
||||
}>;
|
||||
|
||||
|
||||
export type updateNetworkMutation = { __typename?: 'Mutation', updateNetwork: { __typename?: 'Network', accessUrls?: Array<{ __typename?: 'AccessUrl', name?: string | null, type: URL_TYPE, ipv4?: URL | null, ipv6?: URL | null }> | null } };
|
||||
|
||||
export type sendRemoteAccessMutationMutationVariables = Exact<{
|
||||
remoteAccess: RemoteAccessInput;
|
||||
}>;
|
||||
|
||||
|
||||
export type sendRemoteAccessMutationMutation = { __typename?: 'Mutation', remoteSession?: boolean | null };
|
||||
|
||||
export type sendRemoteGraphQLResponseMutationVariables = Exact<{
|
||||
input: RemoteGraphQLServerInput;
|
||||
}>;
|
||||
|
||||
|
||||
export type sendRemoteGraphQLResponseMutation = { __typename?: 'Mutation', remoteGraphQLResponse: boolean };
|
||||
|
||||
export type RemoteGraphQLEventFragmentFragment = { __typename?: 'RemoteGraphQLEvent', remoteGraphQLEventData: { __typename?: 'RemoteGraphQLEventData', type: RemoteGraphQLEventType, body: string, sha256: string } } & { ' $fragmentName'?: 'RemoteGraphQLEventFragmentFragment' };
|
||||
|
||||
export type RemoteAccessEventFragmentFragment = { __typename?: 'RemoteAccessEvent', type: EventType, data: { __typename?: 'RemoteAccessEventData', type: RemoteAccessEventActionType, apiKey: string, url?: { __typename?: 'AccessUrl', type: URL_TYPE, name?: string | null, ipv4?: URL | null, ipv6?: URL | null } | null } } & { ' $fragmentName'?: 'RemoteAccessEventFragmentFragment' };
|
||||
|
||||
export type eventsSubscriptionVariables = Exact<{ [key: string]: never; }>;
|
||||
|
||||
|
||||
export type eventsSubscription = { __typename?: 'Subscription', events?: Array<{ __typename: 'ClientConnectedEvent', connectedEvent: EventType, connectedData: { __typename?: 'ClientConnectionEventData', type: ClientType, version: string, apiKey: string } } | { __typename: 'ClientDisconnectedEvent', disconnectedEvent: EventType, disconnectedData: { __typename?: 'ClientConnectionEventData', type: ClientType, version: string, apiKey: string } } | { __typename: 'ClientPingEvent' } | (
|
||||
{ __typename: 'RemoteAccessEvent' }
|
||||
& { ' $fragmentRefs'?: { 'RemoteAccessEventFragmentFragment': RemoteAccessEventFragmentFragment } }
|
||||
) | (
|
||||
{ __typename: 'RemoteGraphQLEvent' }
|
||||
& { ' $fragmentRefs'?: { 'RemoteGraphQLEventFragmentFragment': RemoteGraphQLEventFragmentFragment } }
|
||||
) | { __typename: 'UpdateEvent' }> | null };
|
||||
|
||||
export const RemoteGraphQLEventFragmentFragmentDoc = {"kind":"Document","definitions":[{"kind":"FragmentDefinition","name":{"kind":"Name","value":"RemoteGraphQLEventFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"RemoteGraphQLEvent"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","alias":{"kind":"Name","value":"remoteGraphQLEventData"},"name":{"kind":"Name","value":"data"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"type"}},{"kind":"Field","name":{"kind":"Name","value":"body"}},{"kind":"Field","name":{"kind":"Name","value":"sha256"}}]}}]}}]} as unknown as DocumentNode<RemoteGraphQLEventFragmentFragment, unknown>;
|
||||
export const RemoteAccessEventFragmentFragmentDoc = {"kind":"Document","definitions":[{"kind":"FragmentDefinition","name":{"kind":"Name","value":"RemoteAccessEventFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"RemoteAccessEvent"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"type"}},{"kind":"Field","name":{"kind":"Name","value":"data"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"type"}},{"kind":"Field","name":{"kind":"Name","value":"url"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"type"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"ipv4"}},{"kind":"Field","name":{"kind":"Name","value":"ipv6"}}]}},{"kind":"Field","name":{"kind":"Name","value":"apiKey"}}]}}]}}]} as unknown as DocumentNode<RemoteAccessEventFragmentFragment, unknown>;
|
||||
export const updateDashboardDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"updateDashboard"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"data"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"DashboardInput"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"apiKey"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"updateDashboard"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"data"},"value":{"kind":"Variable","name":{"kind":"Name","value":"data"}}}],"directives":[{"kind":"Directive","name":{"kind":"Name","value":"auth"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"apiKey"},"value":{"kind":"Variable","name":{"kind":"Name","value":"apiKey"}}}]}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"apps"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"installed"}}]}}]}}]}}]} as unknown as DocumentNode<updateDashboardMutation, updateDashboardMutationVariables>;
|
||||
export const sendNotificationDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"sendNotification"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"notification"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"NotificationInput"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"apiKey"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"sendNotification"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"notification"},"value":{"kind":"Variable","name":{"kind":"Name","value":"notification"}}}],"directives":[{"kind":"Directive","name":{"kind":"Name","value":"auth"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"apiKey"},"value":{"kind":"Variable","name":{"kind":"Name","value":"apiKey"}}}]}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"title"}},{"kind":"Field","name":{"kind":"Name","value":"subject"}},{"kind":"Field","name":{"kind":"Name","value":"description"}},{"kind":"Field","name":{"kind":"Name","value":"importance"}},{"kind":"Field","name":{"kind":"Name","value":"link"}},{"kind":"Field","name":{"kind":"Name","value":"status"}}]}}]}}]} as unknown as DocumentNode<sendNotificationMutation, sendNotificationMutationVariables>;
|
||||
export const updateNetworkDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"updateNetwork"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"data"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"NetworkInput"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"apiKey"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"updateNetwork"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"data"},"value":{"kind":"Variable","name":{"kind":"Name","value":"data"}}}],"directives":[{"kind":"Directive","name":{"kind":"Name","value":"auth"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"apiKey"},"value":{"kind":"Variable","name":{"kind":"Name","value":"apiKey"}}}]}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"accessUrls"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"type"}},{"kind":"Field","name":{"kind":"Name","value":"ipv4"}},{"kind":"Field","name":{"kind":"Name","value":"ipv6"}}]}}]}}]}}]} as unknown as DocumentNode<updateNetworkMutation, updateNetworkMutationVariables>;
|
||||
export const sendRemoteAccessMutationDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"sendRemoteAccessMutation"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"remoteAccess"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"RemoteAccessInput"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"remoteSession"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"remoteAccess"},"value":{"kind":"Variable","name":{"kind":"Name","value":"remoteAccess"}}}]}]}}]} as unknown as DocumentNode<sendRemoteAccessMutationMutation, sendRemoteAccessMutationMutationVariables>;
|
||||
export const sendRemoteGraphQLResponseDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"sendRemoteGraphQLResponse"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"input"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"RemoteGraphQLServerInput"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"remoteGraphQLResponse"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"input"},"value":{"kind":"Variable","name":{"kind":"Name","value":"input"}}}]}]}}]} as unknown as DocumentNode<sendRemoteGraphQLResponseMutation, sendRemoteGraphQLResponseMutationVariables>;
|
||||
export const eventsDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"subscription","name":{"kind":"Name","value":"events"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"events"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"__typename"}},{"kind":"InlineFragment","typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"ClientConnectedEvent"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","alias":{"kind":"Name","value":"connectedData"},"name":{"kind":"Name","value":"data"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"type"}},{"kind":"Field","name":{"kind":"Name","value":"version"}},{"kind":"Field","name":{"kind":"Name","value":"apiKey"}}]}},{"kind":"Field","alias":{"kind":"Name","value":"connectedEvent"},"name":{"kind":"Name","value":"type"}}]}},{"kind":"InlineFragment","typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"ClientDisconnectedEvent"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","alias":{"kind":"Name","value":"disconnectedData"},"name":{"kind":"Name","value":"data"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"type"}},{"kind":"Field","name":{"kind":"Name","value":"version"}},{"kind":"Field","name":{"kind":"Name","value":"apiKey"}}]}},{"kind":"Field","alias":{"kind":"Name","value":"disconnectedEvent"},"name":{"kind":"Name","value":"type"}}]}},{"kind":"FragmentSpread","name":{"kind":"Name","value":"RemoteAccessEventFragment"}},{"kind":"FragmentSpread","name":{"kind":"Name","value":"RemoteGraphQLEventFragment"}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"RemoteAccessEventFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"RemoteAccessEvent"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"type"}},{"kind":"Field","name":{"kind":"Name","value":"data"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"type"}},{"kind":"Field","name":{"kind":"Name","value":"url"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"type"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"ipv4"}},{"kind":"Field","name":{"kind":"Name","value":"ipv6"}}]}},{"kind":"Field","name":{"kind":"Name","value":"apiKey"}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"RemoteGraphQLEventFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"RemoteGraphQLEvent"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","alias":{"kind":"Name","value":"remoteGraphQLEventData"},"name":{"kind":"Name","value":"data"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"type"}},{"kind":"Field","name":{"kind":"Name","value":"body"}},{"kind":"Field","name":{"kind":"Name","value":"sha256"}}]}}]}}]} as unknown as DocumentNode<eventsSubscription, eventsSubscriptionVariables>;
|
||||
@@ -0,0 +1,464 @@
|
||||
import {
|
||||
baseboard,
|
||||
cpu,
|
||||
cpuFlags,
|
||||
mem,
|
||||
memLayout,
|
||||
osInfo,
|
||||
system,
|
||||
versions,
|
||||
} from 'systeminformation';
|
||||
import { docker } from '@app/core/utils/clients/docker';
|
||||
import {
|
||||
type InfoApps,
|
||||
type Os as InfoOs,
|
||||
type InfoCpu,
|
||||
type Display,
|
||||
type Theme,
|
||||
type Temperature,
|
||||
type Baseboard,
|
||||
type Versions,
|
||||
type InfoMemory,
|
||||
type MemoryLayout,
|
||||
type System,
|
||||
type Devices,
|
||||
type InfoResolvers,
|
||||
type Gpu,
|
||||
} from '@app/graphql/generated/api/types';
|
||||
import { getters } from '@app/store';
|
||||
import { loadState } from '@app/core/utils/misc/load-state';
|
||||
import { type DynamixConfig } from '@app/core/types/ini';
|
||||
import { toBoolean } from '@app/core/utils/casting';
|
||||
import toBytes from 'bytes';
|
||||
import { getUnraidVersion } from '@app/common/dashboard/get-unraid-version';
|
||||
import { AppError } from '@app/core/errors/app-error';
|
||||
import { cleanStdout } from '@app/core/utils/misc/clean-stdout';
|
||||
import { getMachineId } from '@app/core/utils/misc/get-machine-id';
|
||||
import { execaCommandSync, execa } from 'execa';
|
||||
import { pathExists } from 'path-exists';
|
||||
import { filter as asyncFilter } from 'p-iteration';
|
||||
import { isSymlink } from 'path-type';
|
||||
import type { PciDevice } from '@app/core/types';
|
||||
import { vmRegExps } from '@app/core/utils/vms/domain/vm-regexps';
|
||||
import { getPciDevices } from '@app/core/utils/vms/get-pci-devices';
|
||||
import { filterDevices } from '@app/core/utils/vms/filter-devices';
|
||||
import { sanitizeVendor } from '@app/core/utils/vms/domain/sanitize-vendor';
|
||||
import { sanitizeProduct } from '@app/core/utils/vms/domain/sanitize-product';
|
||||
import { bootTimestamp } from '@app/common/dashboard/boot-timestamp';
|
||||
|
||||
export const generateApps = async (): Promise<InfoApps> => {
|
||||
const installed = await docker
|
||||
.listContainers({ all: true })
|
||||
.catch(() => [])
|
||||
.then((containers) => containers.length);
|
||||
const started = await docker
|
||||
.listContainers()
|
||||
.catch(() => [])
|
||||
.then((containers) => containers.length);
|
||||
return { installed, started };
|
||||
};
|
||||
|
||||
const generateOs = async (): Promise<InfoOs> => {
|
||||
const os = await osInfo();
|
||||
|
||||
return {
|
||||
...os,
|
||||
uptime: bootTimestamp.toISOString(),
|
||||
};
|
||||
};
|
||||
|
||||
const generateCpu = async (): Promise<InfoCpu> => {
|
||||
const { cores, physicalCores, speedMin, speedMax, stepping, ...rest } =
|
||||
await cpu();
|
||||
const flags = await cpuFlags().then((flags) => flags.split(' '));
|
||||
|
||||
return {
|
||||
...rest,
|
||||
cores: physicalCores,
|
||||
threads: cores,
|
||||
flags,
|
||||
stepping: Number(stepping),
|
||||
// @TODO Find out what these should be if they're not defined
|
||||
speedmin: speedMin || -1,
|
||||
speedmax: speedMax || -1,
|
||||
};
|
||||
};
|
||||
|
||||
const generateDisplay = async (): Promise<Display> => {
|
||||
const filePath = getters.paths()['dynamix-config'];
|
||||
const state = loadState<DynamixConfig>(filePath);
|
||||
if (!state) {
|
||||
return {};
|
||||
}
|
||||
const { theme, unit, ...display } = state.display;
|
||||
return {
|
||||
...display,
|
||||
theme: theme as Theme,
|
||||
unit: unit as Temperature,
|
||||
scale: toBoolean(display.scale),
|
||||
tabs: toBoolean(display.tabs),
|
||||
resize: toBoolean(display.resize),
|
||||
wwn: toBoolean(display.wwn),
|
||||
total: toBoolean(display.total),
|
||||
usage: toBoolean(display.usage),
|
||||
text: toBoolean(display.text),
|
||||
warning: Number.parseInt(display.warning, 10),
|
||||
critical: Number.parseInt(display.critical, 10),
|
||||
hot: Number.parseInt(display.hot, 10),
|
||||
max: Number.parseInt(display.max, 10),
|
||||
locale: display.locale || 'en_US',
|
||||
};
|
||||
};
|
||||
|
||||
const generateBaseboard = async (): Promise<Baseboard> => baseboard();
|
||||
|
||||
const generateVersions = async (): Promise<Versions> => {
|
||||
const unraid = await getUnraidVersion();
|
||||
const softwareVersions = await versions();
|
||||
|
||||
return {
|
||||
unraid,
|
||||
...softwareVersions,
|
||||
};
|
||||
};
|
||||
|
||||
const generateMemory = async (): Promise<InfoMemory> => {
|
||||
const layout = await memLayout().then((dims) =>
|
||||
dims.map((dim) => dim as MemoryLayout)
|
||||
);
|
||||
const info = await mem();
|
||||
let max = info.total;
|
||||
|
||||
// Max memory
|
||||
try {
|
||||
const memoryInfo = await execa('dmidecode', ['-t', 'memory'])
|
||||
.then(cleanStdout)
|
||||
.catch((error: NodeJS.ErrnoException) => {
|
||||
if (error.code === 'ENOENT') {
|
||||
throw new AppError('The dmidecode cli utility is missing.');
|
||||
}
|
||||
|
||||
throw error;
|
||||
});
|
||||
const lines = memoryInfo.split('\n');
|
||||
const header = lines.find((line) =>
|
||||
line.startsWith('Physical Memory Array')
|
||||
);
|
||||
if (header) {
|
||||
const start = lines.indexOf(header);
|
||||
const nextHeaders = lines
|
||||
.slice(start, -1)
|
||||
.find((line) => line.startsWith('Handle '));
|
||||
|
||||
if (nextHeaders) {
|
||||
const end = lines.indexOf(nextHeaders);
|
||||
const fields = lines.slice(start, end);
|
||||
|
||||
max = toBytes(
|
||||
fields
|
||||
?.find((line) =>
|
||||
line.trim().startsWith('Maximum Capacity')
|
||||
)
|
||||
?.trim()
|
||||
?.split(': ')[1] ?? '0'
|
||||
);
|
||||
}
|
||||
}
|
||||
} catch {
|
||||
// Ignore errors here
|
||||
}
|
||||
|
||||
return {
|
||||
layout,
|
||||
max,
|
||||
...info,
|
||||
};
|
||||
};
|
||||
|
||||
const generateDevices = async (): Promise<Devices> => {
|
||||
/**
|
||||
* Set device class to device.
|
||||
* @param device The device to modify.
|
||||
* @returns The same device passed in but with the class modified.
|
||||
*/
|
||||
const addDeviceClass = (device: Readonly<PciDevice>): PciDevice => {
|
||||
const modifiedDevice: PciDevice = {
|
||||
...device,
|
||||
class: 'other',
|
||||
};
|
||||
|
||||
// GPU
|
||||
if (vmRegExps.allowedGpuClassId.test(device.typeid)) {
|
||||
modifiedDevice.class = 'vga';
|
||||
// Specialized product name cleanup for GPU
|
||||
// GF116 [GeForce GTX 550 Ti] --> GeForce GTX 550 Ti
|
||||
const regex = new RegExp(/.+\[(?<gpuName>.+)]/);
|
||||
const productName = regex.exec(device.productname)?.groups?.gpuName;
|
||||
|
||||
if (productName) {
|
||||
modifiedDevice.productname = productName;
|
||||
}
|
||||
|
||||
return modifiedDevice;
|
||||
// Audio
|
||||
}
|
||||
|
||||
if (vmRegExps.allowedAudioClassId.test(device.typeid)) {
|
||||
modifiedDevice.class = 'audio';
|
||||
|
||||
return modifiedDevice;
|
||||
}
|
||||
|
||||
return modifiedDevice;
|
||||
};
|
||||
|
||||
/**
|
||||
* System PCI devices.
|
||||
*/
|
||||
const systemPciDevices = async (): Promise<PciDevice[]> => {
|
||||
const devices = await getPciDevices();
|
||||
const basePath = '/sys/bus/pci/devices/0000:';
|
||||
|
||||
// Remove devices with no IOMMU support
|
||||
const filteredDevices = await asyncFilter(
|
||||
devices,
|
||||
async (device: Readonly<PciDevice>) =>
|
||||
pathExists(`${basePath}${device.id}/iommu_group/`)
|
||||
);
|
||||
|
||||
/**
|
||||
* Run device cleanup
|
||||
*
|
||||
* Tasks:
|
||||
* - Mark disallowed devices
|
||||
* - Add class
|
||||
* - Add whether kernel-bound driver exists
|
||||
* - Cleanup device vendor/product names
|
||||
*/
|
||||
const processedDevices = await filterDevices(filteredDevices).then(
|
||||
async (devices) =>
|
||||
Promise.all(
|
||||
devices
|
||||
// @ts-expect-error - Device is not PciDevice
|
||||
.map((device) => addDeviceClass(device))
|
||||
.map(async (device) => {
|
||||
// Attempt to get the current kernel-bound driver for this pci device
|
||||
await isSymlink(
|
||||
`${basePath}${device.id}/driver`
|
||||
).then((symlink) => {
|
||||
if (symlink) {
|
||||
// $strLink = @readlink('/sys/bus/pci/devices/0000:'.$arrMatch['id']. '/driver');
|
||||
// if (!empty($strLink)) {
|
||||
// $strDriver = basename($strLink);
|
||||
// }
|
||||
}
|
||||
});
|
||||
|
||||
// Clean up the vendor and product name
|
||||
device.vendorname = sanitizeVendor(
|
||||
device.vendorname
|
||||
);
|
||||
device.productname = sanitizeProduct(
|
||||
device.productname
|
||||
);
|
||||
|
||||
return device;
|
||||
})
|
||||
)
|
||||
);
|
||||
|
||||
return processedDevices;
|
||||
};
|
||||
|
||||
/**
|
||||
* System GPU Devices
|
||||
*
|
||||
* @name systemGPUDevices
|
||||
* @ignore
|
||||
* @private
|
||||
*/
|
||||
const systemGPUDevices: Promise<Gpu[]> = systemPciDevices().then(
|
||||
(devices) => {
|
||||
return devices.filter(
|
||||
(device) => device.class === 'vga' && !device.allowed
|
||||
).map(entry => {
|
||||
const gpu: Gpu = {
|
||||
blacklisted: entry.allowed,
|
||||
class: entry.class,
|
||||
id: entry.id,
|
||||
productid: entry.product,
|
||||
typeid: entry.typeid,
|
||||
type: entry.manufacturer,
|
||||
vendorname: entry.vendorname
|
||||
}
|
||||
return gpu;
|
||||
});
|
||||
}
|
||||
).catch(() => []);
|
||||
|
||||
/**
|
||||
* System usb devices.
|
||||
* @returns Array of USB devices.
|
||||
*/
|
||||
const getSystemUSBDevices = async () => {
|
||||
try {
|
||||
// Get a list of all usb hubs so we can filter the allowed/disallowed
|
||||
const usbHubs = await execa(
|
||||
'cat /sys/bus/usb/drivers/hub/*/modalias',
|
||||
{ shell: true }
|
||||
)
|
||||
.then(({ stdout }) =>
|
||||
stdout.split('\n').map((line) => {
|
||||
// eslint-disable-next-line @typescript-eslint/prefer-regexp-exec
|
||||
const [, id] = line.match(/usb:v(\w{9})/) ?? [];
|
||||
return id.replace('p', ':');
|
||||
})
|
||||
)
|
||||
.catch(() => [] as string[]);
|
||||
|
||||
const emhttp = getters.emhttp();
|
||||
|
||||
// Remove boot drive
|
||||
const filterBootDrive = (device: Readonly<PciDevice>): boolean =>
|
||||
emhttp.var.flashGuid !== device.guid;
|
||||
|
||||
// Remove usb hubs
|
||||
const filterUsbHubs = (device: Readonly<PciDevice>): boolean =>
|
||||
!usbHubs.includes(device.id);
|
||||
|
||||
// Clean up the name
|
||||
const sanitizeVendorName = (device: Readonly<PciDevice>) => {
|
||||
const vendorname = sanitizeVendor(device.vendorname || '');
|
||||
return {
|
||||
...device,
|
||||
vendorname,
|
||||
};
|
||||
};
|
||||
|
||||
const parseDeviceLine = (
|
||||
line: Readonly<string>
|
||||
): { value: string; string: string } => {
|
||||
const emptyLine = { value: '', string: '' };
|
||||
|
||||
// If the line is blank return nothing
|
||||
if (!line) {
|
||||
return emptyLine;
|
||||
}
|
||||
|
||||
// Parse the line
|
||||
const [, _] = line.split(/[ \t]{2,}/).filter(Boolean);
|
||||
// eslint-disable-next-line @typescript-eslint/prefer-regexp-exec
|
||||
const match = _.match(/^(\S+)\s(.*)/)?.slice(1);
|
||||
|
||||
// If there's no match return nothing
|
||||
if (!match) {
|
||||
return emptyLine;
|
||||
}
|
||||
|
||||
return {
|
||||
value: match[0],
|
||||
string: match[1],
|
||||
};
|
||||
};
|
||||
|
||||
// Add extra fields to device
|
||||
const parseDevice = (device: Readonly<PciDevice>) => {
|
||||
const modifiedDevice: PciDevice = {
|
||||
...device,
|
||||
};
|
||||
const info = execaCommandSync(
|
||||
`lsusb -d ${device.id} -v`
|
||||
).stdout.split('\n');
|
||||
const deviceName = device.name.trim();
|
||||
const iSerial = parseDeviceLine(
|
||||
info.filter((line) => line.includes('iSerial'))[0]
|
||||
);
|
||||
const iProduct = parseDeviceLine(
|
||||
info.filter((line) => line.includes('iProduct'))[0]
|
||||
);
|
||||
const iManufacturer = parseDeviceLine(
|
||||
info.filter((line) => line.includes('iManufacturer'))[0]
|
||||
);
|
||||
const idProduct = parseDeviceLine(
|
||||
info.filter((line) => line.includes('idProduct'))[0]
|
||||
);
|
||||
const idVendor = parseDeviceLine(
|
||||
info.filter((line) => line.includes('idVendor'))[0]
|
||||
);
|
||||
const serial = `${iSerial.string
|
||||
.slice(8)
|
||||
.slice(0, 4)}-${iSerial.string.slice(8).slice(4)}`;
|
||||
const guid = `${idVendor.value.slice(
|
||||
2
|
||||
)}-${idProduct.value.slice(2)}-${serial}`;
|
||||
|
||||
modifiedDevice.serial = iSerial.string;
|
||||
modifiedDevice.product = iProduct.string;
|
||||
modifiedDevice.manufacturer = iManufacturer.string;
|
||||
modifiedDevice.guid = guid;
|
||||
|
||||
// Set name if missing
|
||||
if (deviceName === '') {
|
||||
modifiedDevice.name =
|
||||
`${iProduct.string} ${iManufacturer.string}`.trim();
|
||||
}
|
||||
|
||||
// Name still blank? Replace using fallback default
|
||||
if (deviceName === '') {
|
||||
modifiedDevice.name = '[unnamed device]';
|
||||
}
|
||||
|
||||
// Ensure name is trimmed
|
||||
modifiedDevice.name = device.name.trim();
|
||||
|
||||
return modifiedDevice;
|
||||
};
|
||||
|
||||
const parseUsbDevices = (stdout: string) =>
|
||||
stdout.split('\n').map((line) => {
|
||||
const regex = new RegExp(/^.+: ID (?<id>\S+)(?<name>.*)$/);
|
||||
const result = regex.exec(line);
|
||||
return result?.groups as unknown as PciDevice;
|
||||
}) ?? [];
|
||||
|
||||
// Get all usb devices
|
||||
const usbDevices = await execa('lsusb').then(async ({ stdout }) =>
|
||||
parseUsbDevices(stdout)
|
||||
.map(parseDevice)
|
||||
.filter(filterBootDrive)
|
||||
.filter(filterUsbHubs)
|
||||
.map(sanitizeVendorName)
|
||||
);
|
||||
|
||||
return usbDevices;
|
||||
} catch (error: unknown) {
|
||||
return [];
|
||||
}
|
||||
};
|
||||
|
||||
return {
|
||||
// Scsi: await scsiDevices,
|
||||
gpu: await systemGPUDevices,
|
||||
// Move this to interfaces
|
||||
// network: await si.networkInterfaces(),
|
||||
pci: await systemPciDevices(),
|
||||
usb: await getSystemUSBDevices(),
|
||||
};
|
||||
};
|
||||
|
||||
const generateMachineId = async (): Promise<string> => getMachineId();
|
||||
|
||||
const generateSystem = async (): Promise<System> => system();
|
||||
|
||||
export const infoSubResolvers: InfoResolvers = {
|
||||
apps: async () => generateApps(),
|
||||
baseboard: async () => generateBaseboard(),
|
||||
cpu: async () => generateCpu(),
|
||||
devices: async () => generateDevices(),
|
||||
display: async () => generateDisplay(),
|
||||
machineId: async () => generateMachineId(),
|
||||
memory: async () => generateMemory(),
|
||||
os: async () => generateOs(),
|
||||
system: async () => generateSystem(),
|
||||
versions: async () => generateVersions(),
|
||||
};
|
||||
@@ -1,5 +1,4 @@
|
||||
import { createSlice, type PayloadAction } from '@reduxjs/toolkit';
|
||||
import merge from 'lodash/merge';
|
||||
import { DaemonConnectionStatus } from '@app/store/types';
|
||||
import { type DockerContainer } from '@app/graphql/generated/api/types';
|
||||
|
||||
|
||||
@@ -2,18 +2,23 @@ import { store } from '@app/store';
|
||||
import { dockerLogger } from '@app/core/log';
|
||||
import { updateDockerState } from '@app/store/modules/docker';
|
||||
import { getDockerContainers } from '@app/core/modules/index';
|
||||
import { ContainerState } from '@app/graphql/generated/api/types';
|
||||
import { docker } from '@app/core/utils/index';
|
||||
import DockerEE from 'docker-event-emitter';
|
||||
import { debounce } from 'lodash';
|
||||
|
||||
const updateContainerCache = async () => {
|
||||
try {
|
||||
await getDockerContainers({ useCache: false });
|
||||
} catch (err) {
|
||||
dockerLogger.warn('Caught error getting containers %o', err)
|
||||
store.dispatch(updateDockerState({ installed: null, running: null, containers: [] }))
|
||||
}
|
||||
try {
|
||||
await getDockerContainers({ useCache: false });
|
||||
} catch (err) {
|
||||
dockerLogger.warn('Caught error getting containers %o', err);
|
||||
store.dispatch(
|
||||
updateDockerState({
|
||||
installed: null,
|
||||
running: null,
|
||||
containers: [],
|
||||
})
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
const debouncedContainerCacheUpdate = debounce(updateContainerCache, 500);
|
||||
@@ -50,12 +55,12 @@ export const setupDockerWatch = async (): Promise<DockerEE> => {
|
||||
dockerLogger.addContext('data', data);
|
||||
dockerLogger.debug(`[${data.from}] ${data.Type}->${data.Action}`);
|
||||
dockerLogger.removeContext('data');
|
||||
await debouncedContainerCacheUpdate()
|
||||
await debouncedContainerCacheUpdate();
|
||||
}
|
||||
);
|
||||
// Get docker container count on first start
|
||||
// Get docker container count on first start
|
||||
await debouncedContainerCacheUpdate();
|
||||
await dee.start();
|
||||
dockerLogger.debug('Binding to docker events');
|
||||
return dee;
|
||||
return dee;
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user