Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions eshtek/apps.ts
Original file line number Diff line number Diff line change
Expand Up @@ -144,3 +144,9 @@ interface AppsInstallScriptV2 {
}

export type AppsInstallScript = AppsInstallScriptV1 | AppsInstallScriptV2;

export interface InstallScriptCuration {
name: string;
url: string;
script: AppsInstallScript;
}
43 changes: 24 additions & 19 deletions eshtek/errors.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,23 +7,28 @@ export enum GlobalErrorCode {
GENERIC_SERVER_ERROR = 'GENERIC_SERVER_ERROR',
GENERIC_USER_ERROR = 'GENERIC_USER_ERROR',
GENERIC_WEBSOCKET_ERROR = 'GENERIC_WEBSOCKET_ERROR',
SERVER_NOT_CONNECTED = 'Server not currently connected',
INSTALL_APP_NO_APP_ID = 'App id not provided in request',
INSTALL_APP_NOT_SUPPORTED_AND_NO_SCRIPT = 'Supported app not found and no install script provided',
INSTALL_APP_NO_TRAIN_PROVIDED = 'Train is required if install script is provided',
INSTALL_APP_DOCKER_HUB_RATE_LIMIT = 'Docker Hub rate limit exceeded, wait a few hours for it to reset',
PROCESS_INSTALL_SCRIPT_FAILED_JSON_PARSE = 'Failed to JSON parse install script',
PROCESS_INSTALL_SCRIPT_INVALID_JSON = 'Install script must be a valid JSON object',
PROCESS_INSTALL_SCRIPT_MISSING_VERSION = 'Install script must have a "version" field',
PROCESS_INSTALL_SCRIPT_UNSUPPORTED_VERSION = 'Unsupported install script version',
PROCESS_INSTALL_SCRIPT_MISSING_APP_VALUES = 'Install script must have an "app_values" field',
PROCESS_INSTALL_SCRIPT_UNKNOWN_LOCATION = 'Install script has an unknown location',
PROCESS_INSTALL_SCRIPT_INVALID_RANDOM_STRING_LENGTH = 'Install script has an invalid random string length',
PROCESS_INSTALL_SCRIPT_FAILED_JSON_PARSE_AFTER = 'Failed to JSON parse install script after processing',
PROCESS_INSTALL_SCRIPT_INVALID_MEMORY_PERCENTAGE = 'Install script has an invalid memory percentage',
PROCESS_INSTALL_SCRIPT_INVALID_MEMORY_VALUE = 'Install script has an invalid memory value',
PROCESS_INSTALL_SCRIPT_MISSING_QUESTION_RESPONSE = 'Install script requires a response for a question',
PROCESS_INSTALL_SCRIPT_INVALID_QUESTION_RESPONSE_TYPE = 'Install script question response has invalid type',
RUN_INSTALL_SCRIPT_UNSUPPORTED_VERSION = 'Install script must have a "version" field',
DDP_CLIENT_DISCONNECTED = 'DDPClient disconnected from DDP server',
SERVER_NOT_CONNECTED = 'SERVER_NOT_CONNECTED',
SERVER_NOT_FOUND = 'SERVER_NOT_FOUND',
SERVER_UPDATE_ALREADY_IN_PROGRESS = 'SERVER_UPDATE_ALREADY_IN_PROGRESS',
SERVER_UPDATE_NOT_AVAILABLE = 'SERVER_UPDATE_NOT_AVAILABLE',
SERVER_UPDATE_NOT_SUPPORTED = 'SERVER_UPDATE_NOT_SUPPORTED',
EMAIL_ACTION_INVALID_KEY = 'EMAIL_ACTION_INVALID_KEY',
INSTALL_APP_NO_APP_ID = 'INSTALL_APP_NO_APP_ID',
INSTALL_APP_NOT_SUPPORTED_AND_NO_SCRIPT = 'INSTALL_APP_NOT_SUPPORTED_AND_NO_SCRIPT',
INSTALL_APP_NO_TRAIN_PROVIDED = 'INSTALL_APP_NO_TRAIN_PROVIDED',
INSTALL_APP_DOCKER_HUB_RATE_LIMIT = 'INSTALL_APP_DOCKER_HUB_RATE_LIMIT',
PROCESS_INSTALL_SCRIPT_FAILED_JSON_PARSE = 'PROCESS_INSTALL_SCRIPT_FAILED_JSON_PARSE',
PROCESS_INSTALL_SCRIPT_INVALID_JSON = 'PROCESS_INSTALL_SCRIPT_INVALID_JSON',
PROCESS_INSTALL_SCRIPT_MISSING_VERSION = 'PROCESS_INSTALL_SCRIPT_MISSING_VERSION',
PROCESS_INSTALL_SCRIPT_UNSUPPORTED_VERSION = 'PROCESS_INSTALL_SCRIPT_UNSUPPORTED_VERSION',
PROCESS_INSTALL_SCRIPT_MISSING_APP_VALUES = 'PROCESS_INSTALL_SCRIPT_MISSING_APP_VALUES',
PROCESS_INSTALL_SCRIPT_UNKNOWN_LOCATION = 'PROCESS_INSTALL_SCRIPT_UNKNOWN_LOCATION',
PROCESS_INSTALL_SCRIPT_INVALID_RANDOM_STRING_LENGTH = 'PROCESS_INSTALL_SCRIPT_INVALID_RANDOM_STRING_LENGTH',
PROCESS_INSTALL_SCRIPT_FAILED_JSON_PARSE_AFTER = 'PROCESS_INSTALL_SCRIPT_FAILED_JSON_PARSE_AFTER',
PROCESS_INSTALL_SCRIPT_INVALID_MEMORY_PERCENTAGE = 'PROCESS_INSTALL_SCRIPT_INVALID_MEMORY_PERCENTAGE',
PROCESS_INSTALL_SCRIPT_INVALID_MEMORY_VALUE = 'PROCESS_INSTALL_SCRIPT_INVALID_MEMORY_VALUE',
PROCESS_INSTALL_SCRIPT_MISSING_QUESTION_RESPONSE = 'PROCESS_INSTALL_SCRIPT_MISSING_QUESTION_RESPONSE',
PROCESS_INSTALL_SCRIPT_INVALID_QUESTION_RESPONSE_TYPE = 'PROCESS_INSTALL_SCRIPT_INVALID_QUESTION_RESPONSE_TYPE',
RUN_INSTALL_SCRIPT_UNSUPPORTED_VERSION = 'RUN_INSTALL_SCRIPT_UNSUPPORTED_VERSION',
DDP_CLIENT_DISCONNECTED = 'DDP_CLIENT_DISCONNECTED',
}
8 changes: 8 additions & 0 deletions eshtek/server-schema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -197,6 +197,14 @@ export const serverHealthSchema = z.object({
actions_available: z.array(serverActionsSchema),
});

export const serverUpgradeInfoSchema = z.object({
serverName: z.string(),
hostId: z.string(),
currentVersion: z.string(),
targetVersion: z.string(),
updateStatus: z.string(),
});

const diskTypeSchema = z.any();

const poolStatusSchema = z.any();
Expand Down
8 changes: 8 additions & 0 deletions eshtek/server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -407,3 +407,11 @@ export interface ServerHealth {
warnings: ServerHealthWarning[];
actions_available: ServerActions[];
}

export interface ServerUpgradeInfo {
serverName: string;
hostId: string;
currentVersion: string;
targetVersion: string;
updateStatus: string;
}
87 changes: 87 additions & 0 deletions eshtek/versions.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
export interface VersionParts {
year: number;
month: number;
build: number;
patch: number;
}

export const parseVersion = (version: string): VersionParts => {
const cleanVersion = version.split('-')[0];
const parts = cleanVersion.split('.').map(p => {
const num = Number(p);
return isNaN(num) ? 0 : num;
});
return {
year: parts[0] || 0,
month: parts[1] || 0,
build: parts[2] || 0,
patch: parts[3] || 0,
};
};

export const compareVersions = (a: VersionParts, b: VersionParts): number => {
if (a.year !== b.year) return a.year - b.year;
if (a.month !== b.month) return a.month - b.month;
if (a.build !== b.build) return a.build - b.build;
return a.patch - b.patch;
};

export const parseRange = (range: string): { min?: VersionParts; max?: VersionParts; minInclusive: boolean; maxInclusive: boolean } => {
const parts = range.split(/\s+/);
let min: VersionParts | undefined;
let max: VersionParts | undefined;
let minInclusive = false;
let maxInclusive = false;

for (let i = 0; i < parts.length; i++) {
const part = parts[i];
if (part.startsWith('>=')) {
min = parseVersion(part.substring(2));
minInclusive = true;
} else if (part.startsWith('>')) {
min = parseVersion(part.substring(1));
minInclusive = false;
} else if (part.startsWith('<=')) {
max = parseVersion(part.substring(2));
maxInclusive = true;
} else if (part.startsWith('<')) {
max = parseVersion(part.substring(1));
maxInclusive = false;
}
}

return { min, max, minInclusive, maxInclusive };
};

export const isTrueNASVersionInRange = (buildVersion: string, versionRange: string): boolean => {
if (!buildVersion) {
return false;
}

try {
const version = parseVersion(buildVersion);
const { min, max, minInclusive, maxInclusive } = parseRange(versionRange);

if (min) {
const cmp = compareVersions(version, min);
if (minInclusive) {
if (cmp < 0) return false;
} else {
if (cmp <= 0) return false;
}
}

if (max) {
const cmp = compareVersions(version, max);
if (maxInclusive) {
if (cmp > 0) return false;
} else {
if (cmp >= 0) return false;
}
}

return true;
} catch (error) {
return false;
}
};
2 changes: 1 addition & 1 deletion package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

26 changes: 25 additions & 1 deletion truenas/webui/interfaces/api/api-call-directory.interface.ts
Original file line number Diff line number Diff line change
Expand Up @@ -881,6 +881,17 @@ export interface ApiCallDirectory {
params: [ServiceName, { silent: boolean }];
response: boolean; // False indicates that service has been stopped.
};
'service.reload': {
params: [
service: string,
options?: {
ha_propagate?: boolean;
silent?: boolean;
timeout?: number | null;
}
];
response: boolean;
};
'service.update': { params: [number | ServiceName, Partial<Service>]; response: number };

// Sharing
Expand All @@ -902,7 +913,20 @@ export interface ApiCallDirectory {
response: null | { reason: string };
};
'sharing.smb.update': { params: [id: number, update: SmbShareUpdate]; response: SmbShare };
'sharing.smb.sync_registry': { params: []}
'sharing.smb.sync_registry': { params: []; response: void };

// Etc
'etc.generate': {
params: [
name: string,
checkpoint?: 'initial' | 'interface_sync' | 'post_init' | 'pool_import' | 'pre_interface_sync' | null
];
response: Array<{
path: string;
status: 'CHANGED' | 'REMOVED';
changes: string[];
}>;
};

// SMART
'smart.config': { params: void; response: SmartConfig };
Expand Down