Skip to content

Commit 7897e72

Browse files
authored
Merge pull request #75 from eshtek/feature/apps-overhaul
Shared changes to support all the feature/apps-overhaul branches
2 parents 3ba7bd4 + 96afab8 commit 7897e72

8 files changed

Lines changed: 251 additions & 4 deletions

File tree

eshtek/admin.types.ts

Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
/**
2+
* Admin API Types and Interfaces
3+
*/
4+
5+
/**
6+
* Response from the catalog status endpoint
7+
*/
8+
export interface CatalogStatusResponse {
9+
totalApps: number;
10+
totalNonDeprecated: number;
11+
totalWithScripts: number;
12+
totalWithScriptsNonDeprecated: number;
13+
totalDeprecated: number;
14+
lastSync: Date | null;
15+
}
16+
17+
/**
18+
* Individual app in the catalog
19+
*/
20+
export interface CatalogApp {
21+
id: number;
22+
name: string;
23+
train: string | null;
24+
version: string | null;
25+
appVersion: string | null;
26+
title: string | null;
27+
description: string | null;
28+
home: string | null;
29+
iconUrl: string | null;
30+
screenshots: string[];
31+
sources: string[];
32+
categories: string[];
33+
keywords: string[];
34+
maintainers: any[];
35+
supported: boolean;
36+
deprecated: boolean;
37+
installScript: string | null;
38+
requirements: any;
39+
compatibility: string | null;
40+
lastCatalogSync: Date | null;
41+
metadata: any;
42+
// Event statistics (detailed)
43+
installsCompleted?: number;
44+
installsFailed?: number;
45+
uninstallsCompleted?: number;
46+
uninstallsFailed?: number;
47+
upgradesCompleted?: number;
48+
upgradesFailed?: number;
49+
updatesCompleted?: number;
50+
updatesFailed?: number;
51+
}
52+
53+
/**
54+
* Response from the catalog data endpoint
55+
*/
56+
export interface AppsCatalogResponse {
57+
apps: CatalogApp[];
58+
totalApps: number;
59+
totalWithScripts: number;
60+
totalDeprecated: number;
61+
lastSync: Date | null;
62+
}
63+
64+
/**
65+
* Drive data with event statistics
66+
*/
67+
export interface DriveData {
68+
id: number;
69+
manufacturer: string;
70+
model: string;
71+
name: string | null;
72+
type: string | null;
73+
size: number | null;
74+
smr: boolean;
75+
notes: string | null;
76+
isUserDiscovered: boolean;
77+
createdAt: Date;
78+
updatedAt: Date;
79+
// Event statistics
80+
utilized: number;
81+
replaced: number;
82+
removed: number;
83+
failed: number;
84+
discovered: number;
85+
}
86+
87+
/**
88+
* Response from the drives data endpoint
89+
*/
90+
export interface DrivesResponse {
91+
drives: DriveData[];
92+
totalDrives: number;
93+
totalSMR: number;
94+
totalUtilized: number;
95+
totalFailed: number;
96+
totalRemoved: number;
97+
}

eshtek/apps.ts

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -59,8 +59,28 @@ export interface AppRequirementsCheck {
5959
};
6060
}
6161

62-
export interface AppListing extends AvailableApp {
63-
hexos: boolean;
62+
export interface AppMaintainer {
63+
name: string;
64+
email: string;
65+
}
66+
67+
export interface AppListing {
68+
appId: string;
69+
name: string;
70+
train: "stable" | "community";
71+
version: string;
72+
appVersion: string;
73+
description: string;
74+
icon: string;
75+
categories: string[];
76+
keywords: string[];
77+
maintainers: AppMaintainer[];
78+
screenshots: string[];
79+
sources: string[];
80+
homepage: string;
81+
recommended: boolean;
82+
supported: boolean;
83+
fresh: boolean;
6484
installScript?: string;
6585
requirements?: AppRequirements;
6686
}
@@ -120,6 +140,7 @@ export interface InstallationQuestion {
120140

121141
interface AppsInstallScriptV1 {
122142
version: 1;
143+
requirements?: AppRequirements;
123144
ensure_directories_exists?: Array<string | { path: string; network_share?: boolean; posix?: boolean }>;
124145
ensure_permissions_exists?: Array<{
125146
path: string;
@@ -132,6 +153,7 @@ interface AppsInstallScriptV1 {
132153

133154
interface AppsInstallScriptV2 {
134155
version: 2;
156+
requirements?: AppRequirements;
135157
installation_questions?: InstallationQuestion[];
136158
ensure_directories_exists?: Array<string | { path: string; network_share?: boolean; posix?: boolean }>;
137159
ensure_permissions_exists?: Array<{

eshtek/common.ts

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -505,3 +505,16 @@ export function getStepSize(range: number, steps: number = 10, acceptableSteps:
505505
return Math.abs(curr - rawStep) < Math.abs(prev - rawStep) ? curr : prev;
506506
});
507507
}
508+
509+
import type { HexTaskType } from './tasks';
510+
import type { EventState, TaskEventName } from './events';
511+
512+
/**
513+
* Generates a task event name from a task type and event state.
514+
* @param {HexTaskType} taskType - The type of the task.
515+
* @param {EventState} state - The state of the event (started, completed, failed).
516+
* @returns {TaskEventName} - Returns the generated event name (e.g., 'app_install_started').
517+
*/
518+
export function getTaskEventName(taskType: HexTaskType, state: EventState): TaskEventName {
519+
return `${taskType.toLowerCase()}_${state}` as TaskEventName;
520+
}

eshtek/events.ts

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
import type { HexTaskType } from './tasks';
2+
3+
export interface BaseEvent {
4+
eventName: string;
5+
userId: string;
6+
hostId?: string;
7+
timestamp: Date;
8+
properties?: Record<string, any>;
9+
}
10+
11+
export interface TaskEvent extends BaseEvent {
12+
taskId: string;
13+
taskType: HexTaskType;
14+
taskStatus: string;
15+
errorMessage?: string;
16+
}
17+
18+
export interface AppEvent extends TaskEvent {
19+
appId: string;
20+
appTrain?: string;
21+
appVersion?: string;
22+
appTrueNasVersion?: string;
23+
}
24+
25+
export enum EventState {
26+
STARTED = 'started',
27+
COMPLETED = 'completed',
28+
FAILED = 'failed',
29+
DISMISSED = 'dismissed',
30+
}
31+
32+
export type TaskEventName = `${Lowercase<`${HexTaskType}`>}_${EventState}`;
33+
34+
export const SystemEventNames = {
35+
SERVER_CONNECTED: 'server_connected',
36+
SERVER_DISCONNECTED: 'server_disconnected',
37+
USER_LOGIN: 'user_login',
38+
USER_LOGOUT: 'user_logout',
39+
DRIVE_UTILIZED: 'drive_utilized', // Drive added to a pool
40+
DRIVE_REPLACED: 'drive_replaced',
41+
DRIVE_REMOVED: 'drive_removed',
42+
DRIVE_FAILED: 'drive_failed',
43+
DRIVE_HEALTHY: 'drive_healthy', // Drive has no errors
44+
DRIVE_DISCOVERED: 'drive_discovered', // Drive found on system (assigned or unassigned)
45+
APP_DISCOVERED: 'app_discovered', // App found on system
46+
} as const;
47+
48+
export type SystemEventName = typeof SystemEventNames[keyof typeof SystemEventNames];
49+
export type EventName = TaskEventName | SystemEventName;
50+
51+
export interface EventQueryOptions {
52+
eventName?: EventName | EventName[];
53+
userId?: string;
54+
hostId?: string;
55+
taskType?: HexTaskType;
56+
appId?: string;
57+
appTrain?: string;
58+
appVersion?: string;
59+
startDate?: Date;
60+
endDate?: Date;
61+
limit?: number;
62+
}
63+
64+
export interface AppPopularityMetrics {
65+
appId: string;
66+
installCount: number;
67+
uninstallCount: number;
68+
upgradeCount: number;
69+
failureCount: number;
70+
lastInstalled: Date;
71+
}

eshtek/routes.ts

Lines changed: 43 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -124,4 +124,46 @@ export interface RequestAppInstall {
124124

125125
export interface RequestAppDelete {
126126
deleteData?: boolean;
127-
}
127+
}
128+
129+
export enum AppSearchSortBy {
130+
NAME = 'name',
131+
POPULARITY = 'popularity',
132+
CREATED_AT = 'createdAt',
133+
UPDATED_AT = 'updatedAt',
134+
}
135+
136+
export enum AppSearchSortOrder {
137+
ASC = 'asc',
138+
DESC = 'desc',
139+
}
140+
141+
export interface RequestAppSearch {
142+
appId?: string;
143+
search?: string;
144+
category?: string;
145+
fresh?: boolean;
146+
supported?: boolean;
147+
recommended?: boolean;
148+
train?: 'stable' | 'community';
149+
sortBy?: AppSearchSortBy;
150+
sortOrder?: AppSearchSortOrder;
151+
popularityStartDate?: string;
152+
popularityEndDate?: string;
153+
page?: number;
154+
pageSize?: number;
155+
limit?: number; // -1 means return all results
156+
}
157+
158+
export interface AppCategoryInfo {
159+
name: string;
160+
appCount: number;
161+
}
162+
163+
export interface RequestAppCategories {
164+
train?: 'stable' | 'community';
165+
supported?: boolean;
166+
fresh?: boolean;
167+
}
168+
169+
export type ResponseAppCategories = Response<AppCategoryInfo[]>;

eshtek/server-schema.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -241,6 +241,7 @@ export const serverDriveSchema = z.object({
241241
existingData: z.boolean().optional(),
242242
temperature: z.number().optional(),
243243
healthDetails: topologyItemStatusSchema.optional(),
244+
driveId: z.number().optional(),
244245
});
245246

246247
export const serverPoolNewSchema = serverPoolBasicsSchema.extend({

eshtek/server.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -244,6 +244,7 @@ export interface ServerDrive {
244244
existingData?: boolean;
245245
temperature?: number;
246246
healthDetails?: TopologyItemStatus;
247+
driveId?: number; // Database ID from drives table
247248
}
248249

249250
export interface ServerDrivesGroupedBySize {

eshtek/tasks.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -147,7 +147,7 @@ export type HexTaskDataMap = {
147147
export const HexTaskSettings: {
148148
[K in HexTaskType]: HexTaskTypeInfo;
149149
} = {
150-
[HexTaskType.RESTART]: { canHaveMultiple: false, predictedSecondsToComplete: 120 },
150+
[HexTaskType.RESTART]: { canHaveMultiple: false, predictedSecondsToComplete: 500 },
151151
[HexTaskType.SHUTDOWN]: { canHaveMultiple: false, predictedSecondsToComplete: 120 },
152152
[HexTaskType.NETWORK_UPDATE]: { canHaveMultiple: false, predictedSecondsToComplete: 90 },
153153
[HexTaskType.POOL_CREATE]: { canHaveMultiple: true, predictedSecondsToComplete: 30 },

0 commit comments

Comments
 (0)