diff --git a/ts_interfaces/requests/task.ts b/ts_interfaces/requests/task.ts index 492d46e..7d4c4c6 100644 --- a/ts_interfaces/requests/task.ts +++ b/ts_interfaces/requests/task.ts @@ -1,5 +1,6 @@ import * as plugins from '../plugins.js'; import * as data from '../data/index.js'; +import * as userInterfaces from '../data/user.js'; // Get all tasks export interface IRequest_Any_Cloudly_GetTasks @@ -8,7 +9,9 @@ export interface IRequest_Any_Cloudly_GetTasks IRequest_Any_Cloudly_GetTasks > { method: 'getTasks'; - request: {}; + request: { + identity: userInterfaces.IIdentity; + }; response: { tasks: Array<{ name: string; @@ -29,6 +32,7 @@ export interface IRequest_Any_Cloudly_GetTaskExecutions > { method: 'getTaskExecutions'; request: { + identity: userInterfaces.IIdentity; filter?: { taskName?: string; status?: string; @@ -49,6 +53,7 @@ export interface IRequest_Any_Cloudly_GetTaskExecutionById > { method: 'getTaskExecutionById'; request: { + identity: userInterfaces.IIdentity; executionId: string; }; response: { @@ -64,6 +69,7 @@ export interface IRequest_Any_Cloudly_TriggerTask > { method: 'triggerTask'; request: { + identity: userInterfaces.IIdentity; taskName: string; userId?: string; }; @@ -80,6 +86,7 @@ export interface IRequest_Any_Cloudly_CancelTask > { method: 'cancelTask'; request: { + identity: userInterfaces.IIdentity; executionId: string; }; response: { diff --git a/ts_web/appstate.ts b/ts_web/appstate.ts index 917294c..bceb163 100644 --- a/ts_web/appstate.ts +++ b/ts_web/appstate.ts @@ -53,6 +53,8 @@ export interface IDataState { deployments?: plugins.interfaces.data.IDeployment[]; domains?: plugins.interfaces.data.IDomain[]; dnsEntries?: plugins.interfaces.data.IDnsEntry[]; + tasks?: any[]; + taskExecutions?: plugins.interfaces.data.ITaskExecution[]; mails?: any[]; logs?: any[]; s3?: any[]; @@ -71,6 +73,8 @@ export const dataState = await appstate.getStatePart( deployments: [], domains: [], dnsEntries: [], + tasks: [], + taskExecutions: [], mails: [], logs: [], s3: [], @@ -676,7 +680,10 @@ export const taskActions = { const response = await trGetTasks.fire({ identity: loginStatePart.getState().identity, }); - return response as any; + return { + ...currentState, + tasks: response.tasks, + }; } ), @@ -692,7 +699,10 @@ export const taskActions = { identity: loginStatePart.getState().identity, filter: payloadArg.filter, }); - return response as any; + return { + ...currentState, + taskExecutions: response.executions, + }; } ), @@ -708,7 +718,7 @@ export const taskActions = { identity: loginStatePart.getState().identity, executionId: payloadArg.executionId, }); - return response as any; + return currentState; } ), diff --git a/ts_web/elements/cloudly-dashboard.ts b/ts_web/elements/cloudly-dashboard.ts index 513c0f2..fc60194 100644 --- a/ts_web/elements/cloudly-dashboard.ts +++ b/ts_web/elements/cloudly-dashboard.ts @@ -44,6 +44,105 @@ export class CloudlyDashboard extends DeesElement { clusters: [], }; + // Keep view tabs stable across renders to preserve active selection + private readonly viewTabs: plugins.deesCatalog.IView[] = [ + { + name: 'Overview', + iconName: 'lucide:LayoutDashboard', + element: CloudlyViewOverview, + }, + { + name: 'Settings', + iconName: 'lucide:Settings', + element: CloudlyViewSettings, + }, + { + name: 'SecretGroups', + iconName: 'lucide:ShieldCheck', + element: CloudlyViewSecretGroups, + }, + { + name: 'SecretBundles', + iconName: 'lucide:LockKeyhole', + element: CloudlyViewSecretBundles, + }, + { + name: 'Clusters', + iconName: 'lucide:Network', + element: CloudlyViewClusters, + }, + { + name: 'ExternalRegistries', + iconName: 'lucide:Package', + element: CloudlyViewExternalRegistries, + }, + { + name: 'Images', + iconName: 'lucide:Image', + element: CloudlyViewImages, + }, + { + name: 'Services', + iconName: 'lucide:Layers', + element: CloudlyViewServices, + }, + { + name: 'Testing & Building', + iconName: 'lucide:HardHat', + element: CloudlyViewServices, + }, + { + name: 'Deployments', + iconName: 'lucide:Rocket', + element: CloudlyViewDeployments, + }, + { + name: 'Tasks', + iconName: 'lucide:ListChecks', + element: CloudlyViewTasks, + }, + { + name: 'Domains', + iconName: 'lucide:Globe2', + element: CloudlyViewDomains, + }, + { + name: 'DNS', + iconName: 'lucide:Globe', + element: CloudlyViewDns, + }, + { + name: 'Mails', + iconName: 'lucide:Mail', + element: CloudlyViewMails, + }, + { + name: 'Logs', + iconName: 'lucide:FileText', + element: CloudlyViewLogs, + }, + { + name: 's3', + iconName: 'lucide:Cloud', + element: CloudlyViewS3, + }, + { + name: 'DBs', + iconName: 'lucide:Database', + element: CloudlyViewDbs, + }, + { + name: 'Backups', + iconName: 'lucide:Save', + element: CloudlyViewBackups, + }, + { + name: 'Fleet', + iconName: 'lucide:Truck', + element: CloudlyViewBackups, + }, + ]; + constructor() { super(); document.title = `cloudly v${commitinfo.version}`; @@ -76,103 +175,7 @@ export class CloudlyDashboard extends DeesElement {
diff --git a/ts_web/elements/cloudly-view-tasks.ts b/ts_web/elements/cloudly-view-tasks.ts index f0c5fa5..521038e 100644 --- a/ts_web/elements/cloudly-view-tasks.ts +++ b/ts_web/elements/cloudly-view-tasks.ts @@ -18,12 +18,6 @@ export class CloudlyViewTasks extends DeesElement { @state() private data: appstate.IDataState = {}; - @state() - private tasks: any[] = []; - - @state() - private executions: plugins.interfaces.data.ITaskExecution[] = []; - @state() private selectedExecution: plugins.interfaces.data.ITaskExecution | null = null; @@ -41,6 +35,18 @@ export class CloudlyViewTasks extends DeesElement { this.data = dataArg; }); this.rxSubscriptions.push(subscription); + + // Load initial data (non-blocking) + this.loadInitialData(); + } + + private async loadInitialData() { + try { + await appstate.dataState.dispatchAction(appstate.taskActions.getTasks, {}); + await appstate.dataState.dispatchAction(appstate.taskActions.getTaskExecutions, {}); + } catch (error) { + console.error('Failed to load initial task data:', error); + } } public static styles = [ @@ -276,41 +282,6 @@ export class CloudlyViewTasks extends DeesElement { `, ]; - async connectedCallback() { - super.connectedCallback(); - await this.loadTasks(); - await this.loadExecutions(); - } - - private async loadTasks() { - this.loading = true; - try { - const response: any = await appstate.dataState.dispatchAction( - appstate.taskActions.getTasks, {} - ); - this.tasks = response.tasks || []; - } catch (error) { - console.error('Failed to load tasks:', error); - } finally { - this.loading = false; - } - } - - private async loadExecutions() { - try { - const filter: any = {}; - if (this.filterStatus !== 'all') { - filter.status = this.filterStatus; - } - - const response: any = await appstate.dataState.dispatchAction( - appstate.taskActions.getTaskExecutions, { filter } - ); - this.executions = response.executions || []; - } catch (error) { - console.error('Failed to load executions:', error); - } - } private async triggerTask(taskName: string) { try { @@ -319,13 +290,28 @@ export class CloudlyViewTasks extends DeesElement { ); // Reload tasks and executions to show the new execution - await this.loadTasks(); - await this.loadExecutions(); + await appstate.dataState.dispatchAction(appstate.taskActions.getTasks, {}); + await this.loadExecutionsWithFilter(); } catch (error) { console.error('Failed to trigger task:', error); } } + private async loadExecutionsWithFilter() { + try { + const filter: any = {}; + if (this.filterStatus !== 'all') { + filter.status = this.filterStatus; + } + + await appstate.dataState.dispatchAction( + appstate.taskActions.getTaskExecutions, { filter } + ); + } catch (error) { + console.error('Failed to load executions:', error); + } + } + private formatDate(timestamp: number): string { return new Date(timestamp).toLocaleString(); } @@ -359,7 +345,8 @@ export class CloudlyViewTasks extends DeesElement { } private renderTaskCard(task: any) { - const lastExecution = this.executions + const executions = this.data.taskExecutions || []; + const lastExecution = executions .filter(e => e.data.taskName === task.name) .sort((a, b) => (b.data.startedAt || 0) - (a.data.startedAt || 0))[0]; @@ -495,32 +482,32 @@ export class CloudlyViewTasks extends DeesElement {
- ${this.tasks.map(task => this.renderTaskCard(task))} + ${(this.data.tasks || []).map(task => this.renderTaskCard(task))}
Execution History @@ -528,7 +515,7 @@ export class CloudlyViewTasks extends DeesElement { { return { Task: itemArg.data.taskName,