Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 11 additions & 2 deletions src/gitops/components/application/ApplicationDetailsTab.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import HealthStatus from '@gitops/Statuses/HealthStatus';
import { OperationState } from '@gitops/Statuses/OperationState';
import SyncStatus from '@gitops/Statuses/SyncStatus';
import { ArgoServer, getArgoServer, getFriendlyClusterName } from '@gitops/utils/gitops';
import { labelControllerNamespaceKey } from '@gitops/utils/gitops';
import { useGitOpsTranslation } from '@gitops/utils/hooks/useGitOpsTranslation';
import { useObjectModifyPermissions } from '@gitops/utils/utils';
import { k8sUpdate, ResourceLink, useK8sModel } from '@openshift-console/dynamic-plugin-sdk';
Expand Down Expand Up @@ -114,6 +115,15 @@ const ApplicationDetailsTab: React.FC<ApplicationDetailsTabProps> = ({ obj }) =>
sources = [];
revisions = [];
}

// Get the controller namespace for AppProject link
const getControllerNamespace = (): string => {
if (obj?.status?.controllerNamespace) return obj.status.controllerNamespace;
if (obj?.metadata?.labels?.[labelControllerNamespaceKey])
return obj.metadata.labels[labelControllerNamespaceKey];
return obj?.metadata?.namespace || '';
};

return (
<div>
<PageSection
Expand Down Expand Up @@ -214,9 +224,8 @@ const ApplicationDetailsTab: React.FC<ApplicationDetailsTabProps> = ({ obj }) =>
title={t('Project')}
help={t('The Argo CD Project that this application belongs to.')}
>
{/* TODO - Update to handle App in Any Namespace when controller namespace is in status */}
<ResourceLink
namespace={obj?.metadata?.namespace}
namespace={getControllerNamespace()}
groupVersionKind={{
group: 'argoproj.io',
version: 'v1alpha1',
Expand Down
68 changes: 50 additions & 18 deletions src/gitops/components/application/graph/ApplicationGraphView.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -80,15 +80,19 @@ const customLayoutFactory: LayoutFactory = (type: string, graph: Graph): Layout
});
};

interface ApplicationContextMenuParams {
application: ApplicationKind;
navigate: NavigateFunction;
launchLabelsModal: () => void;
launchAnnotationsModal: () => void;
launchDeleteModal: () => void;
setGroupNodeStates: React.Dispatch<React.SetStateAction<string[]>>;
}

const customComponentFactory =
(
hrefRef: React.MutableRefObject<string>,
application: ApplicationKind,
navigate: NavigateFunction,
launchLabelsModal: () => void,
launchAnnotationsModal: () => void,
launchDeleteModal: () => void,
setGroupNodeStates: React.Dispatch<React.SetStateAction<string[]>>,
paramsRef: React.RefObject<ApplicationContextMenuParams>,
): ComponentFactory =>
(kind: ModelKind, type: string) => {
const createContextMenuItems = (
Expand Down Expand Up @@ -132,11 +136,15 @@ const customComponentFactory =
<ContextMenuItem
key={label}
onClick={() => {
const params = paramsRef.current;
if (!params) {
return;
}
if (label === t('View in Argo CD')) {
window.open(hrefRef.current, '_blank');
}
if (label === t('View Details')) {
navigate(graphElement.getData().resourcePath);
params.navigate(graphElement.getData().resourcePath);
}
}}
>
Expand Down Expand Up @@ -180,6 +188,18 @@ const customComponentFactory =
<ContextMenuItem
key={label}
onClick={async () => {
const params = paramsRef.current;
if (!params) {
return;
}
const {
application,
navigate,
launchLabelsModal,
launchAnnotationsModal,
launchDeleteModal,
setGroupNodeStates,
} = params;
if (label === t('View in Argo CD')) {
window.open(hrefRef.current, '_blank');
} else if (label === t('Edit labels')) {
Expand Down Expand Up @@ -339,22 +359,34 @@ export const ApplicationGraphView: React.FC<{
const launchDeleteModal = useDeleteModal(application);
const navigate = useNavigate();

const contextMenuParamsRef = React.useRef<ApplicationContextMenuParams>({
application,
navigate,
launchLabelsModal,
launchAnnotationsModal,
launchDeleteModal,
setGroupNodeStates,
});

React.useEffect(() => {
contextMenuParamsRef.current = {
application,
navigate,
launchLabelsModal,
launchAnnotationsModal,
launchDeleteModal,
setGroupNodeStates,
};
}, [application, navigate, launchLabelsModal, launchAnnotationsModal, launchDeleteModal]);

const controller = React.useMemo(() => {
const newController = new Visualization();
newController.registerLayoutFactory(customLayoutFactory);
newController.registerComponentFactory(
customComponentFactory(
hrefRef,
application,
navigate,
launchLabelsModal,
launchAnnotationsModal,
launchDeleteModal,
setGroupNodeStates,
),
);
newController.registerComponentFactory(customComponentFactory(hrefRef, contextMenuParamsRef));
newController.addEventListener(SELECTION_EVENT, setSelectedIds);
return newController;
// Controller is created once; context menu handlers read latest params via ref.
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);

const resourcePaths = React.useMemo(() => {
Expand Down
36 changes: 22 additions & 14 deletions src/gitops/components/appset/graph/ApplicationSetGraphView.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -432,6 +432,8 @@ export const ApplicationSetGraphView: React.FC<{
};
newController.fromModel(modelWithLayout, false);
return newController;
// Controller is recreated only when the ApplicationSet identity changes.
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [applicationSetUid]);

// Parts of the logic to refresh and update the graph is similar to application graph view.
Expand Down Expand Up @@ -492,12 +494,11 @@ export const ApplicationSetGraphView: React.FC<{
prevViewType.current = expandGroups;
}
// Register new layout factory
if (applicationSet.status?.applicationStatus?.length > 0) {
adjustedExpansionSetting = treeViewLayout === TreeViewLayout.OWNER_REFERENCE_LAYOUT;
} else {
adjustedExpansionSetting = true;
}
controller.registerLayoutFactory(customLayoutFactory(adjustedExpansionSetting));
const expansionSetting =
applicationSet.status?.applicationStatus?.length > 0
? treeViewLayout === TreeViewLayout.OWNER_REFERENCE_LAYOUT
: true;
controller.registerLayoutFactory(customLayoutFactory(expansionSetting));

const hasCollapsedStepGroups = collapsedStepGroupsRef.current.size > 0;

Expand Down Expand Up @@ -538,7 +539,15 @@ export const ApplicationSetGraphView: React.FC<{
});
}
}
}, [controller, nodes, initialEdges, treeViewLayout, applications, expandGroups]);
}, [
controller,
nodes,
initialEdges,
treeViewLayout,
applications,
expandGroups,
applicationSet.status?.applicationStatus?.length,
]);

const previousNodeCountRef = React.useRef<number>(0);
const previousNodeIdsRef = React.useRef<string>('');
Expand Down Expand Up @@ -732,6 +741,11 @@ export const ApplicationSetGraphView: React.FC<{
}
}

const structuralNodes = React.useMemo(
() => nodes.filter((n) => n.type !== 'filler-node'),
[nodes],
);

// Effect to handle initial collapse of step-groups after first render
// This runs after Dagre has laid out the expanded graph, then collapses
React.useEffect(() => {
Expand Down Expand Up @@ -779,13 +793,7 @@ export const ApplicationSetGraphView: React.FC<{
graph.layout();
});
}
}, [
controller,
nodes.filter((n) => n.type !== 'filler-node'),
treeViewLayout,
expandedStepGroups,
expandGroups,
]);
}, [controller, structuralNodes, initialNodes, treeViewLayout, expandedStepGroups, expandGroups]);
return (
<TopologyView
className="gitops-topology-view"
Expand Down
19 changes: 6 additions & 13 deletions src/gitops/components/imageupdater/ImageUpdaterDetailsTab.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -30,9 +30,10 @@ const ImageUpdaterDetailsTab: React.FC<ImageUpdaterDetailsTabProps> = ({ obj })

const status = obj.status || {};
const readyCondition = status.conditions?.find((c) => c.type === 'Ready');
const readyLabel = readyCondition
? readyCondition.status === 'True' ? t('True') : t('False')
: '-';
let readyLabel = '-';
if (readyCondition) {
readyLabel = readyCondition.status === 'True' ? t('True') : t('False');
}

return (
<>
Expand Down Expand Up @@ -81,22 +82,14 @@ const ImageUpdaterDetailsTab: React.FC<ImageUpdaterDetailsTabProps> = ({ obj })
title={t('Last Checked At')}
help={t('When the controller last checked for image updates.')}
>
{status.lastCheckedAt ? (
<Timestamp timestamp={status.lastCheckedAt} />
) : (
'-'
)}
{status.lastCheckedAt ? <Timestamp timestamp={status.lastCheckedAt} /> : '-'}
</DetailsDescriptionGroup>

<DetailsDescriptionGroup
title={t('Last Updated At')}
help={t('When the controller last performed an image update.')}
>
{status.lastUpdatedAt ? (
<Timestamp timestamp={status.lastUpdatedAt} />
) : (
'-'
)}
{status.lastUpdatedAt ? <Timestamp timestamp={status.lastUpdatedAt} /> : '-'}
</DetailsDescriptionGroup>

<DetailsDescriptionGroup
Expand Down
Loading