feat: add gui settings field for sso users (#1310)

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

- **New Features**
- Bulk SSO account management is now supported, allowing users to update
multiple SSO account IDs at once.
- Connect settings now include SSO account identifiers for streamlined
configuration.
- Expanded array management functionality introduces advanced operations
for managing disk arrays.
- New fields for SSO user IDs have been added to various settings and
queries.

- **Style & Documentation**
- Improved formatting and support for rich HTML in form descriptions
enhance clarity and presentation.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->

---------

Co-authored-by: Eli Bosley <ekbosley@gmail.com>
This commit is contained in:
Pujit Mehrotra
2025-04-03 09:50:12 -04:00
committed by GitHub
parent 1f10b63c8b
commit 5ba3fa67a2
10 changed files with 202 additions and 83 deletions

View File

@@ -160,7 +160,8 @@ export function ApiSettingsInputSchema(): z.ZodObject<Properties<ApiSettingsInpu
extraOrigins: z.array(z.string()).nullish(),
forwardType: WAN_FORWARD_TYPESchema.nullish(),
port: z.number().nullish(),
sandbox: z.boolean().nullish()
sandbox: z.boolean().nullish(),
ssoUserIds: z.array(z.string()).nullish()
})
}
@@ -362,7 +363,8 @@ export function ConnectSettingsValuesSchema(): z.ZodObject<Properties<ConnectSet
extraOrigins: z.array(z.string()),
forwardType: WAN_FORWARD_TYPESchema.nullish(),
port: z.number().nullish(),
sandbox: z.boolean()
sandbox: z.boolean(),
ssoUserIds: z.array(z.string())
})
}

View File

@@ -107,6 +107,8 @@ export type ApiSettingsInput = {
* If false, the GraphQL sandbox will be disabled and only the production API will be available.
*/
sandbox?: InputMaybe<Scalars['Boolean']['input']>;
/** A list of Unique Unraid Account ID's. */
ssoUserIds?: InputMaybe<Array<Scalars['String']['input']>>;
};
export type ArrayType = Node & {
@@ -408,6 +410,8 @@ export type ConnectSettingsValues = {
* If false, the GraphQL sandbox is disabled and only the production API will be available.
*/
sandbox: Scalars['Boolean']['output'];
/** A list of Unique Unraid Account ID's. */
ssoUserIds: Array<Scalars['String']['output']>;
};
export type ConnectSignInInput = {
@@ -2373,6 +2377,7 @@ export type ConnectSettingsValuesResolvers<ContextType = Context, ParentType ext
forwardType?: Resolver<Maybe<ResolversTypes['WAN_FORWARD_TYPE']>, ParentType, ContextType>;
port?: Resolver<Maybe<ResolversTypes['Port']>, ParentType, ContextType>;
sandbox?: Resolver<ResolversTypes['Boolean'], ParentType, ContextType>;
ssoUserIds?: Resolver<Array<ResolversTypes['String']>, ParentType, ContextType>;
__isTypeOf?: IsTypeOfResolverFn<ParentType, ContextType>;
}>;

View File

@@ -39,8 +39,6 @@ input SetupRemoteAccessInput {
port: Port
}
input EnableDynamicRemoteAccessInput {
url: AccessUrlInput!
enabled: Boolean!
@@ -59,59 +57,67 @@ type DynamicRemoteAccessStatus {
}
"""
Intersection type of ApiSettings and RemoteAccess
Intersection type of ApiSettings and RemoteAccess
"""
type ConnectSettingsValues {
"""
If true, the GraphQL sandbox is enabled and available at /graphql.
If false, the GraphQL sandbox is disabled and only the production API will be available.
If true, the GraphQL sandbox is enabled and available at /graphql.
If false, the GraphQL sandbox is disabled and only the production API will be available.
"""
sandbox: Boolean!
"""
A list of origins allowed to interact with the API.
A list of origins allowed to interact with the API.
"""
extraOrigins: [String!]!
"""
The type of WAN access used for Remote Access.
The type of WAN access used for Remote Access.
"""
accessType: WAN_ACCESS_TYPE!
"""
The type of port forwarding used for Remote Access.
The type of port forwarding used for Remote Access.
"""
forwardType: WAN_FORWARD_TYPE
"""
The port used for Remote Access.
The port used for Remote Access.
"""
port: Port
"""
A list of Unique Unraid Account ID's.
"""
ssoUserIds: [String!]!
}
"""
Input should be a subset of ApiSettings that can be updated.
Some field combinations may be required or disallowed. Please refer to each field for more information.
Input should be a subset of ApiSettings that can be updated.
Some field combinations may be required or disallowed. Please refer to each field for more information.
"""
input ApiSettingsInput {
"""
If true, the GraphQL sandbox will be enabled and available at /graphql.
If false, the GraphQL sandbox will be disabled and only the production API will be available.
If true, the GraphQL sandbox will be enabled and available at /graphql.
If false, the GraphQL sandbox will be disabled and only the production API will be available.
"""
sandbox: Boolean
"""
A list of origins allowed to interact with the API.
A list of origins allowed to interact with the API.
"""
extraOrigins: [String!]
"""
The type of WAN access to use for Remote Access.
The type of WAN access to use for Remote Access.
"""
accessType: WAN_ACCESS_TYPE
"""
The type of port forwarding to use for Remote Access.
The type of port forwarding to use for Remote Access.
"""
forwardType: WAN_FORWARD_TYPE
"""
The port to use for Remote Access. Not required for UPNP forwardType. Required for STATIC forwardType.
Ignored if accessType is DISABLED or forwardType is UPNP.
The port to use for Remote Access. Not required for UPNP forwardType. Required for STATIC forwardType.
Ignored if accessType is DISABLED or forwardType is UPNP.
"""
port: Port
"""
A list of Unique Unraid Account ID's.
"""
ssoUserIds: [String!]
}
type ConnectSettings implements Node {
@@ -140,8 +146,8 @@ type Mutation {
setAdditionalAllowedOrigins(input: AllowedOriginInput!): [String!]!
setupRemoteAccess(input: SetupRemoteAccessInput!): Boolean!
"""
Update the API settings.
Some setting combinations may be required or disallowed. Please refer to each setting for more information.
Update the API settings.
Some setting combinations may be required or disallowed. Please refer to each setting for more information.
"""
updateApiSettings(input: ApiSettingsInput!): ConnectSettingsValues!
}
}

View File

@@ -219,6 +219,9 @@ export const config = createSlice({
stateAsArray.push(action.payload);
state.remote.ssoSubIds = stateAsArray.join(',');
},
setSsoUsers(state, action: PayloadAction<string[]>) {
state.remote.ssoSubIds = action.payload.filter((id) => id).join(',');
},
removeSsoUser(state, action: PayloadAction<string | null>) {
if (action.payload === null) {
state.remote.ssoSubIds = '';
@@ -309,6 +312,7 @@ const { actions, reducer } = config;
export const {
addSsoUser,
setSsoUsers,
updateUserConfig,
updateAccessTokens,
updateAllowedOrigins,
@@ -324,6 +328,7 @@ export const {
*/
export const configUpdateActionsFlash = isAnyOf(
addSsoUser,
setSsoUsers,
updateUserConfig,
updateAccessTokens,
updateAllowedOrigins,

View File

@@ -18,7 +18,7 @@ import {
WAN_FORWARD_TYPE,
} from '@app/graphql/generated/api/types.js';
import { setupRemoteAccessThunk } from '@app/store/actions/setup-remote-access.js';
import { updateAllowedOrigins, updateUserConfig } from '@app/store/modules/config.js';
import { setSsoUsers, updateAllowedOrigins, updateUserConfig } from '@app/store/modules/config.js';
import { mergeSettingSlices } from '@app/unraid-api/types/json-forms.js';
import { csvStringToArray } from '@app/utils.js';
@@ -50,11 +50,12 @@ export class ConnectSettingsService {
async getCurrentSettings(): Promise<ConnectSettingsValues> {
const { getters } = await import('@app/store/index.js');
const { local, api } = getters.config();
const { local, api, remote } = getters.config();
return {
...(await this.dynamicRemoteAccessSettings()),
sandbox: local.sandbox === 'yes',
extraOrigins: csvStringToArray(api.extraOrigins),
ssoUserIds: csvStringToArray(remote.ssoSubIds),
};
}
@@ -63,7 +64,7 @@ export class ConnectSettingsService {
* @param settings - The settings to sync
* @returns true if a restart is required, false otherwise
*/
async syncSettings(settings: Partial<ApiSettingsInput>) {
async syncSettings(settings: Partial<ApiSettingsInput>): Promise<boolean> {
let restartRequired = false;
const { getters } = await import('@app/store/index.js');
const { nginx } = getters.emhttp();
@@ -86,13 +87,15 @@ export class ConnectSettingsService {
port: settings.port,
});
}
if (settings.extraOrigins) {
await this.updateAllowedOrigins(settings.extraOrigins);
}
if (typeof settings.sandbox === 'boolean') {
restartRequired ||= await this.setSandboxMode(settings.sandbox);
}
if (settings.ssoUserIds) {
restartRequired ||= await this.updateSSOUsers(settings.ssoUserIds);
}
const { writeConfigSync } = await import('@app/store/sync/config-disk-sync.js');
writeConfigSync('flash');
return restartRequired;
@@ -117,6 +120,32 @@ export class ConnectSettingsService {
return true;
}
/**
* Updates the SSO users and returns true if a restart is required
* @param userIds - The list of SSO user IDs
* @returns true if a restart is required, false otherwise
*/
private async updateSSOUsers(userIds: string[]): Promise<boolean> {
const { ssoUserIds } = await this.getCurrentSettings();
const currentUserSet = new Set(ssoUserIds);
const newUserSet = new Set(userIds);
if (newUserSet.symmetricDifference(currentUserSet).size === 0) {
// there's no change, so no need to update
return false;
}
// make sure we aren't adding invalid user ids
const uuidRegex =
/^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$/;
const invalidUserIds = userIds.filter((id) => !uuidRegex.test(id));
if (invalidUserIds.length > 0) {
throw new GraphQLError(`Invalid SSO user ID's: ${invalidUserIds.join(', ')}`);
}
const { store } = await import('@app/store/index.js');
store.dispatch(setSsoUsers(userIds));
// request a restart if we're there were no sso users before
return currentUserSet.size === 0;
}
private async updateRemoteAccess(input: SetupRemoteAccessInput): Promise<boolean> {
const { store } = await import('@app/store/index.js');
await store.dispatch(setupRemoteAccessThunk(input)).unwrap();
@@ -151,6 +180,7 @@ export class ConnectSettingsService {
await this.remoteAccessSlice(),
await this.sandboxSlice(),
this.flashBackupSlice(),
this.ssoUsersSlice(),
// Because CORS is effectively disabled, this setting is no longer necessary
// keeping it here for in case it needs to be re-enabled
//
@@ -344,4 +374,32 @@ export class ConnectSettingsService {
],
};
}
/**
* Extra origins settings slice
*/
ssoUsersSlice(): SettingSlice {
return {
properties: {
ssoUserIds: {
type: 'array',
items: {
type: 'string',
},
title: 'Unraid API SSO Users',
description: `Provide a list of Unique Unraid Account ID's. Find yours at <a href="https://account.unraid.net/settings" target="_blank">account.unraid.net/settings</a>`,
},
},
elements: [
{
type: 'Control',
scope: '#/properties/ssoUserIds',
options: {
inputType: 'text',
placeholder: 'UUID',
},
},
],
};
}
}

View File

@@ -69,11 +69,11 @@ export class ConnectResolver implements ConnectResolvers {
const restartRequired = await this.connectSettingsService.syncSettings(settings);
const currentSettings = await this.connectSettingsService.getCurrentSettings();
if (restartRequired) {
const restartDelayMs = 3_000;
setTimeout(async () => {
// Send restart out of band to avoid blocking the return of this resolver
this.logger.log('Restarting API');
await this.connectService.restartApi();
}, restartDelayMs);
}, 300);
}
return currentSettings;
}

View File

@@ -44,7 +44,7 @@ const placeholder = computed(() => control.value.uischema?.options?.placeholder
<template>
<ControlLayout v-if="control.visible" :label="control.label" :errors="control.errors">
<div class="space-y-4">
<p v-if="control.description">{{ control.description }}</p>
<p v-if="control.description" v-html="control.description" />
<div v-for="(item, index) in items" :key="index" class="flex gap-2">
<Input
:type="inputType"

View File

@@ -14,6 +14,7 @@ export const getConnectSettingsForm = graphql(/* GraphQL */ `
accessType
forwardType
port
ssoUserIds
}
}
}
@@ -28,6 +29,7 @@ export const updateConnectSettings = graphql(/* GraphQL */ `
accessType
forwardType
port
ssoUserIds
}
}
`);

View File

@@ -14,8 +14,8 @@ import type { TypedDocumentNode as DocumentNode } from '@graphql-typed-document-
* Learn more about it here: https://the-guild.dev/graphql/codegen/plugins/presets/preset-client#reducing-bundle-size
*/
type Documents = {
"\n query GetConnectSettingsForm {\n connect {\n id\n settings {\n id\n dataSchema\n uiSchema\n values {\n sandbox\n extraOrigins\n accessType\n forwardType\n port\n }\n }\n }\n }\n": typeof types.GetConnectSettingsFormDocument,
"\n mutation UpdateConnectSettings($input: ApiSettingsInput!) {\n updateApiSettings(input: $input) {\n sandbox\n extraOrigins\n accessType\n forwardType\n port\n }\n }\n": typeof types.UpdateConnectSettingsDocument,
"\n query GetConnectSettingsForm {\n connect {\n id\n settings {\n id\n dataSchema\n uiSchema\n values {\n sandbox\n extraOrigins\n accessType\n forwardType\n port\n ssoUserIds\n }\n }\n }\n }\n": typeof types.GetConnectSettingsFormDocument,
"\n mutation UpdateConnectSettings($input: ApiSettingsInput!) {\n updateApiSettings(input: $input) {\n sandbox\n extraOrigins\n accessType\n forwardType\n port\n ssoUserIds\n }\n }\n": typeof types.UpdateConnectSettingsDocument,
"\n query LogFiles {\n logFiles {\n name\n path\n size\n modifiedAt\n }\n }\n": typeof types.LogFilesDocument,
"\n query LogFileContent($path: String!, $lines: Int, $startLine: Int) {\n logFile(path: $path, lines: $lines, startLine: $startLine) {\n path\n content\n totalLines\n startLine\n }\n }\n": typeof types.LogFileContentDocument,
"\n subscription LogFileSubscription($path: String!) {\n logFile(path: $path) {\n path\n content\n totalLines\n }\n }\n": typeof types.LogFileSubscriptionDocument,
@@ -40,8 +40,8 @@ type Documents = {
"\n mutation setupRemoteAccess($input: SetupRemoteAccessInput!) {\n setupRemoteAccess(input: $input)\n }\n": typeof types.setupRemoteAccessDocument,
};
const documents: Documents = {
"\n query GetConnectSettingsForm {\n connect {\n id\n settings {\n id\n dataSchema\n uiSchema\n values {\n sandbox\n extraOrigins\n accessType\n forwardType\n port\n }\n }\n }\n }\n": types.GetConnectSettingsFormDocument,
"\n mutation UpdateConnectSettings($input: ApiSettingsInput!) {\n updateApiSettings(input: $input) {\n sandbox\n extraOrigins\n accessType\n forwardType\n port\n }\n }\n": types.UpdateConnectSettingsDocument,
"\n query GetConnectSettingsForm {\n connect {\n id\n settings {\n id\n dataSchema\n uiSchema\n values {\n sandbox\n extraOrigins\n accessType\n forwardType\n port\n ssoUserIds\n }\n }\n }\n }\n": types.GetConnectSettingsFormDocument,
"\n mutation UpdateConnectSettings($input: ApiSettingsInput!) {\n updateApiSettings(input: $input) {\n sandbox\n extraOrigins\n accessType\n forwardType\n port\n ssoUserIds\n }\n }\n": types.UpdateConnectSettingsDocument,
"\n query LogFiles {\n logFiles {\n name\n path\n size\n modifiedAt\n }\n }\n": types.LogFilesDocument,
"\n query LogFileContent($path: String!, $lines: Int, $startLine: Int) {\n logFile(path: $path, lines: $lines, startLine: $startLine) {\n path\n content\n totalLines\n startLine\n }\n }\n": types.LogFileContentDocument,
"\n subscription LogFileSubscription($path: String!) {\n logFile(path: $path) {\n path\n content\n totalLines\n }\n }\n": types.LogFileSubscriptionDocument,
@@ -83,11 +83,11 @@ export function graphql(source: string): unknown;
/**
* The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
*/
export function graphql(source: "\n query GetConnectSettingsForm {\n connect {\n id\n settings {\n id\n dataSchema\n uiSchema\n values {\n sandbox\n extraOrigins\n accessType\n forwardType\n port\n }\n }\n }\n }\n"): (typeof documents)["\n query GetConnectSettingsForm {\n connect {\n id\n settings {\n id\n dataSchema\n uiSchema\n values {\n sandbox\n extraOrigins\n accessType\n forwardType\n port\n }\n }\n }\n }\n"];
export function graphql(source: "\n query GetConnectSettingsForm {\n connect {\n id\n settings {\n id\n dataSchema\n uiSchema\n values {\n sandbox\n extraOrigins\n accessType\n forwardType\n port\n ssoUserIds\n }\n }\n }\n }\n"): (typeof documents)["\n query GetConnectSettingsForm {\n connect {\n id\n settings {\n id\n dataSchema\n uiSchema\n values {\n sandbox\n extraOrigins\n accessType\n forwardType\n port\n ssoUserIds\n }\n }\n }\n }\n"];
/**
* The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
*/
export function graphql(source: "\n mutation UpdateConnectSettings($input: ApiSettingsInput!) {\n updateApiSettings(input: $input) {\n sandbox\n extraOrigins\n accessType\n forwardType\n port\n }\n }\n"): (typeof documents)["\n mutation UpdateConnectSettings($input: ApiSettingsInput!) {\n updateApiSettings(input: $input) {\n sandbox\n extraOrigins\n accessType\n forwardType\n port\n }\n }\n"];
export function graphql(source: "\n mutation UpdateConnectSettings($input: ApiSettingsInput!) {\n updateApiSettings(input: $input) {\n sandbox\n extraOrigins\n accessType\n forwardType\n port\n ssoUserIds\n }\n }\n"): (typeof documents)["\n mutation UpdateConnectSettings($input: ApiSettingsInput!) {\n updateApiSettings(input: $input) {\n sandbox\n extraOrigins\n accessType\n forwardType\n port\n ssoUserIds\n }\n }\n"];
/**
* The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
*/

View File

@@ -110,6 +110,8 @@ export type ApiSettingsInput = {
* If false, the GraphQL sandbox will be disabled and only the production API will be available.
*/
sandbox?: InputMaybe<Scalars['Boolean']['input']>;
/** A list of Unique Unraid Account ID's. */
ssoUserIds?: InputMaybe<Array<Scalars['String']['input']>>;
};
export type ArrayType = Node & {
@@ -194,6 +196,13 @@ export enum ArrayDiskFsColor {
YellowOn = 'yellow_on'
}
export type ArrayDiskInput = {
/** Disk ID */
id: Scalars['ID']['input'];
/** The slot for the disk */
slot?: InputMaybe<Scalars['Int']['input']>;
};
export enum ArrayDiskStatus {
/** disabled, old disk still present */
DiskDsbl = 'DISK_DSBL',
@@ -226,6 +235,49 @@ export enum ArrayDiskType {
Parity = 'Parity'
}
export type ArrayMutations = {
__typename?: 'ArrayMutations';
/** Add new disk to array */
addDiskToArray?: Maybe<ArrayType>;
clearArrayDiskStatistics?: Maybe<Scalars['JSON']['output']>;
mountArrayDisk?: Maybe<Disk>;
/** Remove existing disk from array. NOTE: The array must be stopped before running this otherwise it'll throw an error. */
removeDiskFromArray?: Maybe<ArrayType>;
/** Set array state */
setState?: Maybe<ArrayType>;
unmountArrayDisk?: Maybe<Disk>;
};
export type ArrayMutationsaddDiskToArrayArgs = {
input?: InputMaybe<ArrayDiskInput>;
};
export type ArrayMutationsclearArrayDiskStatisticsArgs = {
id: Scalars['ID']['input'];
};
export type ArrayMutationsmountArrayDiskArgs = {
id: Scalars['ID']['input'];
};
export type ArrayMutationsremoveDiskFromArrayArgs = {
input?: InputMaybe<ArrayDiskInput>;
};
export type ArrayMutationssetStateArgs = {
input?: InputMaybe<ArrayStateInput>;
};
export type ArrayMutationsunmountArrayDiskArgs = {
id: Scalars['ID']['input'];
};
export enum ArrayPendingState {
/** Array has no data disks */
NoDataDisks = 'no_data_disks',
@@ -262,6 +314,18 @@ export enum ArrayState {
TooManyMissingDisks = 'TOO_MANY_MISSING_DISKS'
}
export type ArrayStateInput = {
/** Array state */
desiredState: ArrayStateInputState;
};
export enum ArrayStateInputState {
/** Start array */
Start = 'START',
/** Stop array */
Stop = 'STOP'
}
export type Baseboard = {
__typename?: 'Baseboard';
assetTag?: Maybe<Scalars['String']['output']>;
@@ -349,6 +413,8 @@ export type ConnectSettingsValues = {
* If false, the GraphQL sandbox is disabled and only the production API will be available.
*/
sandbox: Scalars['Boolean']['output'];
/** A list of Unique Unraid Account ID's. */
ssoUserIds: Array<Scalars['String']['output']>;
};
export type ConnectSignInInput = {
@@ -496,6 +562,7 @@ export type Docker = Node & {
__typename?: 'Docker';
containers?: Maybe<Array<DockerContainer>>;
id: Scalars['ID']['output'];
mutations: DockerMutations;
networks?: Maybe<Array<DockerNetwork>>;
};
@@ -519,6 +586,22 @@ export type DockerContainer = {
status: Scalars['String']['output'];
};
export type DockerMutations = {
__typename?: 'DockerMutations';
startContainer: DockerContainer;
stopContainer: DockerContainer;
};
export type DockerMutationsstartContainerArgs = {
id: Scalars['ID']['input'];
};
export type DockerMutationsstopContainerArgs = {
id: Scalars['ID']['input'];
};
export type DockerNetwork = {
__typename?: 'DockerNetwork';
attachable: Scalars['Boolean']['output'];
@@ -734,8 +817,6 @@ export type Mount = {
export type Mutation = {
__typename?: 'Mutation';
/** Add new disk to array */
addDiskToArray?: Maybe<ArrayType>;
addPermission: Scalars['Boolean']['output'];
addRoleForApiKey: Scalars['Boolean']['output'];
addRoleForUser: Scalars['Boolean']['output'];
@@ -745,9 +826,9 @@ export type Mutation = {
/** Marks a notification as archived. */
archiveNotification: Notification;
archiveNotifications: NotificationOverview;
array?: Maybe<ArrayMutations>;
/** Cancel parity check */
cancelParityCheck?: Maybe<Scalars['JSON']['output']>;
clearArrayDiskStatistics?: Maybe<Scalars['JSON']['output']>;
connectSignIn: Scalars['Boolean']['output'];
connectSignOut: Scalars['Boolean']['output'];
createApiKey: ApiKeyWithSecret;
@@ -759,29 +840,21 @@ export type Mutation = {
deleteUser?: Maybe<User>;
enableDynamicRemoteAccess: Scalars['Boolean']['output'];
login?: Maybe<Scalars['String']['output']>;
mountArrayDisk?: Maybe<Disk>;
/** Pause parity check */
pauseParityCheck?: Maybe<Scalars['JSON']['output']>;
reboot?: Maybe<Scalars['String']['output']>;
/** Reads each notification to recompute & update the overview. */
recalculateOverview: NotificationOverview;
/** Remove existing disk from array. NOTE: The array must be stopped before running this otherwise it'll throw an error. */
removeDiskFromArray?: Maybe<ArrayType>;
removeRoleFromApiKey: Scalars['Boolean']['output'];
/** Resume parity check */
resumeParityCheck?: Maybe<Scalars['JSON']['output']>;
setAdditionalAllowedOrigins: Array<Scalars['String']['output']>;
setupRemoteAccess: Scalars['Boolean']['output'];
shutdown?: Maybe<Scalars['String']['output']>;
/** Start array */
startArray?: Maybe<ArrayType>;
/** Start parity check */
startParityCheck?: Maybe<Scalars['JSON']['output']>;
/** Stop array */
stopArray?: Maybe<ArrayType>;
unarchiveAll: NotificationOverview;
unarchiveNotifications: NotificationOverview;
unmountArrayDisk?: Maybe<Disk>;
/** Marks a notification as unread. */
unreadNotification: Notification;
/**
@@ -792,11 +865,6 @@ export type Mutation = {
};
export type MutationaddDiskToArrayArgs = {
input?: InputMaybe<arrayDiskInput>;
};
export type MutationaddPermissionArgs = {
input: AddPermissionInput;
};
@@ -832,11 +900,6 @@ export type MutationarchiveNotificationsArgs = {
};
export type MutationclearArrayDiskStatisticsArgs = {
id: Scalars['ID']['input'];
};
export type MutationconnectSignInArgs = {
input: ConnectSignInInput;
};
@@ -874,16 +937,6 @@ export type MutationloginArgs = {
};
export type MutationmountArrayDiskArgs = {
id: Scalars['ID']['input'];
};
export type MutationremoveDiskFromArrayArgs = {
input?: InputMaybe<arrayDiskInput>;
};
export type MutationremoveRoleFromApiKeyArgs = {
input: RemoveRoleFromApiKeyInput;
};
@@ -914,11 +967,6 @@ export type MutationunarchiveNotificationsArgs = {
};
export type MutationunmountArrayDiskArgs = {
id: Scalars['ID']['input'];
};
export type MutationunreadNotificationArgs = {
id: Scalars['String']['input'];
};
@@ -1826,13 +1874,6 @@ export type addUserInput = {
password: Scalars['String']['input'];
};
export type arrayDiskInput = {
/** Disk ID */
id: Scalars['ID']['input'];
/** The slot for the disk */
slot?: InputMaybe<Scalars['Int']['input']>;
};
export type deleteUserInput = {
name: Scalars['String']['input'];
};
@@ -1860,14 +1901,14 @@ export type usersInput = {
export type GetConnectSettingsFormQueryVariables = Exact<{ [key: string]: never; }>;
export type GetConnectSettingsFormQuery = { __typename?: 'Query', connect: { __typename?: 'Connect', id: string, settings: { __typename?: 'ConnectSettings', id: string, dataSchema: any, uiSchema: any, values: { __typename?: 'ConnectSettingsValues', sandbox: boolean, extraOrigins: Array<string>, accessType: WAN_ACCESS_TYPE, forwardType?: WAN_FORWARD_TYPE | null, port?: number | null } } } };
export type GetConnectSettingsFormQuery = { __typename?: 'Query', connect: { __typename?: 'Connect', id: string, settings: { __typename?: 'ConnectSettings', id: string, dataSchema: any, uiSchema: any, values: { __typename?: 'ConnectSettingsValues', sandbox: boolean, extraOrigins: Array<string>, accessType: WAN_ACCESS_TYPE, forwardType?: WAN_FORWARD_TYPE | null, port?: number | null, ssoUserIds: Array<string> } } } };
export type UpdateConnectSettingsMutationVariables = Exact<{
input: ApiSettingsInput;
}>;
export type UpdateConnectSettingsMutation = { __typename?: 'Mutation', updateApiSettings: { __typename?: 'ConnectSettingsValues', sandbox: boolean, extraOrigins: Array<string>, accessType: WAN_ACCESS_TYPE, forwardType?: WAN_FORWARD_TYPE | null, port?: number | null } };
export type UpdateConnectSettingsMutation = { __typename?: 'Mutation', updateApiSettings: { __typename?: 'ConnectSettingsValues', sandbox: boolean, extraOrigins: Array<string>, accessType: WAN_ACCESS_TYPE, forwardType?: WAN_FORWARD_TYPE | null, port?: number | null, ssoUserIds: Array<string> } };
export type LogFilesQueryVariables = Exact<{ [key: string]: never; }>;
@@ -2016,8 +2057,8 @@ export type setupRemoteAccessMutation = { __typename?: 'Mutation', setupRemoteAc
export const NotificationFragmentFragmentDoc = {"kind":"Document","definitions":[{"kind":"FragmentDefinition","name":{"kind":"Name","value":"NotificationFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Notification"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"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":"type"}},{"kind":"Field","name":{"kind":"Name","value":"timestamp"}},{"kind":"Field","name":{"kind":"Name","value":"formattedTimestamp"}}]}}]} as unknown as DocumentNode<NotificationFragmentFragment, unknown>;
export const NotificationCountFragmentFragmentDoc = {"kind":"Document","definitions":[{"kind":"FragmentDefinition","name":{"kind":"Name","value":"NotificationCountFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"NotificationCounts"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"total"}},{"kind":"Field","name":{"kind":"Name","value":"info"}},{"kind":"Field","name":{"kind":"Name","value":"warning"}},{"kind":"Field","name":{"kind":"Name","value":"alert"}}]}}]} as unknown as DocumentNode<NotificationCountFragmentFragment, unknown>;
export const PartialCloudFragmentDoc = {"kind":"Document","definitions":[{"kind":"FragmentDefinition","name":{"kind":"Name","value":"PartialCloud"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Cloud"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"error"}},{"kind":"Field","name":{"kind":"Name","value":"apiKey"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"valid"}},{"kind":"Field","name":{"kind":"Name","value":"error"}}]}},{"kind":"Field","name":{"kind":"Name","value":"cloud"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"status"}},{"kind":"Field","name":{"kind":"Name","value":"error"}}]}},{"kind":"Field","name":{"kind":"Name","value":"minigraphql"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"status"}},{"kind":"Field","name":{"kind":"Name","value":"error"}}]}},{"kind":"Field","name":{"kind":"Name","value":"relay"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"status"}},{"kind":"Field","name":{"kind":"Name","value":"error"}}]}}]}}]} as unknown as DocumentNode<PartialCloudFragment, unknown>;
export const GetConnectSettingsFormDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"GetConnectSettingsForm"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"connect"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"settings"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"dataSchema"}},{"kind":"Field","name":{"kind":"Name","value":"uiSchema"}},{"kind":"Field","name":{"kind":"Name","value":"values"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"sandbox"}},{"kind":"Field","name":{"kind":"Name","value":"extraOrigins"}},{"kind":"Field","name":{"kind":"Name","value":"accessType"}},{"kind":"Field","name":{"kind":"Name","value":"forwardType"}},{"kind":"Field","name":{"kind":"Name","value":"port"}}]}}]}}]}}]}}]} as unknown as DocumentNode<GetConnectSettingsFormQuery, GetConnectSettingsFormQueryVariables>;
export const UpdateConnectSettingsDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"UpdateConnectSettings"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"input"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"ApiSettingsInput"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"updateApiSettings"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"input"},"value":{"kind":"Variable","name":{"kind":"Name","value":"input"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"sandbox"}},{"kind":"Field","name":{"kind":"Name","value":"extraOrigins"}},{"kind":"Field","name":{"kind":"Name","value":"accessType"}},{"kind":"Field","name":{"kind":"Name","value":"forwardType"}},{"kind":"Field","name":{"kind":"Name","value":"port"}}]}}]}}]} as unknown as DocumentNode<UpdateConnectSettingsMutation, UpdateConnectSettingsMutationVariables>;
export const GetConnectSettingsFormDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"GetConnectSettingsForm"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"connect"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"settings"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"dataSchema"}},{"kind":"Field","name":{"kind":"Name","value":"uiSchema"}},{"kind":"Field","name":{"kind":"Name","value":"values"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"sandbox"}},{"kind":"Field","name":{"kind":"Name","value":"extraOrigins"}},{"kind":"Field","name":{"kind":"Name","value":"accessType"}},{"kind":"Field","name":{"kind":"Name","value":"forwardType"}},{"kind":"Field","name":{"kind":"Name","value":"port"}},{"kind":"Field","name":{"kind":"Name","value":"ssoUserIds"}}]}}]}}]}}]}}]} as unknown as DocumentNode<GetConnectSettingsFormQuery, GetConnectSettingsFormQueryVariables>;
export const UpdateConnectSettingsDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"UpdateConnectSettings"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"input"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"ApiSettingsInput"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"updateApiSettings"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"input"},"value":{"kind":"Variable","name":{"kind":"Name","value":"input"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"sandbox"}},{"kind":"Field","name":{"kind":"Name","value":"extraOrigins"}},{"kind":"Field","name":{"kind":"Name","value":"accessType"}},{"kind":"Field","name":{"kind":"Name","value":"forwardType"}},{"kind":"Field","name":{"kind":"Name","value":"port"}},{"kind":"Field","name":{"kind":"Name","value":"ssoUserIds"}}]}}]}}]} as unknown as DocumentNode<UpdateConnectSettingsMutation, UpdateConnectSettingsMutationVariables>;
export const LogFilesDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"LogFiles"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"logFiles"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"path"}},{"kind":"Field","name":{"kind":"Name","value":"size"}},{"kind":"Field","name":{"kind":"Name","value":"modifiedAt"}}]}}]}}]} as unknown as DocumentNode<LogFilesQuery, LogFilesQueryVariables>;
export const LogFileContentDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"LogFileContent"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"path"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"lines"}},"type":{"kind":"NamedType","name":{"kind":"Name","value":"Int"}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"startLine"}},"type":{"kind":"NamedType","name":{"kind":"Name","value":"Int"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"logFile"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"path"},"value":{"kind":"Variable","name":{"kind":"Name","value":"path"}}},{"kind":"Argument","name":{"kind":"Name","value":"lines"},"value":{"kind":"Variable","name":{"kind":"Name","value":"lines"}}},{"kind":"Argument","name":{"kind":"Name","value":"startLine"},"value":{"kind":"Variable","name":{"kind":"Name","value":"startLine"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"path"}},{"kind":"Field","name":{"kind":"Name","value":"content"}},{"kind":"Field","name":{"kind":"Name","value":"totalLines"}},{"kind":"Field","name":{"kind":"Name","value":"startLine"}}]}}]}}]} as unknown as DocumentNode<LogFileContentQuery, LogFileContentQueryVariables>;
export const LogFileSubscriptionDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"subscription","name":{"kind":"Name","value":"LogFileSubscription"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"path"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"logFile"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"path"},"value":{"kind":"Variable","name":{"kind":"Name","value":"path"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"path"}},{"kind":"Field","name":{"kind":"Name","value":"content"}},{"kind":"Field","name":{"kind":"Name","value":"totalLines"}}]}}]}}]} as unknown as DocumentNode<LogFileSubscriptionSubscription, LogFileSubscriptionSubscriptionVariables>;