fix(frontend): add navigation context for cross-view linking and fix double-load bug

Projects "View Secrets"/"View Pipelines" and Groups "View Secrets" now
pass connection/scope/entity context so the target view opens with
filters pre-filled. Fixed double-load bug where dees-simple-appdash's
view-select event re-dispatched setActiveViewAction without context.
This commit is contained in:
2026-02-27 14:17:36 +00:00
parent 623ec4907c
commit 2f050744bc
7 changed files with 74 additions and 6 deletions

File diff suppressed because one or more lines are too long

View File

@@ -34,10 +34,18 @@ export interface IActionLogState {
total: number;
}
export interface INavigationContext {
connectionId?: string;
scope?: 'project' | 'group';
scopeId?: string;
projectId?: string;
}
export interface IUiState {
activeView: string;
autoRefresh: boolean;
refreshInterval: number;
navigationContext?: INavigationContext;
}
// ============================================================================
@@ -664,9 +672,22 @@ export const fetchActionLogAction = actionLogStatePart.createAction<{
// UI Actions
// ============================================================================
export const setActiveViewAction = uiStatePart.createAction<{ view: string }>(
export const setActiveViewAction = uiStatePart.createAction<{
view: string;
navigationContext?: INavigationContext;
}>(
async (statePartArg, dataArg) => {
return { ...statePartArg.getState(), activeView: dataArg.view };
return {
...statePartArg.getState(),
activeView: dataArg.view,
navigationContext: dataArg.navigationContext,
};
},
);
export const clearNavigationContextAction = uiStatePart.createAction(
async (statePartArg) => {
return { ...statePartArg.getState(), navigationContext: undefined };
},
);

View File

@@ -174,6 +174,7 @@ export class GitopsDashboard extends DeesElement {
if (appDash) {
appDash.addEventListener('view-select', (e: CustomEvent) => {
const viewName = e.detail.view.name.toLowerCase();
if (this.uiState.activeView === viewName) return;
appstate.uiStatePart.dispatchAction(appstate.setActiveViewAction, { view: viewName });
});
appDash.addEventListener('logout', async () => {
@@ -338,6 +339,7 @@ export class GitopsDashboard extends DeesElement {
if (!appDash || this.resolvedViewTabs.length === 0) return;
const targetTab = this.resolvedViewTabs.find((t) => t.name.toLowerCase() === viewName);
if (!targetTab) return;
if (appDash.selectedView === targetTab) return;
appDash.loadView(targetTab);
}
}

View File

@@ -101,7 +101,14 @@ export class GitopsViewGroups extends DeesElement {
iconName: 'lucide:key',
type: ['inRow', 'contextmenu'],
actionFunc: async ({ item }: any) => {
appstate.uiStatePart.dispatchAction(appstate.setActiveViewAction, { view: 'secrets' });
appstate.uiStatePart.dispatchAction(appstate.setActiveViewAction, {
view: 'secrets',
navigationContext: {
connectionId: this.selectedConnectionId,
scope: 'group',
scopeId: item.id,
},
});
},
},
]}

View File

@@ -167,6 +167,18 @@ export class GitopsViewPipelines extends DeesElement {
async firstUpdated() {
await appstate.connectionsStatePart.dispatchAction(appstate.fetchConnectionsAction, null);
// Check for navigation context from projects view
const navCtx = appstate.uiStatePart.getState().navigationContext;
if (navCtx?.connectionId && navCtx?.projectId) {
this.selectedConnectionId = navCtx.connectionId;
this.selectedProjectId = navCtx.projectId;
appstate.uiStatePart.dispatchAction(appstate.clearNavigationContextAction, null);
await this.loadProjects();
await this.loadPipelines();
return;
}
const conns = appstate.connectionsStatePart.getState().connections;
if (conns.length > 0 && !this.selectedConnectionId) {
this.selectedConnectionId = conns[0].id;

View File

@@ -102,7 +102,14 @@ export class GitopsViewProjects extends DeesElement {
iconName: 'lucide:key',
type: ['inRow', 'contextmenu'],
actionFunc: async ({ item }: any) => {
appstate.uiStatePart.dispatchAction(appstate.setActiveViewAction, { view: 'secrets' });
appstate.uiStatePart.dispatchAction(appstate.setActiveViewAction, {
view: 'secrets',
navigationContext: {
connectionId: this.selectedConnectionId,
scope: 'project',
scopeId: item.id,
},
});
},
},
{
@@ -110,7 +117,13 @@ export class GitopsViewProjects extends DeesElement {
iconName: 'lucide:play',
type: ['inRow', 'contextmenu'],
actionFunc: async ({ item }: any) => {
appstate.uiStatePart.dispatchAction(appstate.setActiveViewAction, { view: 'pipelines' });
appstate.uiStatePart.dispatchAction(appstate.setActiveViewAction, {
view: 'pipelines',
navigationContext: {
connectionId: this.selectedConnectionId,
projectId: item.id,
},
});
},
},
]}

View File

@@ -201,6 +201,19 @@ export class GitopsViewSecrets extends DeesElement {
async firstUpdated() {
await appstate.connectionsStatePart.dispatchAction(appstate.fetchConnectionsAction, null);
// Check for navigation context from projects/groups view
const navCtx = appstate.uiStatePart.getState().navigationContext;
if (navCtx?.connectionId && navCtx?.scope && navCtx?.scopeId) {
this.selectedConnectionId = navCtx.connectionId;
this.selectedScope = navCtx.scope;
this.selectedScopeId = navCtx.scopeId;
appstate.uiStatePart.dispatchAction(appstate.clearNavigationContextAction, null);
await this.loadEntities();
await this.loadSecrets();
return;
}
const conns = appstate.connectionsStatePart.getState().connections;
if (conns.length > 0 && !this.selectedConnectionId) {
this.selectedConnectionId = conns[0].id;