feat(tasks): Enhance task management with identity handling and initial data loading
This commit is contained in:
@@ -1,5 +1,6 @@
|
|||||||
import * as plugins from '../plugins.js';
|
import * as plugins from '../plugins.js';
|
||||||
import * as data from '../data/index.js';
|
import * as data from '../data/index.js';
|
||||||
|
import * as userInterfaces from '../data/user.js';
|
||||||
|
|
||||||
// Get all tasks
|
// Get all tasks
|
||||||
export interface IRequest_Any_Cloudly_GetTasks
|
export interface IRequest_Any_Cloudly_GetTasks
|
||||||
@@ -8,7 +9,9 @@ export interface IRequest_Any_Cloudly_GetTasks
|
|||||||
IRequest_Any_Cloudly_GetTasks
|
IRequest_Any_Cloudly_GetTasks
|
||||||
> {
|
> {
|
||||||
method: 'getTasks';
|
method: 'getTasks';
|
||||||
request: {};
|
request: {
|
||||||
|
identity: userInterfaces.IIdentity;
|
||||||
|
};
|
||||||
response: {
|
response: {
|
||||||
tasks: Array<{
|
tasks: Array<{
|
||||||
name: string;
|
name: string;
|
||||||
@@ -29,6 +32,7 @@ export interface IRequest_Any_Cloudly_GetTaskExecutions
|
|||||||
> {
|
> {
|
||||||
method: 'getTaskExecutions';
|
method: 'getTaskExecutions';
|
||||||
request: {
|
request: {
|
||||||
|
identity: userInterfaces.IIdentity;
|
||||||
filter?: {
|
filter?: {
|
||||||
taskName?: string;
|
taskName?: string;
|
||||||
status?: string;
|
status?: string;
|
||||||
@@ -49,6 +53,7 @@ export interface IRequest_Any_Cloudly_GetTaskExecutionById
|
|||||||
> {
|
> {
|
||||||
method: 'getTaskExecutionById';
|
method: 'getTaskExecutionById';
|
||||||
request: {
|
request: {
|
||||||
|
identity: userInterfaces.IIdentity;
|
||||||
executionId: string;
|
executionId: string;
|
||||||
};
|
};
|
||||||
response: {
|
response: {
|
||||||
@@ -64,6 +69,7 @@ export interface IRequest_Any_Cloudly_TriggerTask
|
|||||||
> {
|
> {
|
||||||
method: 'triggerTask';
|
method: 'triggerTask';
|
||||||
request: {
|
request: {
|
||||||
|
identity: userInterfaces.IIdentity;
|
||||||
taskName: string;
|
taskName: string;
|
||||||
userId?: string;
|
userId?: string;
|
||||||
};
|
};
|
||||||
@@ -80,6 +86,7 @@ export interface IRequest_Any_Cloudly_CancelTask
|
|||||||
> {
|
> {
|
||||||
method: 'cancelTask';
|
method: 'cancelTask';
|
||||||
request: {
|
request: {
|
||||||
|
identity: userInterfaces.IIdentity;
|
||||||
executionId: string;
|
executionId: string;
|
||||||
};
|
};
|
||||||
response: {
|
response: {
|
||||||
|
@@ -53,6 +53,8 @@ export interface IDataState {
|
|||||||
deployments?: plugins.interfaces.data.IDeployment[];
|
deployments?: plugins.interfaces.data.IDeployment[];
|
||||||
domains?: plugins.interfaces.data.IDomain[];
|
domains?: plugins.interfaces.data.IDomain[];
|
||||||
dnsEntries?: plugins.interfaces.data.IDnsEntry[];
|
dnsEntries?: plugins.interfaces.data.IDnsEntry[];
|
||||||
|
tasks?: any[];
|
||||||
|
taskExecutions?: plugins.interfaces.data.ITaskExecution[];
|
||||||
mails?: any[];
|
mails?: any[];
|
||||||
logs?: any[];
|
logs?: any[];
|
||||||
s3?: any[];
|
s3?: any[];
|
||||||
@@ -71,6 +73,8 @@ export const dataState = await appstate.getStatePart<IDataState>(
|
|||||||
deployments: [],
|
deployments: [],
|
||||||
domains: [],
|
domains: [],
|
||||||
dnsEntries: [],
|
dnsEntries: [],
|
||||||
|
tasks: [],
|
||||||
|
taskExecutions: [],
|
||||||
mails: [],
|
mails: [],
|
||||||
logs: [],
|
logs: [],
|
||||||
s3: [],
|
s3: [],
|
||||||
@@ -676,7 +680,10 @@ export const taskActions = {
|
|||||||
const response = await trGetTasks.fire({
|
const response = await trGetTasks.fire({
|
||||||
identity: loginStatePart.getState().identity,
|
identity: loginStatePart.getState().identity,
|
||||||
});
|
});
|
||||||
return response as any;
|
return {
|
||||||
|
...currentState,
|
||||||
|
tasks: response.tasks,
|
||||||
|
};
|
||||||
}
|
}
|
||||||
),
|
),
|
||||||
|
|
||||||
@@ -692,7 +699,10 @@ export const taskActions = {
|
|||||||
identity: loginStatePart.getState().identity,
|
identity: loginStatePart.getState().identity,
|
||||||
filter: payloadArg.filter,
|
filter: payloadArg.filter,
|
||||||
});
|
});
|
||||||
return response as any;
|
return {
|
||||||
|
...currentState,
|
||||||
|
taskExecutions: response.executions,
|
||||||
|
};
|
||||||
}
|
}
|
||||||
),
|
),
|
||||||
|
|
||||||
@@ -708,7 +718,7 @@ export const taskActions = {
|
|||||||
identity: loginStatePart.getState().identity,
|
identity: loginStatePart.getState().identity,
|
||||||
executionId: payloadArg.executionId,
|
executionId: payloadArg.executionId,
|
||||||
});
|
});
|
||||||
return response as any;
|
return currentState;
|
||||||
}
|
}
|
||||||
),
|
),
|
||||||
|
|
||||||
|
@@ -44,39 +44,8 @@ export class CloudlyDashboard extends DeesElement {
|
|||||||
clusters: [],
|
clusters: [],
|
||||||
};
|
};
|
||||||
|
|
||||||
constructor() {
|
// Keep view tabs stable across renders to preserve active selection
|
||||||
super();
|
private readonly viewTabs: plugins.deesCatalog.IView[] = [
|
||||||
document.title = `cloudly v${commitinfo.version}`;
|
|
||||||
const subcription = appstate.dataState
|
|
||||||
.select((stateArg) => stateArg)
|
|
||||||
.subscribe((dataArg) => {
|
|
||||||
this.data = dataArg;
|
|
||||||
});
|
|
||||||
this.rxSubscriptions.push(subcription);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static styles = [
|
|
||||||
cssManager.defaultStyles,
|
|
||||||
css`
|
|
||||||
.maincontainer {
|
|
||||||
position: relative;
|
|
||||||
width: 100vw;
|
|
||||||
height: 100vh;
|
|
||||||
}
|
|
||||||
|
|
||||||
h1 {
|
|
||||||
font-weight: 400;
|
|
||||||
font-size: 24px;
|
|
||||||
font-family: 'Cal Sans';
|
|
||||||
}
|
|
||||||
`,
|
|
||||||
];
|
|
||||||
public render() {
|
|
||||||
return html`
|
|
||||||
<div class="maincontainer">
|
|
||||||
<dees-simple-login name="cloudly v${commitinfo.version}">
|
|
||||||
<dees-simple-appdash name="cloudly v${commitinfo.version}"
|
|
||||||
.viewTabs=${[
|
|
||||||
{
|
{
|
||||||
name: 'Overview',
|
name: 'Overview',
|
||||||
iconName: 'lucide:LayoutDashboard',
|
iconName: 'lucide:LayoutDashboard',
|
||||||
@@ -171,8 +140,42 @@ export class CloudlyDashboard extends DeesElement {
|
|||||||
name: 'Fleet',
|
name: 'Fleet',
|
||||||
iconName: 'lucide:Truck',
|
iconName: 'lucide:Truck',
|
||||||
element: CloudlyViewBackups,
|
element: CloudlyViewBackups,
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
super();
|
||||||
|
document.title = `cloudly v${commitinfo.version}`;
|
||||||
|
const subcription = appstate.dataState
|
||||||
|
.select((stateArg) => stateArg)
|
||||||
|
.subscribe((dataArg) => {
|
||||||
|
this.data = dataArg;
|
||||||
|
});
|
||||||
|
this.rxSubscriptions.push(subcription);
|
||||||
}
|
}
|
||||||
] as plugins.deesCatalog.IView[]}
|
|
||||||
|
public static styles = [
|
||||||
|
cssManager.defaultStyles,
|
||||||
|
css`
|
||||||
|
.maincontainer {
|
||||||
|
position: relative;
|
||||||
|
width: 100vw;
|
||||||
|
height: 100vh;
|
||||||
|
}
|
||||||
|
|
||||||
|
h1 {
|
||||||
|
font-weight: 400;
|
||||||
|
font-size: 24px;
|
||||||
|
font-family: 'Cal Sans';
|
||||||
|
}
|
||||||
|
`,
|
||||||
|
];
|
||||||
|
public render() {
|
||||||
|
return html`
|
||||||
|
<div class="maincontainer">
|
||||||
|
<dees-simple-login name="cloudly v${commitinfo.version}">
|
||||||
|
<dees-simple-appdash name="cloudly v${commitinfo.version}"
|
||||||
|
.viewTabs=${this.viewTabs}
|
||||||
></dees-simple-appdash>
|
></dees-simple-appdash>
|
||||||
</dees-simple-login>
|
</dees-simple-login>
|
||||||
</div>
|
</div>
|
||||||
|
@@ -18,12 +18,6 @@ export class CloudlyViewTasks extends DeesElement {
|
|||||||
@state()
|
@state()
|
||||||
private data: appstate.IDataState = {};
|
private data: appstate.IDataState = {};
|
||||||
|
|
||||||
@state()
|
|
||||||
private tasks: any[] = [];
|
|
||||||
|
|
||||||
@state()
|
|
||||||
private executions: plugins.interfaces.data.ITaskExecution[] = [];
|
|
||||||
|
|
||||||
@state()
|
@state()
|
||||||
private selectedExecution: plugins.interfaces.data.ITaskExecution | null = null;
|
private selectedExecution: plugins.interfaces.data.ITaskExecution | null = null;
|
||||||
|
|
||||||
@@ -41,6 +35,18 @@ export class CloudlyViewTasks extends DeesElement {
|
|||||||
this.data = dataArg;
|
this.data = dataArg;
|
||||||
});
|
});
|
||||||
this.rxSubscriptions.push(subscription);
|
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 = [
|
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) {
|
private async triggerTask(taskName: string) {
|
||||||
try {
|
try {
|
||||||
@@ -319,13 +290,28 @@ export class CloudlyViewTasks extends DeesElement {
|
|||||||
);
|
);
|
||||||
|
|
||||||
// Reload tasks and executions to show the new execution
|
// Reload tasks and executions to show the new execution
|
||||||
await this.loadTasks();
|
await appstate.dataState.dispatchAction(appstate.taskActions.getTasks, {});
|
||||||
await this.loadExecutions();
|
await this.loadExecutionsWithFilter();
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Failed to trigger task:', 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 {
|
private formatDate(timestamp: number): string {
|
||||||
return new Date(timestamp).toLocaleString();
|
return new Date(timestamp).toLocaleString();
|
||||||
}
|
}
|
||||||
@@ -359,7 +345,8 @@ export class CloudlyViewTasks extends DeesElement {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private renderTaskCard(task: any) {
|
private renderTaskCard(task: any) {
|
||||||
const lastExecution = this.executions
|
const executions = this.data.taskExecutions || [];
|
||||||
|
const lastExecution = executions
|
||||||
.filter(e => e.data.taskName === task.name)
|
.filter(e => e.data.taskName === task.name)
|
||||||
.sort((a, b) => (b.data.startedAt || 0) - (a.data.startedAt || 0))[0];
|
.sort((a, b) => (b.data.startedAt || 0) - (a.data.startedAt || 0))[0];
|
||||||
|
|
||||||
@@ -495,32 +482,32 @@ export class CloudlyViewTasks extends DeesElement {
|
|||||||
<div class="filter-bar">
|
<div class="filter-bar">
|
||||||
<button
|
<button
|
||||||
class="filter-button ${this.filterStatus === 'all' ? 'active' : ''}"
|
class="filter-button ${this.filterStatus === 'all' ? 'active' : ''}"
|
||||||
@click=${() => { this.filterStatus = 'all'; this.loadExecutions(); }}
|
@click=${() => { this.filterStatus = 'all'; this.loadExecutionsWithFilter(); }}
|
||||||
>
|
>
|
||||||
All
|
All
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button
|
||||||
class="filter-button ${this.filterStatus === 'running' ? 'active' : ''}"
|
class="filter-button ${this.filterStatus === 'running' ? 'active' : ''}"
|
||||||
@click=${() => { this.filterStatus = 'running'; this.loadExecutions(); }}
|
@click=${() => { this.filterStatus = 'running'; this.loadExecutionsWithFilter(); }}
|
||||||
>
|
>
|
||||||
Running
|
Running
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button
|
||||||
class="filter-button ${this.filterStatus === 'completed' ? 'active' : ''}"
|
class="filter-button ${this.filterStatus === 'completed' ? 'active' : ''}"
|
||||||
@click=${() => { this.filterStatus = 'completed'; this.loadExecutions(); }}
|
@click=${() => { this.filterStatus = 'completed'; this.loadExecutionsWithFilter(); }}
|
||||||
>
|
>
|
||||||
Completed
|
Completed
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button
|
||||||
class="filter-button ${this.filterStatus === 'failed' ? 'active' : ''}"
|
class="filter-button ${this.filterStatus === 'failed' ? 'active' : ''}"
|
||||||
@click=${() => { this.filterStatus = 'failed'; this.loadExecutions(); }}
|
@click=${() => { this.filterStatus = 'failed'; this.loadExecutionsWithFilter(); }}
|
||||||
>
|
>
|
||||||
Failed
|
Failed
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="task-grid">
|
<div class="task-grid">
|
||||||
${this.tasks.map(task => this.renderTaskCard(task))}
|
${(this.data.tasks || []).map(task => this.renderTaskCard(task))}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<cloudly-sectionheading>Execution History</cloudly-sectionheading>
|
<cloudly-sectionheading>Execution History</cloudly-sectionheading>
|
||||||
@@ -528,7 +515,7 @@ export class CloudlyViewTasks extends DeesElement {
|
|||||||
<dees-table
|
<dees-table
|
||||||
.heading1=${'Task Executions'}
|
.heading1=${'Task Executions'}
|
||||||
.heading2=${'History of task runs and their outcomes'}
|
.heading2=${'History of task runs and their outcomes'}
|
||||||
.data=${this.executions}
|
.data=${this.data.taskExecutions || []}
|
||||||
.displayFunction=${(itemArg: plugins.interfaces.data.ITaskExecution) => {
|
.displayFunction=${(itemArg: plugins.interfaces.data.ITaskExecution) => {
|
||||||
return {
|
return {
|
||||||
Task: itemArg.data.taskName,
|
Task: itemArg.data.taskName,
|
||||||
|
Reference in New Issue
Block a user