feat(webhook): add webhook endpoint and client push notifications, auto-refresh UI, and gitea id mapping fixes
This commit is contained in:
2
.gitignore
vendored
2
.gitignore
vendored
@@ -7,6 +7,8 @@ node_modules/
|
||||
|
||||
# Build outputs
|
||||
# ts_bundled/ is committed (embedded frontend bundle)
|
||||
ts_bundled/bundle.js
|
||||
ts_bundled/bundle.js.map
|
||||
|
||||
# Development
|
||||
.nogit/
|
||||
|
||||
10
changelog.md
10
changelog.md
@@ -1,5 +1,15 @@
|
||||
# Changelog
|
||||
|
||||
## 2026-02-24 - 2.6.0 - feat(webhook)
|
||||
add webhook endpoint and client push notifications, auto-refresh UI, and gitea id mapping fixes
|
||||
|
||||
- Add WebhookHandler with POST /webhook/:connectionId that parses provider-specific headers and broadcasts webhookNotification via TypedSocket to connected clients
|
||||
- Frontend: add auto-refresh toggle, refresh-interval action, dashboard auto-refresh timer, and views subscribing to gitops-auto-refresh events to refresh data
|
||||
- Frontend: add WebSocket client with reconnect logic to receive push notifications and trigger auto-refresh on webhook events
|
||||
- Gitea provider: prefer repository full_name and organization name when mapping project and group ids to ensure stable identifiers
|
||||
- Bump devDependencies: @git.zone/tsbundle ^2.9.0 and @git.zone/tswatch ^3.2.0
|
||||
- Add ts_bundled/bundle.js and bundle.js.map to .gitignore
|
||||
|
||||
## 2026-02-24 - 2.5.0 - feat(gitea-provider)
|
||||
auto-paginate Gitea repository and organization listing; respect explicit page option and default perPage to 50
|
||||
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
"@design.estate/dees-element": "^2.1.6"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@git.zone/tsbundle": "^2.8.4",
|
||||
"@git.zone/tswatch": "^3.1.0"
|
||||
"@git.zone/tsbundle": "^2.9.0",
|
||||
"@git.zone/tswatch": "^3.2.0"
|
||||
}
|
||||
}
|
||||
|
||||
3
readme.todo.md
Normal file
3
readme.todo.md
Normal file
@@ -0,0 +1,3 @@
|
||||
# GitOps TODOs
|
||||
|
||||
- [ ] Webhook HMAC signature verification (X-Gitea-Signature / X-Gitlab-Token) — currently accepts all POSTs
|
||||
@@ -3,6 +3,6 @@
|
||||
*/
|
||||
export const commitinfo = {
|
||||
name: '@serve.zone/gitops',
|
||||
version: '2.5.0',
|
||||
version: '2.6.0',
|
||||
description: 'GitOps management app for Gitea and GitLab - manage secrets, browse projects, view CI pipelines, and stream build logs'
|
||||
}
|
||||
|
||||
@@ -17,16 +17,23 @@ export class OpsServer {
|
||||
public secretsHandler!: handlers.SecretsHandler;
|
||||
public pipelinesHandler!: handlers.PipelinesHandler;
|
||||
public logsHandler!: handlers.LogsHandler;
|
||||
public webhookHandler!: handlers.WebhookHandler;
|
||||
|
||||
constructor(gitopsAppRef: GitopsApp) {
|
||||
this.gitopsAppRef = gitopsAppRef;
|
||||
}
|
||||
|
||||
public async start(port = 3000) {
|
||||
// Create webhook handler before server so routes register via addCustomRoutes
|
||||
this.webhookHandler = new handlers.WebhookHandler(this);
|
||||
|
||||
this.server = new plugins.typedserver.utilityservers.UtilityWebsiteServer({
|
||||
domain: 'localhost',
|
||||
feedMetadata: undefined,
|
||||
bundledContent: bundledFiles,
|
||||
addCustomRoutes: async (typedserver) => {
|
||||
this.webhookHandler.registerRoutes(typedserver);
|
||||
},
|
||||
});
|
||||
|
||||
// Chain typedrouters
|
||||
|
||||
@@ -5,3 +5,4 @@ export { GroupsHandler } from './groups.handler.ts';
|
||||
export { SecretsHandler } from './secrets.handler.ts';
|
||||
export { PipelinesHandler } from './pipelines.handler.ts';
|
||||
export { LogsHandler } from './logs.handler.ts';
|
||||
export { WebhookHandler } from './webhook.handler.ts';
|
||||
|
||||
62
ts/opsserver/handlers/webhook.handler.ts
Normal file
62
ts/opsserver/handlers/webhook.handler.ts
Normal file
@@ -0,0 +1,62 @@
|
||||
import * as plugins from '../../plugins.ts';
|
||||
import { logger } from '../../logging.ts';
|
||||
import type { OpsServer } from '../classes.opsserver.ts';
|
||||
import * as interfaces from '../../../ts_interfaces/index.ts';
|
||||
|
||||
export class WebhookHandler {
|
||||
constructor(private opsServerRef: OpsServer) {}
|
||||
|
||||
public registerRoutes(typedserver: plugins.typedserver.TypedServer): void {
|
||||
typedserver.addRoute('/webhook/:connectionId', 'POST', async (ctx) => {
|
||||
const connectionId = ctx.params.connectionId;
|
||||
|
||||
// Validate connection exists
|
||||
const connection = this.opsServerRef.gitopsAppRef.connectionManager.getConnection(connectionId);
|
||||
if (!connection) {
|
||||
return new Response(JSON.stringify({ error: 'Connection not found' }), {
|
||||
status: 404,
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
});
|
||||
}
|
||||
|
||||
// Parse event type from provider-specific headers
|
||||
const giteaEvent = ctx.headers.get('X-Gitea-Event');
|
||||
const gitlabEvent = ctx.headers.get('X-Gitlab-Event');
|
||||
const event = giteaEvent || gitlabEvent || 'unknown';
|
||||
const provider = giteaEvent ? 'gitea' : gitlabEvent ? 'gitlab' : 'unknown';
|
||||
|
||||
logger.info(`Webhook received: ${provider}/${event} for connection ${connection.name} (${connectionId})`);
|
||||
|
||||
// Broadcast to all connected frontends via TypedSocket
|
||||
try {
|
||||
const typedsocket = this.opsServerRef.server.typedserver.typedsocket;
|
||||
if (typedsocket) {
|
||||
const connections = await typedsocket.findAllTargetConnectionsByTag('allClients');
|
||||
for (const conn of connections) {
|
||||
const req = typedsocket.createTypedRequest<interfaces.requests.IReq_WebhookNotification>(
|
||||
'webhookNotification',
|
||||
conn,
|
||||
);
|
||||
req.fire({
|
||||
connectionId,
|
||||
provider,
|
||||
event,
|
||||
timestamp: Date.now(),
|
||||
}).catch((err: any) => {
|
||||
logger.warn(`Failed to notify client: ${err.message || err}`);
|
||||
});
|
||||
}
|
||||
}
|
||||
} catch (err: any) {
|
||||
logger.warn(`Failed to broadcast webhook event: ${err.message || err}`);
|
||||
}
|
||||
|
||||
return new Response(JSON.stringify({ ok: true }), {
|
||||
status: 200,
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
});
|
||||
});
|
||||
|
||||
logger.info('WebhookHandler routes registered');
|
||||
}
|
||||
}
|
||||
@@ -149,7 +149,7 @@ export class GiteaProvider extends BaseProvider {
|
||||
|
||||
private mapProject(r: plugins.giteaClient.IGiteaRepository): interfaces.data.IProject {
|
||||
return {
|
||||
id: String(r.id),
|
||||
id: r.full_name || String(r.id),
|
||||
name: r.name || '',
|
||||
fullPath: r.full_name || '',
|
||||
description: r.description || '',
|
||||
@@ -164,7 +164,7 @@ export class GiteaProvider extends BaseProvider {
|
||||
|
||||
private mapGroup(o: plugins.giteaClient.IGiteaOrganization): interfaces.data.IGroup {
|
||||
return {
|
||||
id: String(o.id || o.name),
|
||||
id: o.name || String(o.id),
|
||||
name: o.name || '',
|
||||
fullPath: o.name || '',
|
||||
description: o.description || '',
|
||||
|
||||
166543
ts_bundled/bundle.js
166543
ts_bundled/bundle.js
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -5,3 +5,4 @@ export * from './groups.ts';
|
||||
export * from './secrets.ts';
|
||||
export * from './pipelines.ts';
|
||||
export * from './logs.ts';
|
||||
export * from './webhook.ts';
|
||||
|
||||
18
ts_interfaces/requests/webhook.ts
Normal file
18
ts_interfaces/requests/webhook.ts
Normal file
@@ -0,0 +1,18 @@
|
||||
import * as plugins from '../plugins.ts';
|
||||
import * as data from '../data/index.ts';
|
||||
|
||||
export interface IReq_WebhookNotification extends plugins.typedrequestInterfaces.implementsTR<
|
||||
plugins.typedrequestInterfaces.ITypedRequest,
|
||||
IReq_WebhookNotification
|
||||
> {
|
||||
method: 'webhookNotification';
|
||||
request: {
|
||||
connectionId: string;
|
||||
provider: string;
|
||||
event: string;
|
||||
timestamp: number;
|
||||
};
|
||||
response: {
|
||||
ok: boolean;
|
||||
};
|
||||
}
|
||||
@@ -3,6 +3,6 @@
|
||||
*/
|
||||
export const commitinfo = {
|
||||
name: '@serve.zone/gitops',
|
||||
version: '2.5.0',
|
||||
version: '2.6.0',
|
||||
description: 'GitOps management app for Gitea and GitLab - manage secrets, browse projects, view CI pipelines, and stream build logs'
|
||||
}
|
||||
|
||||
@@ -543,3 +543,9 @@ export const toggleAutoRefreshAction = uiStatePart.createAction(async (statePart
|
||||
const state = statePartArg.getState();
|
||||
return { ...state, autoRefresh: !state.autoRefresh };
|
||||
});
|
||||
|
||||
export const setRefreshIntervalAction = uiStatePart.createAction<{ interval: number }>(
|
||||
async (statePartArg, dataArg) => {
|
||||
return { ...statePartArg.getState(), refreshInterval: dataArg.interval };
|
||||
},
|
||||
);
|
||||
|
||||
@@ -43,6 +43,14 @@ export class GitopsDashboard extends DeesElement {
|
||||
|
||||
private resolvedViewTabs: Array<{ name: string; iconName: string; element: any }> = [];
|
||||
|
||||
// Auto-refresh timer
|
||||
private autoRefreshTimer: ReturnType<typeof setInterval> | null = null;
|
||||
|
||||
// WebSocket client
|
||||
private ws: WebSocket | null = null;
|
||||
private wsReconnectTimer: ReturnType<typeof setTimeout> | null = null;
|
||||
private wsIntentionalClose = false;
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
document.title = 'GitOps';
|
||||
@@ -53,7 +61,11 @@ export class GitopsDashboard extends DeesElement {
|
||||
this.loginState = loginState;
|
||||
if (loginState.isLoggedIn) {
|
||||
appstate.connectionsStatePart.dispatchAction(appstate.fetchConnectionsAction, null);
|
||||
this.connectWebSocket();
|
||||
} else {
|
||||
this.disconnectWebSocket();
|
||||
}
|
||||
this.manageAutoRefreshTimer();
|
||||
});
|
||||
this.rxSubscriptions.push(loginSubscription);
|
||||
|
||||
@@ -62,6 +74,7 @@ export class GitopsDashboard extends DeesElement {
|
||||
.subscribe((uiState) => {
|
||||
this.uiState = uiState;
|
||||
this.syncAppdashView(uiState.activeView);
|
||||
this.manageAutoRefreshTimer();
|
||||
});
|
||||
this.rxSubscriptions.push(uiSubscription);
|
||||
}
|
||||
@@ -78,6 +91,36 @@ export class GitopsDashboard extends DeesElement {
|
||||
width: 100%;
|
||||
height: 100vh;
|
||||
}
|
||||
.auto-refresh-toggle {
|
||||
position: fixed;
|
||||
bottom: 16px;
|
||||
right: 16px;
|
||||
z-index: 1000;
|
||||
background: rgba(30, 30, 50, 0.9);
|
||||
border: 1px solid rgba(255, 255, 255, 0.1);
|
||||
border-radius: 8px;
|
||||
padding: 8px 14px;
|
||||
color: #ccc;
|
||||
font-size: 12px;
|
||||
cursor: pointer;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
backdrop-filter: blur(8px);
|
||||
transition: background 0.2s;
|
||||
}
|
||||
.auto-refresh-toggle:hover {
|
||||
background: rgba(40, 40, 70, 0.95);
|
||||
}
|
||||
.auto-refresh-dot {
|
||||
width: 8px;
|
||||
height: 8px;
|
||||
border-radius: 50%;
|
||||
background: #666;
|
||||
}
|
||||
.auto-refresh-dot.active {
|
||||
background: #00ff88;
|
||||
}
|
||||
`,
|
||||
];
|
||||
|
||||
@@ -92,6 +135,15 @@ export class GitopsDashboard extends DeesElement {
|
||||
</dees-simple-appdash>
|
||||
</dees-simple-login>
|
||||
</div>
|
||||
${this.loginState.isLoggedIn ? html`
|
||||
<div
|
||||
class="auto-refresh-toggle"
|
||||
@click=${() => appstate.uiStatePart.dispatchAction(appstate.toggleAutoRefreshAction, null)}
|
||||
>
|
||||
<span class="auto-refresh-dot ${this.uiState.autoRefresh ? 'active' : ''}"></span>
|
||||
Auto-Refresh: ${this.uiState.autoRefresh ? 'ON' : 'OFF'}
|
||||
</div>
|
||||
` : ''}
|
||||
`;
|
||||
}
|
||||
|
||||
@@ -160,6 +212,93 @@ export class GitopsDashboard extends DeesElement {
|
||||
}
|
||||
}
|
||||
|
||||
public override disconnectedCallback() {
|
||||
super.disconnectedCallback();
|
||||
this.clearAutoRefreshTimer();
|
||||
this.disconnectWebSocket();
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// Auto-refresh timer management
|
||||
// ============================================================================
|
||||
|
||||
private manageAutoRefreshTimer(): void {
|
||||
this.clearAutoRefreshTimer();
|
||||
const { autoRefresh, refreshInterval } = this.uiState;
|
||||
if (autoRefresh && this.loginState.isLoggedIn) {
|
||||
this.autoRefreshTimer = setInterval(() => {
|
||||
document.dispatchEvent(new CustomEvent('gitops-auto-refresh'));
|
||||
}, refreshInterval);
|
||||
}
|
||||
}
|
||||
|
||||
private clearAutoRefreshTimer(): void {
|
||||
if (this.autoRefreshTimer) {
|
||||
clearInterval(this.autoRefreshTimer);
|
||||
this.autoRefreshTimer = null;
|
||||
}
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// WebSocket client for webhook push notifications
|
||||
// ============================================================================
|
||||
|
||||
private connectWebSocket(): void {
|
||||
if (this.ws) return;
|
||||
|
||||
const protocol = location.protocol === 'https:' ? 'wss:' : 'ws:';
|
||||
const wsUrl = `${protocol}//${location.host}`;
|
||||
|
||||
try {
|
||||
this.wsIntentionalClose = false;
|
||||
this.ws = new WebSocket(wsUrl);
|
||||
|
||||
this.ws.addEventListener('message', (event) => {
|
||||
try {
|
||||
const data = JSON.parse(event.data);
|
||||
// TypedSocket wraps messages; look for webhookNotification method
|
||||
if (data?.method === 'webhookNotification' || data?.type === 'webhookEvent') {
|
||||
console.log('Webhook event received:', data);
|
||||
document.dispatchEvent(new CustomEvent('gitops-auto-refresh'));
|
||||
}
|
||||
} catch {
|
||||
// Not JSON, ignore
|
||||
}
|
||||
});
|
||||
|
||||
this.ws.addEventListener('close', () => {
|
||||
this.ws = null;
|
||||
if (!this.wsIntentionalClose && this.loginState.isLoggedIn) {
|
||||
this.wsReconnectTimer = setTimeout(() => {
|
||||
this.connectWebSocket();
|
||||
}, 5000);
|
||||
}
|
||||
});
|
||||
|
||||
this.ws.addEventListener('error', () => {
|
||||
// Will trigger close event
|
||||
});
|
||||
} catch (err) {
|
||||
console.warn('WebSocket connection failed:', err);
|
||||
}
|
||||
}
|
||||
|
||||
private disconnectWebSocket(): void {
|
||||
this.wsIntentionalClose = true;
|
||||
if (this.wsReconnectTimer) {
|
||||
clearTimeout(this.wsReconnectTimer);
|
||||
this.wsReconnectTimer = null;
|
||||
}
|
||||
if (this.ws) {
|
||||
this.ws.close();
|
||||
this.ws = null;
|
||||
}
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// Login
|
||||
// ============================================================================
|
||||
|
||||
private async login(username: string, password: string) {
|
||||
const domtools = await this.domtoolsPromise;
|
||||
const simpleLogin = this.shadowRoot!.querySelector('dees-simple-login') as any;
|
||||
|
||||
@@ -38,6 +38,8 @@ export class GitopsViewBuildlog extends DeesElement {
|
||||
@state()
|
||||
accessor selectedJobId: string = '';
|
||||
|
||||
private _autoRefreshHandler: () => void;
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
const connSub = appstate.connectionsStatePart
|
||||
@@ -49,6 +51,18 @@ export class GitopsViewBuildlog extends DeesElement {
|
||||
.select((s) => s)
|
||||
.subscribe((s) => { this.dataState = s; });
|
||||
this.rxSubscriptions.push(dataSub);
|
||||
|
||||
this._autoRefreshHandler = () => this.handleAutoRefresh();
|
||||
document.addEventListener('gitops-auto-refresh', this._autoRefreshHandler);
|
||||
}
|
||||
|
||||
public override disconnectedCallback() {
|
||||
super.disconnectedCallback();
|
||||
document.removeEventListener('gitops-auto-refresh', this._autoRefreshHandler);
|
||||
}
|
||||
|
||||
private handleAutoRefresh(): void {
|
||||
this.fetchLog();
|
||||
}
|
||||
|
||||
public static styles = [
|
||||
|
||||
@@ -19,12 +19,26 @@ export class GitopsViewConnections extends DeesElement {
|
||||
activeConnectionId: null,
|
||||
};
|
||||
|
||||
private _autoRefreshHandler: () => void;
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
const sub = appstate.connectionsStatePart
|
||||
.select((s) => s)
|
||||
.subscribe((s) => { this.connectionsState = s; });
|
||||
this.rxSubscriptions.push(sub);
|
||||
|
||||
this._autoRefreshHandler = () => this.handleAutoRefresh();
|
||||
document.addEventListener('gitops-auto-refresh', this._autoRefreshHandler);
|
||||
}
|
||||
|
||||
public override disconnectedCallback() {
|
||||
super.disconnectedCallback();
|
||||
document.removeEventListener('gitops-auto-refresh', this._autoRefreshHandler);
|
||||
}
|
||||
|
||||
private handleAutoRefresh(): void {
|
||||
this.refresh();
|
||||
}
|
||||
|
||||
public static styles = [
|
||||
|
||||
@@ -32,6 +32,8 @@ export class GitopsViewGroups extends DeesElement {
|
||||
@state()
|
||||
accessor selectedConnectionId: string = '';
|
||||
|
||||
private _autoRefreshHandler: () => void;
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
const connSub = appstate.connectionsStatePart
|
||||
@@ -43,6 +45,18 @@ export class GitopsViewGroups extends DeesElement {
|
||||
.select((s) => s)
|
||||
.subscribe((s) => { this.dataState = s; });
|
||||
this.rxSubscriptions.push(dataSub);
|
||||
|
||||
this._autoRefreshHandler = () => this.handleAutoRefresh();
|
||||
document.addEventListener('gitops-auto-refresh', this._autoRefreshHandler);
|
||||
}
|
||||
|
||||
public override disconnectedCallback() {
|
||||
super.disconnectedCallback();
|
||||
document.removeEventListener('gitops-auto-refresh', this._autoRefreshHandler);
|
||||
}
|
||||
|
||||
private handleAutoRefresh(): void {
|
||||
this.loadGroups();
|
||||
}
|
||||
|
||||
public static styles = [
|
||||
|
||||
@@ -30,6 +30,8 @@ export class GitopsViewOverview extends DeesElement {
|
||||
currentJobLog: '',
|
||||
};
|
||||
|
||||
private _autoRefreshHandler: () => void;
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
const connSub = appstate.connectionsStatePart
|
||||
@@ -41,6 +43,18 @@ export class GitopsViewOverview extends DeesElement {
|
||||
.select((s) => s)
|
||||
.subscribe((s) => { this.dataState = s; });
|
||||
this.rxSubscriptions.push(dataSub);
|
||||
|
||||
this._autoRefreshHandler = () => this.handleAutoRefresh();
|
||||
document.addEventListener('gitops-auto-refresh', this._autoRefreshHandler);
|
||||
}
|
||||
|
||||
public override disconnectedCallback() {
|
||||
super.disconnectedCallback();
|
||||
document.removeEventListener('gitops-auto-refresh', this._autoRefreshHandler);
|
||||
}
|
||||
|
||||
private handleAutoRefresh(): void {
|
||||
appstate.connectionsStatePart.dispatchAction(appstate.fetchConnectionsAction, null);
|
||||
}
|
||||
|
||||
public static styles = [
|
||||
|
||||
@@ -35,6 +35,8 @@ export class GitopsViewPipelines extends DeesElement {
|
||||
@state()
|
||||
accessor selectedProjectId: string = '';
|
||||
|
||||
private _autoRefreshHandler: () => void;
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
const connSub = appstate.connectionsStatePart
|
||||
@@ -46,6 +48,18 @@ export class GitopsViewPipelines extends DeesElement {
|
||||
.select((s) => s)
|
||||
.subscribe((s) => { this.dataState = s; });
|
||||
this.rxSubscriptions.push(dataSub);
|
||||
|
||||
this._autoRefreshHandler = () => this.handleAutoRefresh();
|
||||
document.addEventListener('gitops-auto-refresh', this._autoRefreshHandler);
|
||||
}
|
||||
|
||||
public override disconnectedCallback() {
|
||||
super.disconnectedCallback();
|
||||
document.removeEventListener('gitops-auto-refresh', this._autoRefreshHandler);
|
||||
}
|
||||
|
||||
private handleAutoRefresh(): void {
|
||||
this.loadPipelines();
|
||||
}
|
||||
|
||||
public static styles = [
|
||||
|
||||
@@ -32,6 +32,8 @@ export class GitopsViewProjects extends DeesElement {
|
||||
@state()
|
||||
accessor selectedConnectionId: string = '';
|
||||
|
||||
private _autoRefreshHandler: () => void;
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
const connSub = appstate.connectionsStatePart
|
||||
@@ -43,6 +45,18 @@ export class GitopsViewProjects extends DeesElement {
|
||||
.select((s) => s)
|
||||
.subscribe((s) => { this.dataState = s; });
|
||||
this.rxSubscriptions.push(dataSub);
|
||||
|
||||
this._autoRefreshHandler = () => this.handleAutoRefresh();
|
||||
document.addEventListener('gitops-auto-refresh', this._autoRefreshHandler);
|
||||
}
|
||||
|
||||
public override disconnectedCallback() {
|
||||
super.disconnectedCallback();
|
||||
document.removeEventListener('gitops-auto-refresh', this._autoRefreshHandler);
|
||||
}
|
||||
|
||||
private handleAutoRefresh(): void {
|
||||
this.loadProjects();
|
||||
}
|
||||
|
||||
public static styles = [
|
||||
|
||||
@@ -38,6 +38,8 @@ export class GitopsViewSecrets extends DeesElement {
|
||||
@state()
|
||||
accessor selectedScopeId: string = '';
|
||||
|
||||
private _autoRefreshHandler: () => void;
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
const connSub = appstate.connectionsStatePart
|
||||
@@ -49,6 +51,18 @@ export class GitopsViewSecrets extends DeesElement {
|
||||
.select((s) => s)
|
||||
.subscribe((s) => { this.dataState = s; });
|
||||
this.rxSubscriptions.push(dataSub);
|
||||
|
||||
this._autoRefreshHandler = () => this.handleAutoRefresh();
|
||||
document.addEventListener('gitops-auto-refresh', this._autoRefreshHandler);
|
||||
}
|
||||
|
||||
public override disconnectedCallback() {
|
||||
super.disconnectedCallback();
|
||||
document.removeEventListener('gitops-auto-refresh', this._autoRefreshHandler);
|
||||
}
|
||||
|
||||
private handleAutoRefresh(): void {
|
||||
this.loadSecrets();
|
||||
}
|
||||
|
||||
public static styles = [
|
||||
|
||||
Reference in New Issue
Block a user