feat(core): add table actions (edit, pause, delete confirmation) and global action log

- Add Edit and Pause/Resume actions to connections table
- Add delete confirmation modal to secrets table
- Add 'paused' status to connections with full backend support
- Skip paused connections in health checks and secrets scanning
- Add global ActionLog service with filesystem persistence
- Instrument all mutation handlers (connections, secrets, pipelines) with action logging
- Add Action Log view with entity type filtering to dashboard
This commit is contained in:
2026-02-27 11:13:07 +00:00
parent 630b2502f3
commit 81ead52a72
22 changed files with 564 additions and 8 deletions

View File

@@ -29,6 +29,11 @@ export interface IDataState {
currentJobLog: string;
}
export interface IActionLogState {
entries: interfaces.data.IActionLogEntry[];
total: number;
}
export interface IUiState {
activeView: string;
autoRefresh: boolean;
@@ -70,6 +75,15 @@ export const dataStatePart = await appState.getStatePart<IDataState>(
'soft',
);
export const actionLogStatePart = await appState.getStatePart<IActionLogState>(
'actionLog',
{
entries: [],
total: 0,
},
'soft',
);
export const uiStatePart = await appState.getStatePart<IUiState>(
'ui',
{
@@ -227,6 +241,58 @@ export const deleteConnectionAction = connectionsStatePart.createAction<{
}
});
export const pauseConnectionAction = connectionsStatePart.createAction<{
connectionId: string;
paused: boolean;
}>(async (statePartArg, dataArg) => {
const context = getActionContext();
try {
const typedRequest = new plugins.domtools.plugins.typedrequest.TypedRequest<
interfaces.requests.IReq_PauseConnection
>('/typedrequest', 'pauseConnection');
await typedRequest.fire({
identity: context.identity!,
...dataArg,
});
// Re-fetch to get updated status
const listReq = new plugins.domtools.plugins.typedrequest.TypedRequest<
interfaces.requests.IReq_GetConnections
>('/typedrequest', 'getConnections');
const listResp = await listReq.fire({ identity: context.identity! });
return { ...statePartArg.getState(), connections: listResp.connections };
} catch (err) {
console.error('Failed to pause/resume connection:', err);
return statePartArg.getState();
}
});
export const updateConnectionAction = connectionsStatePart.createAction<{
connectionId: string;
name?: string;
baseUrl?: string;
token?: string;
}>(async (statePartArg, dataArg) => {
const context = getActionContext();
try {
const typedRequest = new plugins.domtools.plugins.typedrequest.TypedRequest<
interfaces.requests.IReq_UpdateConnection
>('/typedrequest', 'updateConnection');
await typedRequest.fire({
identity: context.identity!,
...dataArg,
});
// Re-fetch to get updated data
const listReq = new plugins.domtools.plugins.typedrequest.TypedRequest<
interfaces.requests.IReq_GetConnections
>('/typedrequest', 'getConnections');
const listResp = await listReq.fire({ identity: context.identity! });
return { ...statePartArg.getState(), connections: listResp.connections };
} catch (err) {
console.error('Failed to update connection:', err);
return statePartArg.getState();
}
});
// ============================================================================
// Projects Actions
// ============================================================================
@@ -567,6 +633,33 @@ export const fetchJobLogAction = dataStatePart.createAction<{
}
});
// ============================================================================
// Action Log Actions
// ============================================================================
export const fetchActionLogAction = actionLogStatePart.createAction<{
limit?: number;
offset?: number;
entityType?: interfaces.data.TActionEntity;
} | null>(async (statePartArg, dataArg) => {
const context = getActionContext();
try {
const typedRequest = new plugins.domtools.plugins.typedrequest.TypedRequest<
interfaces.requests.IReq_GetActionLog
>('/typedrequest', 'getActionLog');
const response = await typedRequest.fire({
identity: context.identity!,
limit: dataArg?.limit,
offset: dataArg?.offset,
entityType: dataArg?.entityType,
});
return { entries: response.entries, total: response.total };
} catch (err) {
console.error('Failed to fetch action log:', err);
return statePartArg.getState();
}
});
// ============================================================================
// UI Actions
// ============================================================================